Re: Algorithm to exploit 32 bit time functions to do time zone calculations

Michael G Schwern <[email protected]> Wed, 17 Sep 2008 16:00:03 -0700
Newsgroups gmane.os.miros.general,gmane.comp.lib.libtai
Message-ID <[email protected]>
It's very nice to have someone else to bounce this all off of.


Thorsten Glaser wrote:
>> Maybe you can shed some light on this problem, what to do about year 0=
?
>=20
> I actually haven=E2=80=99t thought about year 0, since localtime/mktime=
 do that,
> and mjd2tm and tm2mjd from DJB code. I think it=E2=80=99s illegal, isn=E2=
=80=99t it?

Illegal according to who?

C99 and POSIX 1003.1 define tm.tm_year as a signed int with a range of "y=
ears
since 1900" which makes a negative year perfectly "legal".


>> Right now the only limit I have on dates is the limit of what Time64_T
>> can store. Does it make sense to stop at 0?
>=20
> No, it makes sense to not stop. The thing is, mktime() and gmtime()
> *must* have full round-trip capabilities (GNU autoconf checks for that
> before it uses it), which is why, for example, my tai64_t data type doe=
s
> not exactly store what DJB calls a TAI timestamp. There is a small wrap=
-
> around at about 0x8000000000000000 (time_t) / 0xC000000000000000 (tai64=
_t)
> of 10 (I think, due to the leap seconds) seconds. So, for whatever valu=
e
> you have in whatever representation (time_t, tai64_t, struct tm), all o=
f
> these must have full round-trip capabilities (with the possible excepti=
on
> that struct tm with a 64-bit year can go beyond the 64-bit time_t value
> scale, but then, a 32-bit year does the same for a 32-bit time_t, so th=
is
> is no change).

I'm a little lost.  Could you give an example?


>> localtime()... well, localtime() gets absurd real fast.  Gregorian/Jul=
ian
>> calendar shifts.
>=20
> Mh. Maybe a struct tm.tm_year is always Gregorian? Have a look, while a=
t
> it, at the "%J" strftime modifier (and, especially, my implementation o=
f
> it, using the tm2mjd function). This will get you Julian days, but noth=
ing
> in Unix has them split off into a calendar time kind of structure.

C99 says "Many functions [in time.h] deal with a calendar time that repre=
sents
the current date (according to the Gregorian calendar) and time."

But then goes on to say:

"Some functions deal with local time, which is the calendar time expresse=
d for
some specific time zone, and with Daylight Saving Time, which is a tempor=
ary
change in the algorithm for determining local time. The local time zone a=
nd
Daylight Saving Time are implementation-defined."

POSIX 1003.1 does not appear to discuss the matter.

It seems clear to me that gmt is always Gregorian but not so clear what
happens with localtime().

I wonder how a Chinese locale deals with this.  They switched from Julian=
 to
Gregorian after 1901, so it should show up in any Chinese localtime()
implementation.  Also Russia and much of Eastern Europe.


> So I think you don=E2=80=99t need to worry about THAT. That=E2=80=99s a=
pplication layer
> to do, similar to hebrew, muslim, asian etc. calendars. And at that, it
> REALLY gets absurd (cf. http://blogs.msdn.com/michkap/default.aspx), bu=
t
> that=E2=80=99s not the (our) OS=E2=80=99 job to worry about.
>=20
> However, for =E2=80=9Cabsurd=E2=80=9D years, the OS=E2=80=99 own functi=
ons might go crazy. Too
> bad we can=E2=80=99t access the OS=E2=80=99 own time zone table (I need=
 to get the info
> for leap seconds out of it, for example).

I'm just glad that ctime() isn't locale sensitive.  Oi, what a mess that =
would be.


PS  I just found this gem in the mktime() standard:

    the original values [in the tm struct] of the other components are no=
t
    restricted to the ranges described in <time.h>.

which the BSD time.h man page expands out to:

     The original values of the tm_wday and tm_yday components of the str=
uc-
     ture are ignored, and the original values of the other components ar=
e not
     restricted to their normal ranges, and will be normalized if needed.=
  For
     example, October 40 is changed into November 9, a tm_hour of -1 mean=
s 1
     hour before midnight, tm_mday of 0 means the day preceding the curre=
nt
     month, and tm_mon of -2 means 2 months before January of tm_year.  (=
A
     positive or zero value for tm_isdst causes mktime() to presume initi=
ally
     that summer time (for example, Daylight Saving Time) is or is not in
     effect for the specified time, respectively.  A negative value for
     tm_isdst causes the mktime() function to attempt to divine whether s=
ummer
     time is in effect for the specified time.  The tm_isdst and tm_gmtof=
f
     members are forced to zero by timegm().)

     On successful completion, the values of the tm_wday and tm_yday comp=
o-
     nents of the structure are set appropriately, and the other componen=
ts
     are set to represent the specified calendar time, but with their val=
ues
     forced to their normal ranges; the final value of tm_mday is not set
     until tm_mon and tm_year are determined.  The mktime() function retu=
rns
     the specified calendar time; if the calendar time cannot be represen=
ted,
     it returns -1;

This is something I haven't tested for yet.


PPS  How does one get the damn qsecretary program to stop making you conf=
irm
every email to this list?  I'm already subscribed.


--=20
The interface should be as clean as newly fallen snow and its behavior
as explicit as Japanese eel porn.