Clock.currTime differs from SysTime

Jonathan M Davis newsgroup.d at jmdavisprog.com
Sat Aug 25 15:00:12 UTC 2018


On Saturday, August 25, 2018 6:53:24 AM MDT Ivo via Digitalmars-d-learn 
wrote:
> I am using Clock.currTime.stdTime to get a unique timestamp in my
> program.
> Now I need to produce something similar in a different
> programming language; so I'm trying to understand how
> Clock.currTime works.
>
> According the the documentation Clock.currTime.stdTime should
> return the number of hnseconds since 00:00 of 01/01/0001 A.D.
> UTC. However it seems that it returns less than what claimed.
>
> Consider the following code:
>
> import std.stdio;
> import std.datetime.date : DateTime;
> import std.datetime.timezone : UTC;
> import std.datetime.systime;
>
> void main() {
>
> auto now = Clock.currTime;
> auto date = DateTime(2018, 8, 25, 14, 42, 0); //this is changed
> manually
> auto st = SysTime(date, UTC());
> writeln(st.stdTime);
> writeln(st.toISOExtString);
> writeln(now.stdTime);
> writeln(now.toISOExtString);
>
> }
>
> I'm done a few tries and here is an output:
> 636708049200000000 //this is st.stdTime
> 2018-08-25T14:42:00Z
> 636707977205129550 //this is now.stdTime
> 2018-08-25T14:42:00.512955
>
> So here is the problem: the difference in time is less than 0.6
> seconds (according to the strings), nevertheless the difference
> of the 2 numbers is 71994870450.
> 71994870450 hnsecs = 71994870450 x 10^{-7} secs = 7199,487045
> secs (unless my maths is wrong)
>
> So what actually is Clock.currTime.stdTime counting?

By default, Clock.currTime returns a SysTime with LocalTime as the TimeZone.
stdTime is always in UTC. So, now's TimeZone is LocalTime, and when you
print it out as a string, you get the date and time in your local time zone
(which you can tell by the lack of time zone information on the end of the
string), whereas when you then construct a SysTime using the same date and
time as your local time zone but tell it that it's in UTC, then the two
values are going to be off by the offset between your local time zone and
UTC - and of course, casting to DateTime strips off the fractional seconds.

If you want to cast a SysTime to DateTime and then construct a SysTime from
it again, then you need to construct the SysTime with the same TimeZone, or
they won't be the same.

And sadly, even if you _do_ do that, and the time was right on the second
(so that there are no fractional seconds), they _still_ might not be the
same if the date and time are near a DST switch. Even though it _usually_
works to convert between a time zone and UTC, in the general case, it's
impossible - with some DST switches you get times that are completely
skipped and thus technically aren't valid, whereas at other DST switches,
you have times that happen twice, resulting in ambiguity. That's why SysTime
always holds the time internally in UTC rather than in whatever time zone
it's set to. The TimeZone object is just used when a function on SysTime
requires that it be converted out of UTC (e.g. when printing out a string or
using a property like year). Unfortunately, that still leaves a problem of
what to do when constructing a SysTime from date and time during a DST
switch, and SysTime does it's best, but unfortunately, trying to convert
from a time zone to UTC is inherently a buggy process.

In this particular case, DST almost certainly was not a factor, but you
still ran into problems, because you used a different time zone when
constructing the new object. So, while it's certainly sometimes necessary to
construct a SysTime from a DateTime (or separate numbers), it's almost
always better to leave the result of Clock.currTime as a SysTime rather than
doing something like casting to DateTime and then constructing another
SysTime from it. Done "correctly," it will work most of the time, but you'll
still be screwed around DST switches.

- Jonathan M Davis





More information about the Digitalmars-d-learn mailing list