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

Michael G Schwern <[email protected]> Tue, 16 Sep 2008 18:34:34 -0700
Newsgroups gmane.os.miros.general,gmane.comp.lib.libtai
Message-ID <[email protected]>
Thorsten Glaser wrote:
> Michael G Schwern dixit:
>=20
>> You: "Your shit is boring."
>=20
> More like "has been done already". Sorry.

Apology accepted.  Sorry things got off to a bad start.


>> If I understand correctly, that's an entire operating system.
>=20
> Yes, but the gist is, that there is code which uses a certain 64-bit ty=
pe,
> called time_t, but you could of course just use int64_t instead, which =
does
> the job quite fine. (Not even a binary change in the time zone data for=
mat.)

Is this approach portable outside BSD?

My main targets are Perl, Python and Ruby which have to be absurdly porta=
ble.
 As I understand it, almost nothing about the time zone database is porta=
ble.
 For example, I could not expect tzload() to work on all operating system=
s.  I
would have to ship my own, which I do not want to do, or write time zone =
code
for each operating system, which I also do not want to do.

I could be wrong, I'm really a Perl programmer who plays a C programmer o=
n TV.

That said, I do recognize that a lot of my work will boil down to just do=
ing a
search and replace for "time_t" with "Time64_T" and "int" with "Int64_T".=
  For
example, asctime().  It's really the trick to get localtime() working tha=
t's
important.  I intend to loot BSD code for everything I can, right now I'm
mostly using it mostly as a reference.  In fact, I'm considering changing=
 from
MIT to BSD license to make that even easier.

Speaking of asctime(), I think this is a y2**31 bug in asctime3:

	char			year[INT_STRLEN_MAXIMUM(int) + 2];

Since 64 bit time can go well above the year 2 billion, years must be sto=
red
as 64 bit ints.  If int is 32 bits, the code above is only allocating eno=
ugh
room for 2**31 years.

I've been testing a lot of 64 bit system's time handling lately and that'=
s a
common mistake, 32 bit years.  Though not as bad as HP/UX's Y10k bug.

Oh, don't forget to make tm.tm_year 64 bit!


>> Also you might want to have a look at the tests in y2038.
>=20
> This is actually a good idea. Compiling (I think it was) CVS with the
> changes was a good test too, as the configure script =E2=80=9Cchecks wh=
ether
> mktime() works=E2=80=9D. To get that right (over all of the 64 bit) was=
 hard.
> You have to think about very many border cases=E2=80=A6 in the end, I j=
ust
> ensured the round-trip via tai64_t was right, not neccessarily the
> tai64_t representation itself.

To test timegm() I just round tripped it through gmtime() at various
interesting times.

    time =3D 60*60*16;
    gmtime64_r(&time, &date);
    is_Int64( timegm64(&date), time, "timegm64(60*60*16)" );

An mktime() test should work the same way, round trip through localtime()=
, no?
You can see the test here (and I really should put all that repeated code=
 into
its own test function).
http://code.google.com/p/y2038/source/browse/trunk/t/timegm.c

Anyhow, if you're interested in the Test Anything Protocol, a really simp=
le
implementation is here:
http://code.google.com/p/y2038/source/browse/trunk/tap.c

And the code to run them is here in the "tap_tests" target.
http://code.google.com/p/y2038/source/browse/trunk/Makefile

More info about TAP can be found here:
http://testanything.org/wiki/index.php/Main_Page

The MyTAP library used by MySQL might be relevant (and cleaner than mine)
http://www.kindahl.net/mytap/doc/

And MySQL's documentation on that.
http://dev.mysql.com/doc/mysqltest/en/unit-test.html


--=20
The mind is a terrible thing,
and it must be stopped.