DateTime Object becomes out of Sync with Time Dialog

Roger Garstang

Well-Known Member
Licensed User
Longtime User
In another bug report I had mentioned there is no way of returning to the default/hardware timezone offset in the DateTime object. In the mean time I added a Global variable to hold the offset when the activity starts so I can set it to 0 and save GMT time text then return it to the default when done. I thought it was working fine until after saving I tried to set the time again.

I have a Button with the selected time as its text. when you click the button it calls:

B4X:
Sub Get_Time
   td.TimeTicks = DateTime.Now
   td.Is24Hours = True
   If td.Show("Please Select Incident Time", "Incident Time", "Ok", "Cancel", "", Null) = DialogResponse.POSITIVE Then
      VM.SetText("IncidentTime", DateTime.Time(td.TimeTicks))
   End If
End Sub

What is confusing is I use DateTime to populate the ticks and use it again to get the text to set the control to yet they return 2 different results. Lets say the time on the device is 12:34. When I click the button the Time Dialog is shown with 12:34. When I click Ok in the time dialog the text I get back from DateTime.Time(td.TimeTicks) is 13:34.

DateTime.GetTimeZoneOffsetAt(DateTime.Now) and the TimezoneOffset in the DateTime Object both report -5 for my timezone. During the Fall/Winter it is -6, so that it goes up an hour is actually opposite of a DST issue. I've also ruled out the shifting to 0 and back being an issue by setting the offset with SetTimeZone right after capturing the current value when the activity starts. So, I get the value of -5 and set it back to -5 and now my text from the Time Dialog returns off by an hour, so something additional is happening to the DateTime object when you set the offset. It is almost like it thinks I'm setting my timezone to Eastern instead of Central.

The problem seems to be similar to the other reported in that the object is trying to set Timezone by Offset which cannot work. So, I'm right back to still no way of restoring the default timezone offset. The Time Dialog appears to use its own DateTime object too which confuses the matter even more since it always shows the correct time.
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Whatever is happening also appears to be internal to the object. When I put Toast Messages before and after setting it like below all 4 display -5. Since it is returning time an hour too fast I'd expect the 2nd set after setting it to return -4. So, it is returning time text like it is set to -4, but not actually setting it to -4.

B4X:
If FirstTime = True Then
   DeviceTimeOffset = DateTime.GetTimeZoneOffsetAt(DateTime.Now)
End If
ToastMessageShow(DateTime.GetTimeZoneOffsetAt(DateTime.Now), False)
ToastMessageShow(DateTime.TimeZoneOffset, False)
DateTime.SetTimeZone(DeviceTimeOffset)
ToastMessageShow(DateTime.GetTimeZoneOffsetAt(DateTime.Now), False)
ToastMessageShow(DateTime.TimeZoneOffset, False)
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim td As TimeDialog
   td.TimeTicks = DateTime.Now
   If td.Show("Please Select Time", "Time Test", "Ok", "Cancel", "", Null) = DialogResponse.POSITIVE Then
      ToastMessageShow(DateTime.Time(td.TimeTicks), False)
   End If
   DateTime.SetTimeZone(DateTime.GetTimeZoneOffsetAt(DateTime.Now))
   If td.Show("Please Select Time", "Time Test", "Ok", "Cancel", "", Null) = DialogResponse.POSITIVE Then
      ToastMessageShow(DateTime.Time(td.TimeTicks), False)
   End If
End Sub

Watch the toast message gain an hour.
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
This is off too though, so how would it be the Dialog?

B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim td As TimeDialog
   td.TimeTicks = DateTime.Now
   td.Show("Please Select Time", "Time Test", "Ok", "Cancel", "", Null)
   ToastMessageShow(DateTime.Time(td.TimeTicks), False)
   DateTime.SetTimeZone(DateTime.GetTimeZoneOffsetAt(DateTime.Now))
   ToastMessageShow(DateTime.Time(td.TimeTicks), False)
End Sub
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
I have an explanation for this issue. In order to understand the actual reason you need to be familiar with TimeDialog implementation and Java Calendar class.

Some points:
- TimeDialog.getTimeTicks returns the ticks of the date 31/12/0002 (2 years after AD).
- TimeDialog.getTimeTicks doesn't use the standard DateTime object. Therefore it is not affected by changes to DateTime time zone.
- TimeDialog.setTimeTicks does use DateTime and therefore it is affected by changes to DateTime time zone.
B4X:
DateTime.SetTimeZone(DateTime.GetTimeZoneOffsetAt(DateTime.Now))
- The above code is not a "nop" operation. The default time zone has two values because of the DST. Once you set the time zone it will only have a single value.

Short answer: you should not use the getter of TimeDialog.TimeTicks
You should instead use this sub:
B4X:
Sub GetTicksFromDialog(td As TimeDialog) As Long
   Return DateTime.TimeParse(NumberFormat(td.Hour, 2, 0) & ":" & NumberFormat(td.Minute, 2, 0) _
      & ":00")
End Sub
 

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Ok, so this appears to be working now:

B4X:
Sub Activity_Create(FirstTime As Boolean)
   Dim td As TimeDialog
   Dim timeTicks As Long
   td.timeTicks = DateTime.Now
   td.Show("Please Select Time", "Time Test", "Ok", "Cancel", "", Null)
   timeTicks = GetTicksFromDialog(td)
   ToastMessageShow(DateTime.Date(timeTicks) & " " & DateTime.time(timeTicks), True)
   DateTime.SetTimeZone(DateTime.GetTimeZoneOffsetAt(DateTime.Now))
   ToastMessageShow(DateTime.Date(timeTicks) & " " & DateTime.time(timeTicks), True)
End Sub

No more hour off when resetting the offset. In reality though I just traded one date for another. It looks like to combine the two I'll have to use the same parsing method...any suggestions for this? I need one of three things- 1. The ability to set the date portion of of the TimeParse to something other than Current Date as it isn't always a time specified for today. 2. A combination method to parse both since we have a DateParse and a TimeParse, but no DateTimeParse. 3. If it is possible I may ask and see if the Time Dialog can use the Date set through TimeTicks as the Date for the time and perhaps it could use the DateTime objects better to not have weird shifts like this.

And, since there were other issues at work clouding what I was seeing I want to understand DateTime.SetTimeZone better. I'm not sure what you mean by "nop", but with the error fixed now it appears DateTime.SetTimeZone just sets the offset and nothing more. To get the proper offset with DST in mind you use GetTimeZoneOffsetAt. The other issue made it appear like SetTimeZone was shifting the offset, so it looked like it was trying to calculate more off of just the one offset. I'm still confused as to why my last example before your post still shifted though since the DateTime Offset should have been the same before and after changing and displayed the same tick value. You said getTimeTicks wasn't affected by the DateTime object, so when changing the offset of DateTime to the same value it already was what changed?
 
Last edited:

Roger Garstang

Well-Known Member
Licensed User
Longtime User
Ok, I think I got it to work now and keep everything correct:

B4X:
Sub Get_Date
   dd.DateTicks = IncidentDate
   If dd.Show("Please Select Incident Date", "Incident Date", "Ok", "Cancel", "", Null) = DialogResponse.POSITIVE Then
      IncidentDate = DateTime.DateParse(NumberFormat2(dd.Year, 4, 0, 0, False) & "-" & NumberFormat(dd.Month, 2, 0) & "-" & NumberFormat(dd.DayOfMonth, 2, 0) & " " & NumberFormat(DateTime.GetHour(IncidentDate), 2, 0) & ":" & NumberFormat(DateTime.GetMinute(IncidentDate), 2, 0))
      VM.SetText("IncidentDate", DateTime.Date(IncidentDate))
   End If
End Sub

Sub Get_Time
   td.TimeTicks = IncidentDate
   td.Is24Hours = True
   If td.Show("Please Select Incident Time", "Incident Time", "Ok", "Cancel", "", Null) = DialogResponse.POSITIVE Then
      IncidentDate = DateTime.DateParse(NumberFormat2(DateTime.GetYear(IncidentDate), 4, 0, 0, False) & "-" & NumberFormat(DateTime.GetMonth(IncidentDate), 2, 0) & "-" & NumberFormat(DateTime.GetDayOfMonth(IncidentDate), 2, 0) & " " & NumberFormat(td.Hour, 2, 0) & ":" & NumberFormat(td.Minute, 2, 0))
      VM.SetText("IncidentDate", DateTime.Date(IncidentDate))
   End If
End Sub

I have a Global long I called IncidentDate. It is used to populate the Database and is read from the Database to date text in a disabled textbox and I renamed the Buttons Set Date and Set Time. I set my Formats with:

B4X:
DateTime.TimeFormat = "HH:mm"
DateTime.DateFormat = "yyyy-MM-dd HH:mm"

when the activity is created (Docs weren't very clear and with two functions I didn't think I could parse time in the Date Parsing function...it doesn't mean much to call them Date and Time in that case and it probably could have used Format1, Format2, Parse1, Parse2 since each can display anything)

Looks like we are good now...although less than optimal having to go to text and back. I put a request in to see if the Time Dialog can be enhanced to work better. To work both ways like my functions above do the Date Dialog would also need an option to clear the time portion to midnight like it does or keep the passed time.
 
Top