Why does mktime give me an hour less?

Viewed 387

I would like to see if at 00:00:00 on January 1, 1970 it actually corresponds to 0 seconds, and I wrote the following:

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

int main(void) {
    int year = 1970;
    
    struct tm t = {0};
    
    t.tm_mday = 1; // January
    t.tm_year = year - 1900;
    t.tm_hour = 0;
    t.tm_isdst = -1;
    
    printf("%ld\n", mktime(&t));
    
    return 0;
}

it gives me a value of -3600. Where am I wrong?

PS: tested with GCC v.10.1. I tried with another compiler under another architecture and it gives me back the correct value.

4 Answers

The mktime function takes a time in local time. Apparently, 00:00:00 at your local time was one hour before the epoch. Launch the program with TZ set to UTC.

The time info you provide to mktime() is in local time, so the timezone matters even if summer time / daylight savings time does not.

You can fool your program by telling it you're in UTC:

$ gcc mytime.c -o mytime
$ ./mytime
28800          <-- Pacific time in the US
$ TZ=GMT0 ./mytime
0

I would like to see if at 00:00:00 on January 1, 1970 it actually corresponds to 0 seconds, and I wrote the following:

00:00:00 on January 1, 1970 GMT, UTC corresponds to 0 seconds.

00:00:00 on January 1, 1970 Italia time corresponds to -3600 seconds.

Set timezone to UTC and then call mktime(). Unfortunately C does not have a portable way to do this, so the suggested code is only illustrative.

setenv("TZ", "UTC", 1);
tzset();
....
mktime(&t)

time_t does not necessarily match long. Recommend casting to a wide type.

// printf("%ld\n", mktime(&t));
printf("%lld\n", (long long) mktime(&t));

t.tm_mday = 1; // January misleads. .tm_mday is the day of the month, not January.

.tm_mon is the months since January so the initialization to 0 matches January.

Concerns about DST apply here only if the local time was using DST in January.

As other answers indicate, mktime works in your local time zone. However, many operating systems offer a related function timegm that works in UTC. This slight modification of your program prints 0, as expected, on my computer:

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

int main(void)
{
    int year = 1970;
    
    struct tm t = {0};
    
    t.tm_mday = 1; // January
    t.tm_year = year - 1900;
    t.tm_hour = 0;
    t.tm_isdst = -1;
    
    printf("%ld\n", timegm(&t));
    
    return 0;
}

Regrettably, this function is not standardized. You may have to define a special "feature selection macro" to get your time.h to declare it.

Related