【问题标题】:C++ time_t problemC++ time_t 问题
【发布时间】:2011-04-09 07:50:21
【问题描述】:

我在使用 C++ (VS 2008) 进行日期管理时遇到问题。

根据MSDN specificationstime_t代表:

自 1970 年 1 月 1 日 0:00 UTC 以来的秒数

因此,我写了这段代码:

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

time_t GetDate(int year, int month, int day, int hour, int min, int sec)
{
    time_t rawtime;
    struct tm * timeinfo;
    
    time ( &rawtime );
    timeinfo = gmtime ( &rawtime );
    timeinfo->tm_year = year - 1900;
    timeinfo->tm_mon = month - 1;
    timeinfo->tm_mday = day;
    timeinfo->tm_hour = hour;
    timeinfo->tm_min = min;
    timeinfo->tm_sec = sec;
    timeinfo->tm_isdst = 0; // disable daylight saving time
    
    time_t ret = mktime ( timeinfo );
    
    return ret;
}

int main ()
{
    time_t time_0 = GetDate(1970,1,1,0,0,0);
    // time_0 == -1 !!!
    time_t time_1 = GetDate(1970,1,1,1,0,0);
    // time_1 == 0 !!!
    return 0;
}

它似乎移动了 1 小时(即零时间是 1970 年 1 月 1 日 1:00 UTC)。

最初,我认为问题可能来自 DayLightSaving 标志,但更改它并不会改变它。

我做错了吗?

提前致谢


附: 理论上,我可能不介意零时间值,因为它只是一个参考时间。

但我需要确定值,因为我正在将代码移植到另一种语言,并且我需要得到完全相同的结果。


编辑:

这是解决方案,感谢Josh Kelley Answer

time_t mktimeUTC(struct tm* timeinfo)
{
    // *** enter in UTC mode
    char* oldTZ = getenv("TZ");
    putenv("TZ=UTC");
    _tzset();
    // ***

    time_t ret = mktime ( timeinfo );

    // *** Restore previous TZ
    if(oldTZ == NULL)
    {
        putenv("TZ=");
    }
    else
    {
        char buff[255];
        sprintf(buff,"TZ=%s",oldTZ);
        putenv(buff);
    }
    _tzset();
    // ***

    return ret;
}

【问题讨论】:

  • -1 是错误条件,而不是 1970 年 1 月 1 日之前的 1 秒。
  • 他应该检查 -1 返回的 errno 并查看它的设置。

标签: c++ c visual-studio-2008 time


【解决方案1】:

mktime 接受 struct tm 给出 本地 时间并返回自 1970 年 1 月 1 日 0:00 UTC 以来的秒数。因此,如果您的本地时区是 UTC,您的 GetDate(1970,1,1,0,0,0); 调用将返回 0,但可能会返回其他时区的其他值。

编辑:对于mktime 或您的GetDate 的UTC 版本,请尝试以下(未经测试):

  1. 调用getenv保存TZ环境变量的当前值(如果有的话)。
  2. 调用putenv 将TZ 环境变量更改为“UTC”。
  3. 致电_tzset 激活您的更改。
  4. 致电mktime
  5. 恢复TZ的旧值,然后再次调用_tzset

【讨论】:

  • 是的,我明白了。以及如何在我的时区获得对应于 1970,1,1,0,0,0 的 UTC 日期?
  • @digEmAll:你刚刚做到了。 UTC 时间是恒定的,无论您在哪个时区都无关紧要。本地时间(struct tm 保存的时间)始终与当前时区相关。如果你的意思是我如何让它返回零。算出 1970 年 1 月 1 日 00:00:00 在子午线时您当地的时间(我认为那是 UTC 时间的起点)。
  • @Martin:对不起,我之前的评论写得不好(我不是英语)。我的意思是,如果我可以(可能使用函数)在我的时区(即 1970/1/1 1:0:0)中获得 1970/1/1 0:0:0 UTC 的相应值,mktime 将返回正确的值(即 0)
【解决方案2】:

只是一个 WAG,但请尝试以下操作:

timeinfo->tm_year = year - (unsigned long)1900;
timeinfo->tm_mon = month - (unsigned long)1;

【讨论】:

  • 嗯...什么是 TM 环境变量?
  • 是的......乔希解释得比我好。
  • 为什么要转换成unsigned long ???如果年份是unsigned,那么 1900 将转换为 unsigned。那么为什么不使用1900UL呢?这个答案的原因是什么?你只是在给这个线程添加噪音。
猜你喜欢
  • 1970-01-01
  • 2017-03-25
  • 2019-04-12
  • 1970-01-01
  • 2017-04-11
  • 1970-01-01
  • 2020-01-20
  • 2017-04-09
  • 1970-01-01
相关资源
最近更新 更多