Search code examples
cgnustrptime

strptime() reads years relative to 1900AD


I'm using a function that I've understood is not part of the standard C library. I found information about it here: 21.4.6.1 Interpret string according to given format.

It is a very helpful function and does exactly what I need. However, when using it in this very simple way:

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

int main()
{
    struct tm timedata;
    strptime("1/1/1", "%d/%m/%Y", &timedata);
    printf("day: %d\nmonth: %d\nyear: %d\n", 
        timedata.tm_mday, timedata.tm_mon, timedata.tm_year);
}

strange data is placed in the struct tm timedata. Output is:

day: 1
month: 0
year: -1899

Which doesn't make much sense to me. 1/1/1 should result in:

day: 1
month: 1
year: 1

From what I can see, this behaviour isn't to be expected when reading the GNU manual. For example:

%Y The year as a decimal number, using the Gregorian calendar.

Last time I checked, the Gregorian calendar didn't start at 1900A.D.

EDIT:

Rewrote code to check return value of function. Same problem persists.

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

int main()
{
    struct tm timedata;
    if(strptime("1/1/1", "%d/%m/%Y", &timedata))
    {
        printf("day: %d\nmonth: %d\nyear: %d\n", 
            timedata.tm_mday, timedata.tm_mon, timedata.tm_year);
    }else{
        printf("Error");
    }
 }

Output:

day: 1
month: 0
year: -1899

Solution

  • Code works correctly. struct tm does not use the same offsets as OP thought. @underscore_d

    // C11dr §7.27.1 4
    int tm_mon; // months since January — [0, 11]
    int tm_year; // years since 1900
    

    int main() {
        struct tm timedata;
        char *p = strptime("1/1/1", "%d/%m/%Y", &timedata);
        if (p) {
          printf("day: %d\nmonth since January: %d\nyear since 1900: %d\n",
            timedata.tm_mday, timedata.tm_mon, timedata.tm_year);
          printf("day: %d\nmonth: %d\nyear: %d\n", 
            timedata.tm_mday, timedata.tm_mon + 1, timedata.tm_year + 1900);
        } else {
          puts("Failed");
        }
    }
    

    Output

    day: 1
    month since January: 0
    year since 1900: -1899
    day: 1
    month: 1
    year: 1
    

    Note: strptime() is defined in POSIX.1-2001 and POSIX.1-2008, also documented in POSIXy systems using man 3 strptime. It is not in the standard C library.