timegm cross platform

I use the following macro on Windows:

#define timegm _mkgmtime

as _mkgmtime does the same.


For most functions, that I know of, there is no difference.

The underscore in the names is there to emphasize that these are not standard C functions: AFAIK, there are not tzset nor setenv functions in ANSI C. They are mostly POSIX functions that are implemented by the MS CRT as an aid for portability from other operating systems.

But they don't claim POSIX compatibility, that's why the underscore. And that's why you should be careful and read the MS documentation about these functions... there are demons there!


// Algorithm: http://howardhinnant.github.io/date_algorithms.html
int days_from_epoch(int y, int m, int d)
{
    y -= m <= 2;
    int era = y / 400;
    int yoe = y - era * 400;                                   // [0, 399]
    int doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;  // [0, 365]
    int doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;           // [0, 146096]
    return era * 146097 + doe - 719468;
}

// It  does not modify broken-down time
time_t timegm(struct tm const* t)     
{
    int year = t->tm_year + 1900;
    int month = t->tm_mon;          // 0-11
    if (month > 11)
    {
        year += month / 12;
        month %= 12;
    }
    else if (month < 0)
    {
        int years_diff = (11 - month) / 12;
        year -= years_diff;
        month += 12 * years_diff;
    }
    int days_since_epoch = days_from_epoch(year, month + 1, t->tm_mday);

    return 60 * (60 * (24L * days_since_1970 + t->tm_hour) + t->tm_min) + t->tm_sec;
}

This is a portable way to convert tm in UTC to time_t.

Note that it does not modify/normalise tm structure and it does not change any tz settings.


When David Cutler's team started on the Windows NT design, back in 1989, they didn't yet know which api was going to be dominant. So they created three of them. Win32 was an adaption of the 16-bit version of the Windows api. OS/2 was supported, the operating system that was supposed to supplant DOS but didn't. And Posix was the third, added because the USA government back then specified that they would only consider using operating systems that followed the emerging Posix standard.

The tzset() function you mention is a left-over from the Posix api. You probably misspelled putenv(), same story. The subsystem didn't fare well, Win32 won the api battle in a big way and Posix support was removed from Windows in 2001. Microsoft kept the support for the Posix functions but renamed them with a leading underscore since they are not part of the standard C library. You are supposed to get deprecation warnings when you use the non-prefixed version of the functions. Sounds like you #defined _CRT_NONSTDC_NO_DEPRECATE to suppress them. Best to not do that. Favor the standard C library functions.