How to design date/time libraries (was: Arbitrary abbreviations in phobos considered ridiculous)
Jonathan M Davis
jmdavisProg at gmx.com
Thu Mar 8 11:04:10 PST 2012
On Thursday, March 08, 2012 12:09:29 Stewart Gordon wrote:
> On 08/03/2012 02:56, Jonathan M Davis wrote:
> > On Thursday, March 08, 2012 01:22:42 Stewart Gordon wrote:
> >> On 07/03/2012 08:10, Jacob Carlborg wrote:
> >> <snip>
> >>
> >>> Yeah, Clock.now() would be good and Data.today() as well.
> >>
> >> My utility library has, for consistency, DateValue.now, TimeValue.now and
> >> DateTime.now.
> >
> > I specically avoided giving a way to get the time with any type other than
> > SysTime (and TickDuration for using a monotonic clock), because I believe
> > that it leads to incorrect behavior. Any time that you're dealing with
> > the system clock, you should be dealing with SysTime. Date, TimeOfDay,
> > and DateTime are for when you need the date and/or time but don't care
> > about what absolute time it's associated with in the real world.
> > Treating DateTime as corresponding to a specific point in time is just
> > going to cause problems, because it has no time zone.
>
> <snip>
>
> TimeValue and DateTime in my library always store the time in UTC. It uses
> a global variable for time zone. But a LocalTime could be added to the
> mix. This would be used to hold a time that, when combined with a date,
> will become a DateTime set according to the correct time zone.
Which is very different from Date, TimeOfDay, and DateTime in std.datetime,
since those are effectively calendar dates/times with no concept of time zone.
They're just the date and/or time (e.g. 2012-02-05 or 14:07), which can be
_very_ useful, but it means that you have to realize that you should be using
SysTime when you actually want the system time and/or an absolute time rather
than a generic date and/or time that you're not really going to try and
associate to a particular system time. Actually, when I was doing some
date/time stuff at work (in C++), I tried to port a version of SysTime over
_without_ Date, TimeOfDay, and DateTime, since all we cared about for our stuff
was the system time, and I ended up having to add them anyway, because they
simplified things so much (if nothing else, SysTime needs them to do a lot of
its stuff).
> Interestingly, SQL has
>
> DATE - just a date, simple as that
> TIME - a time of day in unspecified time zone
> TIMETZ - a time of day with time zone specified
> TIMESTAMP - a date/time combination in unspecified time zone
> TIMESTAMPTZ - an absolute instant in time, which can be constructed and
> examined according to the system time zone
>
> Notice how different TIMETZ and TIMESTAMPTZ are, even though "TZ"
> abbreviates " WITH TIME ZONE" in both cases. Moreover, system time zones
> (in at least some SQL implementations) include DST rules, whereas the zone
> stored in a TIMETZ is just a UTC offset.
>
> In my scheme:
> - DateValue corresponds to DATE
> - TimeValue corresponds to a TIMETZ with the zone set as UTC
> - DateTime corresponds to TIMESTAMPTZ
> - LocalTime, if it were added, would correspond to TIME
>
> I'd also like to add DST handling to my library, but it'll take thinking
> about. I'm not sure what OS APIs have in the way of retrieving the DST
> rules for the locale. Though I have just discovered
> GetDynamicTimeZoneInformation in the Windows API - I'll investigate it
> later.
LOL. The OS APIs suck at giving proper time info, and Windows' not only has
very few time zones, but their data is _frequently_ wrong - especially with
regards to DST. You're also stuck reading the registry if you want timezone-
specific information rather than simply info for the current time zone.
GetDynamicTimeZoneInformation is an attempt to fix their very broken,
historical API (GetTimeZoneInformation) which doesn't take into account the
fact that DST rules can change. GetDynamicTimeZoneInformation does, but it
only exists on Vista+. However, Microsoft made it so that the functions that
use the result from GetTimeZoneInformation basically ignore what's in that
struct and use the same information that the struct from
GetDynamicTimeZoneInformation uses (probably by either using a memcmp or
checking the time zone's name to determine that it's a known timezone). And
_all_ of that is highly broken in that it bases DST switches off of the _local_
time rather than UTC. It was a nightmare to sort all of that out.
In general, Posix does much better (though you do end up having to read the
timezone files yourself if you want to use anything other than the local
timezone). It's information is _much_ more accurate, and it bases everything
off of UTC. However, unlike Windows, it's a royal pain to figure out what the
local timezone is. And the C API that they give you sucks just as much as the
Windows one does.
Yeah. I could probably complain for hours about how pathetic the time stuff is
that the OSes provide. So, I'll shut up now. I think that std.datetime does a
good job of building on top of what's there, but the patheticness of the C
APIs made it a lot harder than it should be.
- Jonathan M Davis
More information about the Digitalmars-d
mailing list