mktime 返回不正确的值
Posted
技术标签:
【中文标题】mktime 返回不正确的值【英文标题】:mktime returns incorrect value 【发布时间】:2016-10-09 09:38:25 【问题描述】:我想在微控制器上使用mktime
(或至少使用 32 位宽的时间戳)。我从avr libc source files 添加了所需的文件(在 Atmel Studio 7 中,时间函数不可用),没有更改算法。但是对于 2016.06.08.23:34:00(UTC+1,欧盟夏令时),mktime
返回518736960
,但它应该返回1465425240
。
set_zone(ONE_HOUR);
set_dst(eu_dst);
struct tm myTime;
myTime.tm_sec = 0;
myTime.tm_min = 36;
myTime.tm_hour = 23;
myTime.tm_mday = 8;
myTime.tm_mon = 5;
myTime.tm_year = 116;
myTime.tm_isdst = ONE_HOUR;
time_t tim = mktime(&myTime);
我做错了什么?这些功能应该可以正常工作。
【问题讨论】:
“标准库”?不,这是一个包含一些非标准函数的 C 库实现。我们不知道幕后还有哪些其他不可移植的行为。tm::tm_isdst
如果 DST 有效,则为正数,如果无效则为零,如果没有可用信息,则为负数 - 将其发送到ONE_HOUR
几乎没有意义。省略非标准部分 - set_zone()
和 set_dst()
并设置 tm_isdst==0
看看结果如何。如果您设置的时间是您不想要的时间(即已经调整),则不需要时区或 DST 调整。
Better to first struct tm myTime = 0;
as struct tm
可能有其他实现定义字段未由 OP 代码设置。
@klenium :我的建议不是为了解决问题,而是为了让您排除这些函数中出现错误的可能性,以便您可以确定问题是 mktime()
- 这就是您调查软件错误的方式 - 分而治之。
@Clifford 我也曾怀疑过一个不同的日子,但不以为然,因为预期和实际之间的差异显然不是 100 的倍数(因此不是 3600*24 的倍数),因为时代是错误的,对于给定的时间戳,预期也必须是错误的。我曾假设 OP 的部分只有 1 oops。 IAC,阅读很棒的手册是个好主意。
【参考方案1】:
518736960 对应 Unix 纪元时间 09 Jun 1986 21:36:00;在我看来,这个实现好像使用了不同的时代,从 2000 年 1 月 1 日开始,而不是 1970 年 1 月 1 日。
时间差可归因于 TZ 和 DST 偏移。相差一个日期的原因是 2000 年不是闰年,但 1970 年是。
编辑:
文档here 明确指出纪元开始时间是 2000 年:
虽然标准中没有指定,但通常期望 time_t 是一个有符号整数,表示从 1970 年 1 月 1 日午夜开始的偏移量,以秒为单位......即“Unix 时间”。此实现使用从 2000 年 1 月 1 日午夜开始的无符号 32 位整数偏移量。使用此“纪元”有助于简化转换函数,而 32 位值允许正确表示时间,直到 2136 年 2 月 7 日星期二 06:28:15世界标准时间。定义宏 UNIX_OFFSET 和 NTP_OFFSET 是为了帮助在 Unix 和 NTP 时间戳之间进行转换。
没有纪元标准,也没有time_t
的特定底层宽度或签名。但是,如果您将mktime()
的结果与localtime()
进行往返,例如使用相同的库,它将产生正确的结果。一个库或系统的 time_t
值不必与另一个库或系统的值兼容,因此在系统之间交换 time_t
值会有点问题。
在这种情况下,您可以通过添加UNIX_OFFSET
或NTP_OFFSET
转换为公认的事实标准,并在必要时确保对接收系统进行任何相应的调整。原理类似于@987654322 的原理@ 例如,通过使用商定的中间表示在具有不同终结性的系统之间交换数据(这在交换 time_t
时也需要考虑)。
通常交换指定格式的字符串(例如ISO 8601)更简单,以避免时代、数据类型和字节序的差异。另一方面,与字符串表示的转换比纯粹的算术操作更昂贵。
【讨论】:
以上是关于mktime 返回不正确的值的主要内容,如果未能解决你的问题,请参考以下文章