std :: mktime和时区信息

Vol*_*lkA 31 c++

我正在尝试将我认为是UTC字符串的时间信息转换为std::mktime在C++中使用的时间戳.我的问题是,<ctime>/ <time.h>没有转换为UTC的功能; mktime只会将时间戳作为本地时间返回.

所以我需要弄清楚时区偏移量并将其考虑在内,但我找不到与平台无关的方法,不涉及将整个代码移植到boost::date_time.有一些我忽略的简单解决方案吗?

Ser*_*erg 22

timestamp = mktime(&tm) - _timezone;
Run Code Online (Sandbox Code Playgroud)

或平台独立方式:

 timestamp = mktime(&tm) - timezone;
Run Code Online (Sandbox Code Playgroud)

如果你查看mktime()的来源:

http://www.raspberryginger.com/jbailey/minix/html/mktime_8c-source.html

在00117行中转换为当地时间的时间:

seconds += _timezone;
Run Code Online (Sandbox Code Playgroud)

  • 这不包括夏令时.如果时间戳是在夏令时期间创建的,那么您需要3600秒才能得到结果.问题是,您如何确定转换的时间戳是否是在夏令时期间进行的? (9认同)
  • 在_some implementation_中.这不是可以依赖的东西.将其视为_not_简单存在.这就是为什么它的名字以下划线开头. (4认同)
  • 我只是使用了"时区"(不是"_timezone")."timezone"在<time.h>中定义. (2认同)

Dan*_*und 7

mktime()使用tzname来检测时区.tzset()从TZ环境变量初始化tzname变量.如果TZ变量出现在环境中但其值为空或其值无法正确解释,则使用UTC.

根据timegm联机帮助页的便携式(非线程安全)版本

   #include <time.h>
   #include <stdlib.h>

   time_t
   my_timegm(struct tm *tm)
   {
       time_t ret;
       char *tz;

       tz = getenv("TZ");
       setenv("TZ", "", 1);
       tzset();
       ret = mktime(tm);
       if (tz)
           setenv("TZ", tz, 1);
       else
           unsetenv("TZ");
       tzset();
       return ret;
   }
Run Code Online (Sandbox Code Playgroud)

Eric S Raymond在他的文章" Time,Clock,and Calendar Programming In C"中发表了一个线程安全版本

time_t my_timegm(register struct tm * t)
/* struct tm to seconds since Unix epoch */
{
    register long year;
    register time_t result;
#define MONTHSPERYEAR   12      /* months per calendar year */
    static const int cumdays[MONTHSPERYEAR] =
        { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };

    /*@ +matchanyintegral @*/
    year = 1900 + t->tm_year + t->tm_mon / MONTHSPERYEAR;
    result = (year - 1970) * 365 + cumdays[t->tm_mon % MONTHSPERYEAR];
    result += (year - 1968) / 4;
    result -= (year - 1900) / 100;
    result += (year - 1600) / 400;
    if ((year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0) &&
        (t->tm_mon % MONTHSPERYEAR) < 2)
        result--;
    result += t->tm_mday - 1;
    result *= 24;
    result += t->tm_hour;
    result *= 60;
    result += t->tm_min;
    result *= 60;
    result += t->tm_sec;
    if (t->tm_isdst == 1)
        result -= 3600;
    /*@ -matchanyintegral @*/
    return (result);
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,此解决方案是OH GOD,因此不是THREADSAFE.如果要从两个不同的线程调用它,则必须将其包装在互斥锁中. (4认同)
  • 另请参阅[另一个问题的答案](http://stackoverflow.com/a/6474100/60075),它说使用 `setenv("TZ", "UTC", 1);` 代替,这样它就可以工作在 Windows 上。 (2认同)
  • 不可能使任何依赖于环境变量的线程安全:-( (2认同)

小智 5

昨天我遇到了同样的问题,通过搜索文档“man mktime”:

函数 mktime() 和 timegm() 将中断时间(在 *timeptr 指向的结构中)转换为与 time(3) 函数返回的值具有相同编码的时间值(即,从纪元开始的秒数,UTC)。mktime() 函数根据当前时区设置解释输入结构(请参阅 tzset(3))。timegm() 函数将输入结构解释为表示世界协调时间 (UTC)。

短的:

您应该使用 timegm,而不是使用 mktime。

问候,

  • 适用于 Linux 和 BSD。在 Windows 上使用 _mkgmtime。 (2认同)

小智 5

使用_mkgmtime,它会处理一切。


Ano*_*ous 4

mktime 假定日期值位于本地时区。因此,您可以预先更改时区环境变量(setenv)并获取 UTC 时区。

Windows tzset

也可以尝试看看各种自制的utc-mktimes、mktime-utcs等。