【问题标题】:Converting date, time and UTC offset values to milliseconds since unix epoch?将日期、时间和 UTC 偏移值转换为自 unix 纪元以来的毫秒数?
【发布时间】:2017-02-19 04:43:36
【问题描述】:

我正在从事一个机器人项目,该项目具有来自不同位置的传感器数据,精度为毫秒(gps 将 ntp 同步到 1 毫秒内)。

如何将历史日期、时间和 UTC 偏移分量转换为自 unix 纪元以来的毫秒数?也就是说,所有YYYY-mm-dd HH:MM:SS.mS +/-UTC offset 都可以作为单独的整数使用,而不是字符串。

偏移量考虑了夏令时,例如,UTC +1 的时区在夏令时期间的 UTC 偏移量将是 +2。

有一个similar post,但它处理的是字符串格式的日期时间,没有 UTC 偏移信息。

该帖子接受的答案是使用mktime,但在this post 中,一位超过60K 的代表用户评论说:

mktime 将使用您计算机的区域设置将该日期/时间转换为 GMT。如果您不想减去本地时区,请使用 mkgmtime。

我已经确认mktime 确实执行了依赖于夏令时标志tm_isdst 的时区转换。我没有信息是否在夏令时期间进行了观察,只有它们与 UTC 的偏移量。

自 unix 纪元以来,将具有 UTC 偏移量的历史日期时间转换为毫秒的稳健方法是什么?

【问题讨论】:

  • 如果您查看您提到的问题的公认答案,它会处理单个整数。它将字符串拆分为部分,将它们转换为整数,然后使用它们。只需删除转换部分。
  • 是的。请记住,有半小时的时区。所以 timeZone 不应该以小时为单位。
  • 还有刻钟时区。
  • 使用库。提升 Date_time 是一种选择。
  • @DirkEddelbuettel 感谢您对 Boost.Date_Time 的建议,我看了看,找不到使用 UTC 偏移量获取 unix 纪元的方法。您是否建议手动从 local_date_time 中减去 UTC 偏移量,其中 local_date_time 是使用未调整的日期时间值设置的?

标签: c++ c linux datetime epoch


【解决方案1】:

这是一个free, open-source C++11/14 header-only library,它可以完成这项工作。它是fully documented,可在所有 C++11/14 实现中移植。甚至还有一个video presentation

#include "chrono_io.h"
#include "date.h"
#include <iostream>
#include <sstream>

int
main()
{
    using namespace std;
    using namespace std::chrono;
    using namespace date;
    istringstream in{"2016-10-10 23:48:59.456 -4"};
    sys_time<milliseconds> tp;
    int ih;
    in >> parse("%F %T", tp) >> ih;
    tp -= hours{ih};
    cout << tp.time_since_epoch() << '\n';
}

这个输出:

1476157739456ms

这是自纪元以来的正确Unix Time 毫秒数。如果您需要包含闰秒,上述链接中有相应的功能,但该部分不是仅标题(需要使用IANA timezone database)。

这个库是基于&lt;chrono&gt; 的。特别是tp 的类型是std::chrono::time_point&lt;std::chrono::system_clock, std::chrono::milliseconds&gt;,但语法更漂亮。

如果您的输入流遵循标准的 UTC 偏移语法 +/-hhmm 而不是 +/-[h]h,则代码可以简化为:

istringstream in{"2016-10-10 23:48:59.456 -0400"};
sys_time<milliseconds> tp;
in >> parse("%F %T %z", tp);

这将为tp 输出完全相同的值。

1476157739456ms

也支持这种修改后的语法:

istringstream in{"2016-10-10 23:48:59.456 -4:00"};
sys_time<milliseconds> tp;
in >> parse("%F %T %Ez", tp);

如果你想要毫秒的整数值,可以使用&lt;chrono&gt;duration.count()成员函数:

cout << tp.time_since_epoch().count() << '\n';

1476157739456

不管你怎么切,这是几行类型安全的代码,没有明确的转换因子。

我注意到您使用 [c++] 和 [c] 标记了您的问题。此答案仅针对 C++ 语言。 C 和 C++ 是两种不同的语言,如果您必须用 C 编程,那么在 C 抽象级别编程的其他答案之一会更好。

如果你只是输出tp

cout << tp << '\n';

然后它输出预期的 UTC 时间戳:

2016-10-11 03:48:59.456

【讨论】:

  • 你的演讲真的很棒! :) 该示例编译并运行,但是在运行in &gt;&gt; parse("%F %T", lt) &gt;&gt; ih; 行时我收到Segmentation fault (core dumped)。我错过了什么吗?我正在使用带有标志-std=c++11g++ 编译示例。
  • 包含-0400 的第二个示例运行良好。你的图书馆很棒!有没有一种与创建日期类似的方法来创建日期时间?那是auto x1 = year{y}/m/d;。我问的原因是年月日等都是int。您演示文稿中的 make_zoned 函数看起来可能能够获取 int 值?。
  • 我的偏移值也不是时区,而是记录传感器数据时与 UTC 的实际偏移量。因此无需担心夏令时转换,UTC 可以映射到两个本地日期时间。
  • @rippleing 对于核心转储,在parse 之后检查in.fail()。如果为 true,则 ih 未初始化。哪个版本的 gcc 核心转储了? -std=c++11 应该足够了。
  • @ripple:日期时间是 chrono::time_point,sys_time 表示 UTC,或 local_time 表示本地要与 time_zone 配对。 auto x1 = sys_days{year{y}/m/d} + hours{h} + minutes{m} + seconds{s} + milliseconds{ms}(达到你想要的任何精度)。如果您想要本地时间而不是 UTC 时间,请使用 local_days 而不是 sys_days
【解决方案2】:

如果您查看您提到的问题的公认答案,它会处理单个整数。它将字符串拆分为部分,将它们转换为整数,然后使用它们。只需放下转换部分。

tm t;
// Fill tm_sec, tm_min, tm_hour and so on
return (mktime(&t) - tz * SECONDS_IN_TIMEZONE) * 1000 + milliseconds

如果 timezone 是整数,您可以将其乘以 timezone 的秒数,如果从 time 乘以 substract。 +4 区域表示时间比 UTC 多 4 小时。另请注意,并非所有时区都有整数小时数。因此,您可能希望以秒/毫秒或至少分钟为单位存储时区。

【讨论】:

    【解决方案3】:

    如果您的时区以小时 +/- UTC 表示,您可以首先使用 mktime(如链接答案所述)将日期/时间转换为自纪元以来的秒数。然后,添加/减去时区差异。

    编辑:

    由于mktime 函数假定给定时间是针对当前时区的,因此您还需要将结果移动该数量。

    首先,运行tzset() 函数。这会设置两个全局变量:timezone 是当前时间落后于 GMT 的秒数,daylight 表示夏令时是否有效。

    struct tm my_time;
    // populate fields
    int my_tz;
    // set to timezone in question as seconds ahead of UTC
    time_t t = mktime(&my_time);
    t += timezone;
    if (daylight) {
        t -= 3600;
    }
    t -= my_tz;
    

    【讨论】:

    • 我有 +/-UTC 的时区。我更新了这篇文章,以突出我读到的受人尊敬的用户(60K+ 代表)关于 mktime 自动将日期时间从当前时区转换为 UTC 的内容?这是正确的吗?
    • mktime "将本地时间转换为日历值。"
    猜你喜欢
    • 2020-12-04
    • 2011-10-23
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 2019-12-04
    • 2020-09-14
    • 1970-01-01
    相关资源
    最近更新 更多