将unix epoch以来的日期,时间和UTC偏移值转换为毫秒?

时间:2016-10-10 17:33:09

标签: c++ c linux datetime epoch

我正在研究一个机器人项目,它具有来自不同位置的传感器数据,精确到毫秒级(gps同步ntp到1ms内)。

如何将历史日期,时间和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偏移的历史日期时间转换为毫秒的有效方法是什么?

3 个答案:

答案 0 :(得分:2)

这是一个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)。

此库基于<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>的{​​{1}}成员函数可以使用

duration.count()

无论如何切片,这是几行类型安全的代码,没有明确的转换因子。

我注意到你用[c ++]和[c]标记了你的问题。这个答案只涉及C ++语言。 C和C ++是两种不同的语言,如果你必须用C语言编程,那么在C级抽象程序中编程的其他答案之一会更好。

对于好奇的,如果只输出cout << tp.time_since_epoch().count() << '\n'; 1476157739456

,请使用这些变体中的任何一种
tp

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

cout << tp << '\n';

答案 1 :(得分:0)

如果你有以小时+/- 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;

答案 2 :(得分:0)

如果你查看你提到的问题的接受答案,它会处理个别整数。它将字符串拆分为部分,将它们转换为整数,然后使用它们。只需删除转换部分即可。

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

如果时区是一个整数,您可以将它乘以时区的秒数,然后将减去。 +4区域意味着时间比UTC大4小时。另请注意,并非所有时区都有完整的小时数。因此,您可能希望以秒/毫秒或至少几分钟存储时区。