[M3devel] leap-second issue with Date.i3

Mika Nystrom mika at async.caltech.edu
Mon Nov 12 12:42:09 CET 2007


Now it's not clear to me that [0..59] was wrong in the first place.
The key thing to remember is that the following oft-repeated statement
(from the FreeBSD time(3) man page)...

     The time() function returns the value of time in seconds since 0 hours, 0
     minutes, 0 seconds, January 1, 1970, Coordinated Universal Time.

is actually wrong.  Today, the "right"(*) specification is that the
time() function returns a value that is currently 23 (I think that's
the number) less than the number of seconds since the Unix epoch.
This is obvious if you've ever noticed that the 0th second of a
minute always comes out divisible by 60 in Unix time.  The leap
seconds are just not representable in Unix time.  POSIX localtime
can't return 60 for the seconds, because the same POSIX time
represents two different seconds.

Wikipedia talks about this a bit.  They give the example of Unix
time 915,148,800, which corresponds to BOTH 23:59:60 UTC on December
31, 1998 and 00:00:00 UTC on January 1, 1999.  I am a bit baffled
why POSIX bothers to have the 60 in their struct tm definition, if
the underlying timeval data structure just can't represent the time
in question.  That is, when you pass 915,148,800 to Date.FromTime
you probably get 00:00:00 UTC, Jan 1, 1999, and NOT 23:59:60 UTC,
Dec. 31, 1998, even though both are equally correct.

There is however a cryptic comment in my localtime man page that

     The asctime(), ctime(), difftime(), gmtime(), localtime(), and mktime()
     functions conform to ISO/IEC 9899:1990 (``ISO C90''), and conform to
     ISO/IEC 9945-1:1996 (``POSIX.1'') provided the selected local timezone
     does not contain a leap-second table (see zic(8)).

I read the zic man page several times and am none the wiser!!!!

... that is, I don't know if POSIX functions localtime et al. can ever
return 60 for the seconds field.  Possibly FreeBSD ones may if zic is
fed the proper information, but then does that mess up the Unix time 
values?  (One would think it would have to.)

I really just want to be sure that my server programs don't crash 
because they try to do something like s : [0..59] := 60 at an 
inopportune moment!  (And your solution accomplishes that, at least.)

      Mika

(*) actually the correct specification for the Unix time defines
it in terms of UTC.  Unix time = 86400*(# of days since Jan 1, 1970)
+ 3600 * UTC.hour + 60 * UTC.minute + UTC.second.  It follows from this
definition that Unix time maps neither linearly nor single-valuedly to 
actual time.


Tony Hosking writes:
>I see no problem with changing seconds to [0..60].  That matches the  
>POSIX spec nicely enough.
>
>On Nov 10, 2007, at 6:33 AM, Mika Nystrom wrote:
>
>> Hello everyone,
>>
>> I just ... added a workaround for a nasty bug I had in some code
>> of my own.  My code used Unix's localtime to convert a Time.T to a
>> Date.T using the zoneinfo files.  I'm not sure if there's a "normal"
>> way to do this in M3, so I have some messy stuff involving mutexes,
>> static storage, etc.  (Note one has to be careful when linking this
>> stuff into a program with the normal M3 conversion codes--- 
> Date.FromTime
>> and Date.ToTime---which also use (other) hidden mutexes to protect
>> some of the same data structures!)
>>
>> The issue is this.  I just realized that localtime sometimes returns
>> "60" for the seconds---namely, during a leap second!  Just copying
>> this into a Date.T will lead to a range error and a program crash.
>> Do we really want Modula-3 users to have to restart their servers
>> the moment after popping the champagne corks?  (Ok, well during
>> New Year's Eve in my time zone, but still...)
>>
>> Does anyone know how Date.T handles/should handle this?  As correct
>> as it is, I find it somewhat unsatisfying to change the seconds
>> field to [0..60], because off-by-one errors are so common in
>> programming... it's probably The Right Thing to do, though.
>>
>>      Mika



More information about the M3devel mailing list