Chronos is one of the many Smalltalk-related blogs syndicated on Planet Smalltalk
χρόνος

Discussion of the Essence# programming language, and related issues and technologies.

Blog Timezone: America/Los_Angeles [Winter: -0800 hhmm | Summer: -0700 hhmm] 
Your local time:  

2006-01-27

Comparative Examples: Chronos/Smalltalk vs. MS Dot Net

David McNamee, in his Fun With TimeZone blog entry, explains why one should store time stamps relative to Universal Time, and not relative to local time:


...you have to remember that local time is ambiguous and should really only be used for display purposes. It should never be relied upon for logic or stored in a database. What do I mean by ambiguous? What happens when we switch from Standard Time to Daylight Saving Time? At 1:59AM, we are still on Standard Time. Sixty seconds later, it's three o'clock in the morning. An hour disappears. Did the hour really disappear? No. We just change the clocks for the summer months because Ben Franklin thought we were wasting daylight.

If local time isn't reliable, then how do we record time? What we should really store is Coordinated Universal Time (UTC), which is also known as Greenwich Mean Time (GMT). UTC/GMT never changes. There aren't any bizarre rules to follow. If we store that, we can have reliable calculations based on accurate data. If we like, we can also record the offset from UTC where the data was collected. That would allow us to reconstruct collection patterns during data analysis. That information can be collected on the device and sent back to the server.


Yes. And there's an even worse situation when transitioning from "Daylight Saving Time" (a.k.a. "Summer Time" in most of the world) back to "Standard Time": The hour from 1am to 2am (a left-closed, right open interval; local time; assuming the transition time-of-day is 2am local time, which is not at all the case everywhere) is repeated twice!

Another major issue is timestamps collected from one time zone but stored or processed in another. And then there's the fact that time zone offsets can change for other reasons than DST transitions. Hawaii (which doesn't observe DST) changed its "Standard Time" offset from -10:30 to -10:00 in 1946. Parts of Indiana have switched between Eastern and Central Time. Such things can and do happen.

David also provides some example .Net code for storing timestamps in Universal Time, and for also including the key information needed to reconstruct the original local time from the recorded UT timestamp:

DateTime rightNow = DateTime.Now;
TimeZone timeZone = TimeZone.CurrentTimeZone;

lblCurrentTime.Text = rightNow.ToString();
lblTimeZone.Text =
timeZone.IsDaylightSavingTime(rightNow) ?
timeZone.DaylightName.ToString() :
timeZone.StandardName.ToString();
lblOffset.Text =
timeZone.GetUtcOffset(rightNow).TotalHours.ToString();
lblUTC.Text =
rightNow.ToUniversalTime().ToString();


Although Chronos provides an even better approach for applications that use it, David's approach has the advantage or making life easier for applications that don't or can't use Chronos, when such applications also need to use the timestamp information. So here's the Chronos code that implements David's approach:

| rightNow localTimeText universalTimeText timeZoneKey timeZoneAbbreviation timeZoneStatus offsetText |
rightNow := Timepoint now.
localTimeText := rightNow localePrintString. "Human readable format based on current Locale."
universalTimeText := rightNow asUT printString. "defaults to ISO 8601 format."
timeZoneKey := rightNow timeZone key. "e.g., 'America/New_York'"
timeZoneAbbreviation := rightNow timeZone commonAbbreviation. "e.g., 'EDT'"
timeZoneStatus := rightNow timeZone isStandardTime
ifTrue: [#StandardTime]
ifFalse: [#DaylightSavingTime].
offsetText := rightNow timeZone zuluNotation.
(Dictionary new
at: #timestamp put: rightNow;
at: #localTimeText put: localTimeText;
at: #universalTimeText put: universalTimeText;
at: #timeZoneKey put: timeZoneKey;
at: #timeZoneAbbreviation put: timeZoneAbbreviation;
at: #timeZoneStatus put: timeZoneStatus;
at: #timeZoneOffsetText put: offsetText;
yourself)


And here's the output (line breaks and other formatting added by hand):

Dictionary (
#timestamp-> 2006-01-27T14:19:25.022803-08:00
#localTimeText-> 'January 27, 2006 2:19:25 pm PST'
#universalTimeText-> '2006-01-27T22:19:25.022803+00:00'
#timeZoneKey-> #'America/Los_Angeles'
#timeZoneAbbreviation-> #PST
#timeZoneStatus-> #StandardTime
#timeZoneOffsetText-> 'Z-08:00')



No comments: