将日期、时间和 UTC 偏移值转换为自 unix 纪元以来的毫秒数?
Posted
技术标签:
【中文标题】将日期、时间和 UTC 偏移值转换为自 unix 纪元以来的毫秒数?【英文标题】:Converting date, time and UTC offset values to milliseconds since unix epoch? 【发布时间】: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
是使用未调整的日期时间值设置的?
【参考方案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 -= hoursih;
cout << tp.time_since_epoch() << '\n';
这个输出:
1476157739456ms
这是自纪元以来的正确Unix Time 毫秒数。如果您需要包含闰秒,上述链接中有相应的功能,但该部分不是仅标题(需要使用IANA timezone database)。
这个库是基于<chrono>
的。特别是tp
的类型是std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds>
,但语法更漂亮。
如果您的输入流遵循标准的 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);
如果你想要毫秒的整数值,可以使用<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
【讨论】:
你的演讲真的很棒! :) 该示例编译并运行,但是在运行in >> parse("%F %T", lt) >> ih;
行时我收到Segmentation fault (core dumped)
。我错过了什么吗?我正在使用带有标志-std=c++11
的g++
编译示例。
包含-0400
的第二个示例运行良好。你的图书馆很棒!有没有一种与创建日期类似的方法来创建日期时间?那是auto x1 = yeary/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_daysyeary/m/d + hoursh + minutesm + secondss + millisecondsms
(达到你想要的任何精度)。如果您想要本地时间而不是 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
"将本地时间转换为日历值。"以上是关于将日期、时间和 UTC 偏移值转换为自 unix 纪元以来的毫秒数?的主要内容,如果未能解决你的问题,请参考以下文章
在 VBA 中,如何以简单的方式将 UTC UNIX 时间戳转换为本地时区日期?