y2038 TPF Grant Delivered

schwern on 2008-10-17T23:03:20

The y2038 TPF grant has shipped all its deliverables and I now consider it to be complete. While the original estimate of August 18th was blown through, writing portable C code is a bitch, I'm happy the 2038 problem has been fixed with time to spare. All that remains now is for the patches to be integrated. (Rafael is not integrating any bleadperl branches until after 5.8.9 is released.)

Perl now has a portable means to calculate time in a range of +/- 142 million years. It also has another C programmer to help hack the perl guts.

Why 142 million years and not 292 billion as is the true range of 64 bit time? Well, it turns out that Perl has access to a portable 64 bit integer, it has no accompanying portable 64 bit integer scalar type. Because all arguments passed into a Perl function are scalars, I had to make due with double precision floating point numbers. These are accurate out to about 2**52 after which accuracy degrades. 2**52 is about 142 million years.

Since the code is a drop-in replacement for the time.h fucntions, and not specific to Perl, any project written in C can take advantage. For example, in order to allow users access to the code without patching Perl, Time::Local::Extended has been patched to include this code. The author should release a new version soon. The patch is available.

use Time::Local::Extended;
print scalar gmtime(2**52);
__END__
Sat Dec  6 03:48:16 142715360


I gave a presentation at PPW covering the problem, the usual proposed solutions which aren't, and the solution which y2038 takes.

This does not mean the end of the y2038 project. Ideally the entirety of time.h will be reimplemented. timegm() has already been done (not in the standard, but too useful to ignore), mktime() (ie. timelocal()) is next on the list and the wildly complicated strftime() has been started. 2038 bugs have been identified in Ruby and Python, they are the project's next targets.

Help is greatly appreciated.



Here is a breakdown of the project's deliverables and their conclusions.

64 bit localtime/gmtime -----------------------

* Write C versions of localtime() and gmtime() which work with times beyond 2038 regardless of the limits of the system C libraries.

Done. The y2038 project solves this problem.

* Test for negative times. * If it can be made to work, make it work. * If not, provide a proper error message.

Done and it works. It also provides a proper errno and error message on overflow or failure.

* Fix any performance issues so the process is O(1) (currently parts of the code are O(n)).

Using a little clever math, it is now O(1). The process for calculating a date does not get slower as the time increases. This sped up the time to calculate distant dates by about 10000x.

* Make gmtime64_r() properly report an EOVERFLOW error when the year is too large to be held by tm.tm_year.

Done. Also provided an option to use an alternative (but incompatible) tm struct with a bigger tm_year to punch through the y2billion bug, which Perl uses.

* Fix any portability issues.

The code is written in ANSI C89 and conforms to the POSIX spec. Tested on most Unixen and Windows. A configuration header allows tweaking.

Provide a patch for Perl which... ---------------------------------

* Adapts these libraries for perl and change pp_gmtime() and pp_localtime() to use them.

Done as a bleadperl branch.

* Add additional tests to localtime(), gmtime() and related core modules (Time::Local) for beyond 2038.

Done. Time::Local, Time::gmtime and Time::localtime were fixed and tested.

* Ensure cross-platform compatibility including any necessary Configure probing.

Done. No additional probing was necessary.

* Use the existing system libraries should they be 64 bit clean.

Done with Merijn's help to add probes to Configure.

* Works with bleadperl.

Done. Rafael is holding off integrating the branch until after 5.8.9 is released.

* Works with 5.10.

Done, no additional work is necessary. It can be included as part of the normal maint-perl process and hopefully included in 5.10.1.

* BONUS Backport to 5.8.

Done, no backporting is needed, but it is unlikely (and inadvisable) to be included in 5.8.9 this late in the process. 5.8 users can use Time::Local::Extended.