Skip to content

Amazing Discoveries

m42a edited this page Mar 9, 2013 · 1 revision

Date handling limits

tm->tm_year

Many operating systems make time_t bigger but forget to increase the size of tm->tm_year. They fail at Y2^31-1, a bit after 2 billion years.

OS X

Despite now using 64 bit CPUs (Intel Core Duo 2) still uses 32 bit integers and time_t, presumably to avoid having 32 and 64 bit versions of software. So it fails at the normal 32 bit boundries.

10.6 appears to have fixed this, but a new bug emerges. gmtime loses Dec 31st, -2235476. It ticks over from Dec 30th, 23:59:59, -2235476 to Jan 1st, 00:00:00, -2235475 causing all subsequent calendar dates to be off by a day. This has been reported to Apple as bug 7654647.

Another bit of 10.6 fun. timegm() and mktime() both hang at gmtime(-4136232677718). This is Wed Jan 1 14:24:44 -129102. This has been reported to Apple as 7704213.

OpenVMS

Normally uses an unsigned time_t, so they can go all the way out to 2^32-1. Also has an option to use a signed time_t, for Unix compatibility, but unfortunately it appears they left tm->tm_year unsigned so negative time_t returns nonsensical dates.

Visual C++ 2008, 2009

time_t is signed, but the date functions and difftime() don't work with negative times. time_t is also > 32 bit but has a bizarre y3001 bug.

Also VC8 is missing the C99 strtoll() function.

VC6, VC7, GCC on Windows, Borland C

Signed 32 bit upper limit, but can't handle negative times.

AIX <= 5.2

According to the perl source...

/* AIX 5.2 and below use mktime for localtime, and defines the edge case
 * for time 0x7fffffff to be valid only in UTC. AIX 5.3 provides localtime64
 * available in the 32bit environment, which could warrant Configure
 * checks in the future.
 */

Read the whole sordid tale.

AIX again

Merijn informs me that before year 0 AIX gets very, very slow.

HP/UX

Has a Y10K bug, but interestingly fails inside Y10k not at the end of Y9999.

Linux 64 bit

For distant dates in the past appears to be returning localtime() calculations based on solar noon, so Europe/Berlin is a few minutes before Europe/Paris. This is a pretty clever solution for times before the invention of standard time zones. Unfortunately they seem to be doing it for full time zones like US/Pacific. I don't know what solar noon would be for the entire Pacific time zone region.

BSD

On 64 bit FreeBSD 7.2 mktime() and timegm() cannot handle a negative year.

Both gmtime() and localtime() stop working about 30 seconds before the y231 bug.

mktime()

None of FreeBSD, Linux nor OS X properly return a "can not represent date" error for the missing hour during DST spring ahead. Example...

#include <stdio.h>
#include <time.h>
#include <stdlib.h>

/* 2008 March 9th, 2:59:59am does not exist in an American time zone
   because of DST change from 2am -> 3am
*/
int main(void) {
    time_t when;
    struct tm date;
    struct tm *localdate;

    date.tm_sec = 59;
    date.tm_min = 59;
    date.tm_hour = 2;
    date.tm_mday = 9;
    date.tm_mon  = 2;
    date.tm_year = 108;
    date.tm_isdst = -1;

    when = mktime(&date);

    printf("time: %d\n", (int)when);

    localdate = localtime(&when);
    printf("%04d.%02d.%02d %02d:%02d:%02d\n",
           localdate->tm_year + 1900, 
           localdate->tm_mon + 1,
           localdate->tm_mday,
           localdate->tm_hour,
           localdate->tm_min,
           localdate->tm_sec
          );

    return 0;
}

Also, mktime() is documented to return -1 when it can not represent a date. This means there is no way to differentiate between an error and Dec 31st, 23:59:59.