Search code examples
ctimemktime

mktime returns incorrect value


I'de like to use mktime on a microcontroller (or at least use 32-bit wide timestamps). I added the needed files from avr libc source files (in Atmel Studio 7, time functions aren't available), didn't change the algoritms. But for 2016. 06. 08. 23:34:00 (UTC+1, EU dst), mktime returns 518736960, but it should return 1465425240.

set_zone(ONE_HOUR);
set_dst(eu_dst);
struct tm myTime;
myTime.tm_sec = 0;
myTime.tm_min = 36;
myTime.tm_hour = 23;
myTime.tm_mday = 8;
myTime.tm_mon = 5;
myTime.tm_year = 116;
myTime.tm_isdst = ONE_HOUR;
time_t tim = mktime(&myTime);

What am I doing wrong? These functions should work fine.


Solution

  • 518736960 corresponds to Unix epoch time 09 Jun 1986 21:36:00; it looks to me as if this implementation uses a different epoch, starting 1 January 2000 rather then 1 January 1970.

    The time difference is then attributable to the TZ and DST offsets. The out-by-one date difference is attributable to the fact that 2000 was not a leap-year, but 1970 was.


    Edit:

    The documentation here clearly states that the epoch start is 2000:

    Though not specified in the standard, it is often expected that time_t is a signed integer representing an offset in seconds from Midnight Jan 1 1970... i.e. 'Unix time'. This implementation uses an unsigned 32 bit integer offset from Midnight Jan 1 2000. The use of this 'epoch' helps to simplify the conversion functions, while the 32 bit value allows time to be properly represented until Tue Feb 7 06:28:15 2136 UTC. The macros UNIX_OFFSET and NTP_OFFSET are defined to assist in converting to and from Unix and NTP time stamps.

    There is no standard for epoch nor the specific underlying width or signedness of time_t. However if you round-trip the result of mktime() with localtime() for example using the same library it will produce a correct result. One library or system's time_t value need not be compatible with another's, so exchanging a time_t value between systems is slightly problematic.

    In this case you could convert to a recognised defacto standard by adding UNIX_OFFSET or NTP_OFFSET and if necessary ensure that any corresponding adjustment is performed on the receiving system The principle is similar to the principle of network byte order for example for exchanging data between systems with different endinaness by using an agreed intermediate representation (which is as it happens also something to consider when exchanging a time_t).

    Often it is simpler to exchange a string of a specified format (such as ISO 8601) to avoid epoch, data type and endianness differences. On te other hand conversion to and from string representations is more expensive than purely arithmetic manipulation.