Search code examples
cmktimeubuntu-20.04tzdata

mktime or tz database unexpected return for 1941


mktime returns for july 3rd 1941 (00:00:00) and july 4th 1941 (00:00:00) are unexpected. The difference between the two is 82800 seconds, lacking a full hour (3600).

The C program diff1941.c (see below) shows the following :

    $> diff1941

    july3=-899337600i
    diff:82800 should be 86400

At first I thought it was a TZ Database hour shift, but as far as I understand, and according to zdump command, there is no such shift for 1941.

    zdump -v -c 1940,1943 /etc/localtime

    /etc/localtime  Sun Feb 25 01:59:59 1940 UT = Sun Feb 25 01:59:59 1940 WET isdst=0 gmtoff=0
    /etc/localtime  Sun Feb 25 02:00:00 1940 UT = Sun Feb 25 03:00:00 1940 WEST isdst=1 gmtoff=3600
    /etc/localtime  Fri Jun 14 21:59:59 1940 UT = Fri Jun 14 22:59:59 1940 WEST isdst=1 gmtoff=3600
    /etc/localtime  Fri Jun 14 22:00:00 1940 UT = Sat Jun 15 00:00:00 1940 CEST isdst=1 gmtoff=7200
    /etc/localtime  Mon Nov  2 00:59:59 1942 UT = Mon Nov  2 02:59:59 1942 CEST isdst=1 gmtoff=7200
    /etc/localtime  Mon Nov  2 01:00:00 1942 UT = Mon Nov  2 02:00:00 1942 CET isdst=0 gmtoff=3600

So at this point I am confused. Either my program has a bug that I can not see (possible), or there is a bug in lib C mktime function(unlikely), or there is something subtle in the TZ database and I can not find it (probable): what do you think of it ?

I am using:

  • Ubuntu 20.04 64 bits,
  • libc 2.31-0ubuntu9,
  • tzdata 2019c-3ubuntu1
  • /etc/localtime points on /usr/share/zoneinfo/Europe/Paris

diff1941.c:

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

long int stamp(int d,int m,int y)
{
   struct tm date;
   memset(&date,0,sizeof(date));

   date.tm_mday=d;
   date.tm_mon=m-1;
   date.tm_year=y-1900;

   return mktime(&date);
}

int main(int argc, char **argv)
{
    if (argc>1)
        setenv("TZ","0",1);
    long int july3=stamp(3,7,1941);
    long int july4=stamp(4,7,1941);

    printf("july3=%ldi\n",july3);
    printf("diff:%ld should be 86400\n",july4-july3);
}

Solution

  • Usually, when you see 1 hour difference in time, that means you should take a look at daylight saving time settings.

    On both dates 3rd July 1941 and 4th July 1941 daylight saving time was in effect in France. You specify tm_isdst = 0, that means the daylight saving time is not in effect for your dates. So your dates are invalid - there was no such time as 3rd July 1941 with 00:00:00 with no DST.

    Glibc mktime tries it's best to determine what time do you have in mind. Actually it determines the first of the dates as 3rd July 1941 02:00:00 and the second of the dates as 4th July 1941 01:00:00. The difference is one day minus one hour.

    Either set isdst=-1 to let mktime "automagically" determine the current DST for your input times. In France it was DST all the time in 1941, it will determine isdst=1. Or explicit specify that you want DST by setting date.isdst=1.