How to convert a UTC date & time to a time_t in C++?

I have decided to implement my own version of mkgmtime and it was easier than I thought.

const int SecondsPerMinute = 60;
const int SecondsPerHour = 3600;
const int SecondsPerDay = 86400;
const int DaysOfMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

bool IsLeapYear(short year)
{
    if (year % 4 != 0) return false;
    if (year % 100 != 0) return true;
    return (year % 400) == 0;
}

time_t mkgmtime(short year, short month, short day, short hour, short minute, short second)
{
    time_t secs = 0;
    for (short y = 1970; y < year; ++y)
        secs += (IsLeapYear(y)? 366: 365) * SecondsPerDay;
    for (short m = 1; m < month; ++m) {
        secs += DaysOfMonth[m - 1] * SecondsPerDay;
        if (m == 2 && IsLeapYear(year)) secs += SecondsPerDay;
    }
    secs += (day - 1) * SecondsPerDay;
    secs += hour * SecondsPerHour;
    secs += minute * SecondsPerMinute;
    secs += second;
    return secs;
}

My main concern was that mkgmtime must be consistent with gmtime. Such that gmtime(mktime(t)) returns the original input values. Therefore I have compared the results for all multiples of 61 between 0 and MAX_INT for time_t and they are indeed equal (at least on my system). Therefore the above routine is correct.

This outcome also means that the C library does not take leap seconds into account, which is a bad thing in itself but good for my purpose. The two functions will stay consistent for a long time. To be absolutely sure, my Timestamp class that uses this function always performs a quick check on program start and proves the consistency for a couple of meaningful values.


For completeness, here's a version of mkgmtime() that takes a struct tm* as argument:

static time_t mkgmtime(const struct tm *ptm) {
    time_t secs = 0;
    // tm_year is years since 1900
    int year = ptm->tm_year + 1900;
    for (int y = 1970; y < year; ++y) {
        secs += (IsLeapYear(y)? 366: 365) * SecondsPerDay;
    }
    // tm_mon is month from 0..11
    for (int m = 0; m < ptm->tm_mon; ++m) {
        secs += DaysOfMonth[m] * SecondsPerDay;
        if (m == 1 && IsLeapYear(year)) secs += SecondsPerDay;
    }
    secs += (ptm->tm_mday - 1) * SecondsPerDay;
    secs += ptm->tm_hour       * SecondsPerHour;
    secs += ptm->tm_min        * SecondsPerMinute;
    secs += ptm->tm_sec;
    return secs;
}

Tags:

C++

Time T