【问题标题】:Problem when converting from time_t to tm then back to time_t从 time_t 转换为 tm 然后再转换回 time_t 时出现问题
【发布时间】:2019-04-12 10:41:11
【问题描述】:

我的time_t 值为1530173696,它代表Thursday, June 28, 2018 8:14:56 AM

我想将时间四舍五入到最接近的小时。具体来说,一直到1530172800,它代表Thursday, June 28, 2018 8:00:00 AM。所以,我的想法是将此time_t 转换为tm 结构,然后将其secmin 值分配给0

但是,在我这样做之后,在我将修改后的 tm 转换回 time_t 值之后,我得到的值就差了很多。我得到一个值1530158400,它代表Thursday, June 28, 2018 4:00:00 AM。那是4小时的休息时间。即使检查高达8:59:59 AM 的值,仍会给出4:00:00 AM 的向下舍入值。

我写了下面的代码来演示这个问题。我使用 VisulStudio 2017。

我不明白我做错了什么。我很感激任何帮助。谢谢。

#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);
}

【问题讨论】:

    标签: c++ mktime time.h time-t


    【解决方案1】:

    gmtime_s() 返回以 UTC 时间 表示的tm。您将其传递给mktime(),它期望tm 改为以本地时间 表示。您的 StackOverflow 个人资料显示您位于阿布扎比,其时区为 GMT+4。这就是为什么你有 4 小时的差异。

    使用localtime_s() 而不是gmtime_s()

    【讨论】:

    • 这很有效,而且很有意义。非常感谢。对我的问题进行投票将不胜感激。
    【解决方案2】:

    由于1530173696 被用作Unix Time(UTC 不包括闰秒),因此可以在不涉及时区的情况下解决此问题。

    Howard Hinnant's date/time library 可用于解决此问题,并检查您是否得到正确答案。但是,如果您想了解如何在不使用任何库的情况下非常简单地执行此操作,请跳到此答案的末尾。

    1530173696 是自 1970-01-01 UTC 以来的秒数。如果您想将其转换为人类可读的日期/时间,可以:

    #include "date/date.h"
    #include <iostream>
    
    int
    main()
    {
        time_t datetime = 1530173696;
        date::sys_seconds tp{std::chrono::seconds{datetime}};
        using date::operator<<;
        std::cout << tp << '\n';
    }
    

    哪个输出:

    2018-06-28 08:14:56
    

    这只会验证输入。此外,tp 只不过是基于system_clockstd::chrono::time_point,但精度为seconds。您可以使用以下方法将其四舍五入:

    tp = floor<std::chrono::hours>(tp);
    

    这里的floor可以从namespace date下的"date.h"抓取,或者如果你有C++17或更高版本,你可以使用std::chrono::floor。你可以使用"date.h"再次打印tp,你会得到:

    2018-06-28 08:00:00
    

    (根据需要)。要将其转回time_t,只需提取duration,然后提取count

    time_t myTime_T = tp.time_since_epoch().count();
    

    这将具有预期的值1530172800

    最后,如果您不需要以人类可读的形式打印这些时间戳,您可以自己轻松计算:

    time_t myTime_T = datetime / 3600 * 3600;
    

    这基本上与以下操作相同:

    tp = floor<std::chrono::hours>(tp);
    

    除了floor 版本将在输入是否定的情况下继续得到正确答案(1970-01-01 00:00:00 UTC 之前的时间戳)。当给出否定输入时,“手动”实现将向上下一个小时。

    【讨论】:

      猜你喜欢
      • 2015-05-06
      • 2016-12-11
      • 1970-01-01
      • 2014-02-02
      • 2016-05-23
      • 1970-01-01
      • 2022-11-12
      • 2021-07-21
      • 2018-06-04
      相关资源
      最近更新 更多