让mktime()忽略C++中的DST和本地时区

jgovgodb  于 11个月前  发布在  其他
关注(0)|答案(4)|浏览(105)

我们的系统从供应商处接收ASCII格式的数据“20210715083015”。这个时间是美国东部时间,并且已经调整为夏令时。
我们的后端需要从Epoch开始以纳秒为单位的时间。我试图使用mktime()进行转换,但mktime()坚持为DST添加一个小时,即使我将tm_isdst强制为0。
下面是代码片段:

std::tm tmstr{};
<breakdown ASCII time into tm structure>

tmstr.tm_isdst = 0;
cout << "isdst before: " tmstr.tm_isdst;
time_t seconds = std::mktime(&tmstr);
cout << ", isdst after: " tmstr.tm_isdst << endl;

字符串
下面是输出:

isdst before: 0, isdst after: 1


它忽略了设置值0,并应用自己的转换。
我如何使用mktime()或类似的东西,而不试图调整时间到我的时区?我宁愿不必在内部设置时区,我只是想让它直接从tm结构转换为秒。
这是g++版本7.3.1,在Redhat版本6.10下。

jtjikinw

jtjikinw1#

它忽略了设置值0
不,它不是忽略该成员。
mktime()考虑.tm_isdst,然后将所有struct tm成员调整为该日期的 * 通常值 *,因此在OP的情况下,预计会更改.tm_isdst.tm_hour,因为tmstr在7月15日的“20210715”日光时间。
我如何使用mktime()或类似的东西,而不会尝试将时间调整到我的时区?
mktime()是本地时间转换。通常的方法是让mktime()推导日光标志。

tmstr.tm_isdst = -1;

字符串
这个时间是美国东部时间,已经调整为夏令时。
不,你是说现在是美国标准东部时间(EST)。美国东部时间(ET)有日光调整。
将您的时区从有日光和标准时段的时区更改为只有标准时段的时区。研究setenv()。也许就像这样简单:

// Implementation dependent code.
setenv("TZ", "EST5", 1);
tzset();
time_t seconds = mktime(&tmstr);

缺少关键问题:time_t结果是否正确?

暂时忽略tmstr。报告的time_t值是多少?预期的time_t值是多少?
我怀疑OP确实得到了正确的time_t值,只是不是struct tm中的预期结果。

n3h0vuf2

n3h0vuf22#

希望你可以使用timegm()函数(不要与gmtime()函数混淆...更多信息请参见下文)。
mktime()函数有一个状态。如果上一次使用它时isdst设置为0,那么使用isdst = -1将使用0。如果上一次使用它时isdst设置为1,那么使用isdst = -1将使用1。只有当时间变化发生时,函数被调用时才是真的(在1h窗口内)。其他函数也不太可能改变该变量(即localtime()也可能影响该状态,我还没有测试过)。

// a date when the time change happened (Sun Oct 26 01:08:48 PST 1980)
time_t et = 341399328;

struct tm t = {};
localtime_r(&et, &t);

struct tm ot = {};
ot.tm_year = t.tm_year;
ot.tm_mon = t.tm_mon;
ot.tm_mday = t.tm_mday;
ot.tm_hour = t.tm_hour;
ot.tm_min = t.tm_min;
ot.tm_sec = t.tm_sec;

ot.tm_isdst = 1;
std::cerr << " +--> " << mktime(&ot) << " (1)\n";
ot.tm_isdst = 0;
std::cerr << " +--> " << mktime(&ot) << " (0)\n";
ot.tm_isdst = -1;
std::cerr << " +--> " << mktime(&ot) << " (-1)\n"; // same as 0

ot.tm_isdst = 0;
std::cerr << " +--> " << mktime(&ot) << " (0)\n";
ot.tm_isdst = 1;
std::cerr << " +--> " << mktime(&ot) << " (1)\n";
ot.tm_isdst = -1;
std::cerr << " +--> " << mktime(&ot) << " (-1)\n"; // same as 1

字符串
输出应该始终与输入相同(即从time_t转换为struct tm,反之亦然)。相反,我得到:
341399328 -> 1980/10/26 1:8:48
电话:+341395728(1)
电话:+341399328(0)
电话:+341399328(-1)
电话:+341399328(0)
电话:+341395728(1)
电话:+341395728(-1)
所以,或多或少,你不能相信mktime()转换。
现在有两个新函数:timegm()timelocal()timelocal()函数与mktime()相同。timegm()完全忽略了本地时区,因此您可以正确地来回转换UTC时间。匡威的是gmtime()
换句话说:

  1. time_tstruct tm,带gmtime()
  2. struct tmtime_t,带timegm()
    并且(1)中的输入time_t将总是等于(2)中的输出time_t
umuewwlo

umuewwlo3#

在这里发帖比较方便……
mktime()手册页中,您没有阅读所写的内容.
mktime()函数的作用是:将分解的时间结构转换为本地时间,日历时间表示。该函数忽略调用方在tm_wdaytm_yday字段中提供的值。在tm_isdst字段中指定的值通知mktime()是否使用夏令时(DST)在tm结构中提供的时间内有效:正值表示DST有效;零表示DST无效;而负值意味着mktime()应该(使用时区信息和系统数据库)尝试确定DST是否在指定时间生效。
mktime()函数按如下方式修改tm结构的字段:tm_wdaytm_yday被设置为根据其他字段的内容确定的值;如果结构成员超出其有效区间,则将对其进行规范化(例如,10月40日改为11月9日); tm_isdst已设置(无论其初始值如何)分别为正值或0,以指示DST在指定时间是否生效。调用mktime()还将使用有关当前时区的信息设置外部变量tzname

fbcarpbf

fbcarpbf4#

似乎没有办法阻止mktime()应用DST。但它确实告诉我们它是否添加了额外的小时。因此一个简单的修复方法如下.

time_t t = mktime( &tmst );
  if(tmst.tm_isdst == 1)
    t -= 60*60;

字符串

相关问题