我有一个大型数据集,其时间戳以UTC时间为单位,以毫秒为单位。我正在将此数据集与另一个时间戳为超过小时的时间戳同步,因此我需要将第一个时间转换为本地时间,以秒为单位。
我在这个主题上读到的大多数类似问题都是从time()函数得到的UTC时间,它得到当前时间。
我已尝试实施从C++ Reference拉出的以下内容。
我尝试转换的时间戳是双倍的,但我不确定如何实际使用此值。
来自我的数据集的示例ts:1512695257869
int main ()
{
double my_utc_ts; //value acquired from the data set
time_t rawtime;
struct tm * ptm;
time ( &rawtime ); //getting current time
//rawtime = my_utc_ts; //this is what I tried and is wrong, and results in a nullptr
ptm = gmtime ( &rawtime );
puts ("Current time around the World:");
printf ("Phoenix, AZ (U.S.) : %2d:%02d\n", (ptm->tm_hour+MST)%24, ptm->tm_min);
return 0;
}
在我能够将它转换为可用的gmtime对象或其他任何东西之后,我需要超过一小时...我想如果我可以获得UTC时间戳,我将能够计算出这一部分成功转换,但我还没有想到这么远。
非常感谢指导。提前谢谢。
答案 0 :(得分:2)
在我能够将它转换为可用的gmtime对象或其他任何东西后,我需要超过一小时......
以下是如何使用基于<chrono>
的{{3}}将自1970-01-01 00:00:00 UTC以来的双倍表示毫秒转换为超过当地小时的秒数:
#include "date/tz.h"
#include <iostream>
int
main()
{
using namespace std::chrono;
using namespace date;
double my_utc_ts = 1512695257869;
using ms = duration<double, std::milli>;
sys_time<milliseconds> utc_ms{round<milliseconds>(ms{my_utc_ts})};
auto loc_s = make_zoned(current_zone(), floor<seconds>(utc_ms)).get_local_time();
auto sec_past_hour = loc_s - floor<hours>(loc_s);
std::cout << utc_ms << " UTC\n";
std::cout << sec_past_hour << " past the local hour\n";
}
这为我输出:
2017-12-08 01:07:37.869 UTC
457s past the local hour
如果您的本地时区不是与UTC偏移的整数小时数,则第二行输出将与您不同。
我们从您的输入my_utc_ts
开始。
下一行创建一个自定义std::chrono::duration
,其中double
为表示,milliseconds
为精度。此类型别名名为ms
。
下一行构造utc_ms
,std::chrono::time_point<system_clock, milliseconds>
持有1512695257869,代表时间点2017-12-08 01:07:37.869 UTC。到目前为止,还没有进行实际的计算。只需将double 1512695257869
强制转换为表示自1970-01-01 00:00:00 UTC以来的整数毫秒的类型。
这一行开始计算:
auto loc_s = make_zoned(current_zone(), floor<seconds>(utc_ms)).get_local_time();
这将创建一个{time_zone, system_time}
对,能够使用time_zone
作为该映射,在UTC和本地时间之间进行映射。它使用current_zone()
来查找计算机的当前时区,并将时间点utc_ms
从精度毫秒缩短到精度秒。最后,尾随.get_local_time()
从此映射中提取本地时间,精度为秒,并映射到当前时区。也就是说,loc_s
是自1970-01-01 00:00:00 UTC以来的秒数,由您在2017-12-08 01:07生效的本地时区的UTC偏移量抵消:37 UTC。
现在,如果您将loc_s
截断为精确的小时数,并从loc_s
中减去截断的时间点,您将获得超过当地小时的秒数:
auto sec_past_hour = loc_s - floor<hours>(loc_s);
整个计算只是上面两行代码。接下来的两行只是流出utc_ms
和sec_past_hour
。
假设您的本地时区在UTC时间2017-12-08 01:07:37 UTC的整数小时内偏离UTC,您可以仔细检查:
457 == 7*60 + 37
事实上,如果 你可以假设你的本地时区总是偏离UTC整整几个小时,那么上面的程序可以通过不映射到当地时间:
sys_time<milliseconds> utc_ms{round<milliseconds>(ms{my_utc_ts})};
auto utc_s = floor<seconds>(utc_ms);
auto sec_past_hour = utc_s - floor<hours>(utc_s);
结果将是相同的。
(警告:并非所有时区都与UTC相差整数小时)
如果已知您的数据库生成的时区不是计算机的当前本地时区,则可以将current_zone()
替换为生成数据库的IANA时区标识符,从而将其考虑在内。例如:
auto loc_s = make_zoned("America/New_York", floor<seconds>(utc_ms)).get_local_time();
整个库基于C ++ 11引入的std <chrono>
库。上面utc_ms
和loc_s
的类型是std::chrono::time_point
的实例,sec_past_hour
的类型std::chrono::seconds
(它本身就是std::chrono::duration
的实例化)。
duration
成员函数将 .count()
转换为其“表示”类型。对于seconds
,此表示类型将是带符号的64位整数。
有关<chrono>
的详细视频教程,请参阅此Howard Hinnant's, free, open-source, C++11/14/17 timezone library。此演示文稿将鼓励您尽可能避免使用.count()
成员函数。
例如,不要将sec_past_hour
转换为long
,以便将其与数据集的其他值进行比较,而是将数据集的其他值转换为std::chrono::duration
,以便您可以将它们与sec_past_hour
进行比较。
例如:
long other_data = 123456789; // past the hour in microseconds
if (microseconds{other_data} < sec_past_hour)
// ...
此代码段显示<chrono>
将如何为您处理单位转化。这意味着你不会犯错误,比如你应该乘以1,000,000,或用错误的零数拼写“百万”。
答案 1 :(得分:0)
我首先将浮点数转换为time_t
。 time_t
通常是自纪元以来的秒数(通常是POSIX纪元 - 午夜,1970年1月1日),所以听起来似乎只需要一点点相当简单数学。
因此,为了论证,您假设您的输入使用不同的时期。仅仅为了论证,让我们假设它使用的是一个午夜时代,1900年1月1日(而且,如上所述,它是以毫秒而不是秒为单位)。
因此,要将其转换为time_t
,您必须先除以1000以将毫秒转换为秒。然后你减去1900年1月1日午夜到1970年1月1日午夜之间的秒数。现在你有一个值可以视为标准库可以处理的time_t
1 < / SUP>
然后使用localtime
获得与struct tm
相同的时间。
然后将tm
的分钟和秒数归零,并使用mktime
得到代表该时间的time_t
。
最后,使用difftime
来区分两者。
1.目前,我假设您的标准库基于标准POSIX时代,但这是一个非常安全的假设。 功能