Search code examples
c++mktimetime.htime-t

Problem when converting from time_t to tm then back to time_t


I have a time_t value of 1530173696 which represents Thursday, June 28, 2018 8:14:56 AM.

I want to round down the time to the nearest hour. Specifically, down to 1530172800, which represent Thursday, June 28, 2018 8:00:00 AM. So, my idea is to convert this time_t to a tm struct, and then assign its sec and min values to 0.

However, after I do that, and after I convert the modified tm back to a time_t value, the value I get is way off. I get a value of 1530158400 which represents Thursday, June 28, 2018 4:00:00 AM. That's 4 hours off. Even checking values of up to 8:59:59 AM still gives the rounded down value of 4:00:00 AM.

I wrote the code below to demonstrate the problem. I use VisulStudio 2017.

I don't understand what I am doing wrong. I appreciate any help. Thanks.

#include <iostream>
#include <time.h>

bool equalTMs(tm& tm1, tm& tm2);
void printTM(tm& myTM);

int main()
{
    tm myTM;
    time_t datetime = 1530173696;
    //datetime = 1530176399; // to check the time_t value of 8:59 AM
    gmtime_s(&myTM, &datetime);
    myTM.tm_sec = 0;
    myTM.tm_min = 0;
    time_t myTime_T = mktime(&myTM);

    tm sanityCheckTM;
    time_t roundedDownToNearestHour = 1530172800;
    gmtime_s(&sanityCheckTM, &roundedDownToNearestHour);
    time_t sanityCheckTimeT = mktime(&sanityCheckTM);

    std::cout << "datetime: " << datetime << std::endl;
    std::cout << "myTime_T: " << myTime_T << std::endl;
    std::cout << std::endl;
    std::cout << "roundedDownToNearestHour: " << roundedDownToNearestHour << std::endl;
    std::cout << "sanityCheckTimeT: " << sanityCheckTimeT << std::endl;
    std::cout << std::endl;
    std::cout << "myTM and sanityCheckTM equal? " << (equalTMs(myTM, sanityCheckTM) ? "true" : "false") << std::endl;

    std::cout << "\nmyTM:-\n\n";
    printTM(myTM);
    std::cout << "\nsanityCheckTM:-\n\n";
    printTM(sanityCheckTM);
    std::cout << "\n";

    time_t _time_t = 1530158400;
    tm _tm;
    gmtime_s(&_tm, &_time_t);
    std::cout << "_time_t: " << _time_t << std::endl;
    std::cout << "_tm and sanityCheckTM equal? " << (equalTMs(_tm, sanityCheckTM) ? "true" : "false") << std::endl;

    std::cout << "\n_tm:-\n\n";
    printTM(_tm);

}

void printTM(tm& myTM)
{
    std::cout << "tm_sec: " << myTM.tm_sec << std::endl;
    std::cout << "tm_min: " << myTM.tm_min << std::endl;
    std::cout << "tm_hour: " << myTM.tm_hour << std::endl;
    std::cout << "tm_mday: " << myTM.tm_mday << std::endl;
    std::cout << "tm_mon: " << myTM.tm_mon << std::endl;
    std::cout << "tm_year: " << myTM.tm_year << std::endl;
    std::cout << "tm_wday: " << myTM.tm_wday << std::endl;
    std::cout << "tm_yday: " << myTM.tm_yday << std::endl;
    std::cout << "tm_isdst: " << myTM.tm_isdst << std::endl;
}

bool equalTMs(tm& tm1, tm& tm2)
{
    return (tm1.tm_sec == tm2.tm_sec)
        && (tm1.tm_min == tm2.tm_min)
        && (tm1.tm_hour == tm2.tm_hour)
        && (tm1.tm_mday == tm2.tm_mday)
        && (tm1.tm_mon == tm2.tm_mon)
        && (tm1.tm_year == tm2.tm_year)
        && (tm1.tm_wday == tm2.tm_wday)
        && (tm1.tm_yday == tm2.tm_yday)
        && (tm1.tm_isdst == tm2.tm_isdst);
}

Solution

  • gmtime_s() returns a tm that is expressed in UTC time. You pass that to mktime(), which expects the tm to be expressed in LOCAL time instead. Your StackOverflow profile says you are located in Abu Dhabi, whose time zone is GMT+4. That is why you have a 4-hour discrepancy.

    Use localtime_s() instead of gmtime_s().