mktime returns -1 when given a valid struct tm

12,858

Solution 1

In you case 43 (1943) is considered as a not valid year. The reason is that mktime return a time_t type. This type is not really standardized. What the documentation said :

The time_t type is an integral value representing the number of seconds elapsed since 00:00 hours, Jan 1, 1970 UTC. And tm_year is the number of years since 1900

This link What is ultimately a time_t typedef to? says :

time_t represents the number of seconds since the start of the Unix epoch: midnight UTC of January 1, 1970 (not counting leap seconds). Some systems correctly handle negative time values, while others do not.

If we consider that time_t is a signed 32 bits integer, in the best scenario you can create date between ~ 13/12/1901 and 19/1/2038

But in your case the implementation does not use the negative part of time_t, so you cannot create date prior 1970 with mktime.

Solution 2

time_t is a 64-bit integer on your system and you're using the wrong format flag specifier to print it out. You need to use the ll modifier to indicate that it's 64 bits:

time_t t = mktime(&stm);
printf("%lld", (int64_t)t);  // This will be correct if time_t is 32 or 64 bits

Since the time is before the epoch (January 1, 1970), the time is a negative value like -851910873, which is 0xffffffffcd38df27 in hex as a 64-bit integer. When you try to print it out as a 32-bit integer, you get the upper 32 bits, which is 0xffffffff or -1 (although technically this is undefined behavior according to the C standard, so don't rely on this).

As others have mentioned, the actual size of time_t is not specified, so you shouldn't make any assumptions about it. The safest thing to do is to always widen it to 64 bits if you really need to know how big it is.

Share:
12,858
Charlie Skilbeck
Author by

Charlie Skilbeck

Updated on September 14, 2022

Comments

  • Charlie Skilbeck
    Charlie Skilbeck over 1 year
    #include <stdio.h>
    #include <time.h>
    
    int main(int argc, char* argv[])
    {
        struct tm stm;
        stm.tm_sec = 27;
        stm.tm_min = 5;
        stm.tm_hour = 18;
        stm.tm_mday = 2;
        stm.tm_mon = 0;
        stm.tm_year = 43;
        stm.tm_wday = 0;
        stm.tm_yday = 0;
        printf("%d\n", mktime(&stm));
        getchar();
        return 0;
    }
    

    prints -1

    What am I misunderstanding?

    [+edit] this is using Visual Studio 2012 with 32 bit target. I guess a follow up question would be 'what is the recommended method for storing arbitrary date/time values (i.e. those which may be before 1900)?'

    • Admin
      Admin over 11 years
      Why don't you check errno or use perror to find out what is wrong?
    • Charlie Skilbeck
      Charlie Skilbeck over 11 years
      someone deleted the answer, which is that the year is invalid - I was using a version of strptime which based years from 1970 rather than 1900.
    • benjarobin
      benjarobin over 11 years
      I did delete temporally my answer, I need to check something (I was right the first time)
  • Matteo Italia
    Matteo Italia over 11 years
    Actually, POSIX says that time_t is a signed type (link), so, when it's implemented as a 32 bit integer, it can be used to express up to 68 years before 1970.
  • Mat
    Mat over 11 years
    time_t is signed, 1943 is not out of range.
  • benjarobin
    benjarobin over 11 years
    @Mat It really depend of the implementation, please fully read the link of Matteo Italia stackoverflow.com/questions/471248/… . time_t represents the number of seconds since the start of the Unix epoch: midnight UTC of January 1, 1970 (not counting leap seconds). Some systems correctly handle negative time values, while others do not.
  • benjarobin
    benjarobin over 11 years
    This is not because time_t is signed that computation of date prior 1970 are implemented. Since the standard doesn't say anything about this, the support of date prior 1970 may not added.