将日期、时间和 UTC 偏移值转换为自 unix 纪元以来的毫秒数?

Converting date, time and UTC offset values to milliseconds since unix epoch?

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

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

夏令时的偏移量,例如,UTC +1 的时区在夏令时期间的 UTC 偏移量为 +2。

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

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

mktime will use your computer's locale to convert that date/time into GMT. If you do not want to have your local timezone subtracted, then use mkgmtime.

我已经确认 mktime 确实执行了取决于夏令时标志 tm_isdst 的时区转换。我不知道这些观察是否是在夏令时期间进行的,只有它们对 UTC 的偏移量。

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

如果您有以小时 +/- UTC 为单位的时区,您可以先使用 mktime(如链接答案所述)将 date/time 转换为纪元以来的秒数。然后,add/subtract时差。

编辑:

由于 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;

如果您查看您提到的问题的已接受答案,它涉及单个整数。它将字符串拆分为多个部分,将它们转换为整数,然后使用它们。只需删除转换部分。

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

如果时区是一个整数,您可以将它乘以时区中的秒数,如果是从时间中减去。 +4 时区表示时间比 UTC 时间长 4 小时。另请注意,并非所有时区都具有整数小时数。因此,您可能希望将时区存储在 seconds/milliseconds 或至少几分钟内。

这是其中的一个free, open-source C++11/14 header-only library which will do the job. It is fully documented, and portable across all C++11/14 implementations. There is even a 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 milliseconds since the epoch. If you need to include leap seconds, there are facilities for that at the above links, but that part is not header-only (requires using the IANA timezone database).

的正确数字是哪个

此库是基于 <chrono> 的。特别是 tp 的类型是 std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>,但语法更漂亮。

如果您的输入流遵循 +/-hhmm 的标准 UTC 偏移语法而不是 +/-[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);

如果你想要毫秒的整数值,可以用<chrono>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