如何将 UTC 时间戳转换为本地时间,即整点后的秒数?
How can I convert a UTC timestamp to local time, seconds past the hour?
我有一个大型数据集,其时间戳采用 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,我就能弄清楚这部分成功转换的时间戳,但我没想到这么远。
非常感谢指导。提前致谢。
我首先将浮点数转换为 time_t
。 time_t
通常是自纪元以来的秒数(通常是 POSIX 纪元——1970 年 1 月 1 日午夜),所以这听起来只需要相当简单的数学.
因此,为了争论起见,我们假设您的输入使用了不同的纪元。只是为了争论,我们假设它使用的是 1900 年 1 月 1 日午夜的纪元(并且,如前所述,它以毫秒而不是秒为单位)。
因此,要将其转换为 time_t
,您首先要除以 1000,将毫秒转换为秒。然后减去 1900 年 1 月 1 日午夜到 1970 年 1 月 1 日午夜之间的秒数。现在你有一个值,你可以将其视为标准库可以处理的 time_t
1.
然后使用 localtime
获得与 struct tm
相同的时间。
然后将 tm
中的分钟和秒归零,并使用 mktime
得到表示该时间的 time_t
。
最后用difftime
求出两者的区别
1. 目前,我假设您的标准库基于标准 POSIX 纪元,但这是一个非常安全的假设。
After I'm able to convert it to a usable gmtime object or whatever, I need to get seconds past the hour...
以下是如何使用基于 <chrono>
的 Howard Hinnant's, free, open-source, C++11/14/17 timezone library 将表示自 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
,这是一个持有1512695257869的std::chrono::time_point<system_clock, milliseconds>
,表示时间点2017-12-0801: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();
这将创建一个能够在 UTC 和本地时间之间进行映射的 {time_zone, system_time}
对,使用 time_zone
作为该映射。它使用current_zone()
找到计算机的当前时区,并将时间点utc_ms
从毫秒精度截断到秒精度。最后,尾部 .get_local_time()
从这个映射中提取本地时间,精度为秒,并映射到当前时区。也就是说,loc_s
是自 1970 年 1 月 1 日以来的秒数 00:00:00 UTC,由 2017 年 12 月 8 日生效的本地时区 UTC 偏移量抵消 [=113] =] UTC.
现在,如果您将 loc_s
截断到小时的精度,并从 loc_s
中减去截断的时间点,您将得到本地小时后的秒数:
auto sec_past_hour = loc_s - floor<hours>(loc_s);
整个计算就是上面的两行代码。接下来的两行只是流出 utc_ms
和 sec_past_hour
.
假设您的本地时区在 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
s 可以使用 .count()
成员函数转换为它们的 "representation" 类型。对于 seconds
,此表示类型将是带符号的 64 位整数。
有关 <chrono>
的更详细的视频教程,请参阅此 Cppcon 2016 presentation。本演示文稿将鼓励您尽可能避免使用 .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,000,000,或将 "million" 拼写错误的零个数。
我有一个大型数据集,其时间戳采用 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,我就能弄清楚这部分成功转换的时间戳,但我没想到这么远。
非常感谢指导。提前致谢。
我首先将浮点数转换为 time_t
。 time_t
通常是自纪元以来的秒数(通常是 POSIX 纪元——1970 年 1 月 1 日午夜),所以这听起来只需要相当简单的数学.
因此,为了争论起见,我们假设您的输入使用了不同的纪元。只是为了争论,我们假设它使用的是 1900 年 1 月 1 日午夜的纪元(并且,如前所述,它以毫秒而不是秒为单位)。
因此,要将其转换为 time_t
,您首先要除以 1000,将毫秒转换为秒。然后减去 1900 年 1 月 1 日午夜到 1970 年 1 月 1 日午夜之间的秒数。现在你有一个值,你可以将其视为标准库可以处理的 time_t
1.
然后使用 localtime
获得与 struct tm
相同的时间。
然后将 tm
中的分钟和秒归零,并使用 mktime
得到表示该时间的 time_t
。
最后用difftime
求出两者的区别
1. 目前,我假设您的标准库基于标准 POSIX 纪元,但这是一个非常安全的假设。
After I'm able to convert it to a usable gmtime object or whatever, I need to get seconds past the hour...
以下是如何使用基于 <chrono>
的 Howard Hinnant's, free, open-source, C++11/14/17 timezone library 将表示自 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
,这是一个持有1512695257869的std::chrono::time_point<system_clock, milliseconds>
,表示时间点2017-12-0801: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();
这将创建一个能够在 UTC 和本地时间之间进行映射的 {time_zone, system_time}
对,使用 time_zone
作为该映射。它使用current_zone()
找到计算机的当前时区,并将时间点utc_ms
从毫秒精度截断到秒精度。最后,尾部 .get_local_time()
从这个映射中提取本地时间,精度为秒,并映射到当前时区。也就是说,loc_s
是自 1970 年 1 月 1 日以来的秒数 00:00:00 UTC,由 2017 年 12 月 8 日生效的本地时区 UTC 偏移量抵消 [=113] =] UTC.
现在,如果您将 loc_s
截断到小时的精度,并从 loc_s
中减去截断的时间点,您将得到本地小时后的秒数:
auto sec_past_hour = loc_s - floor<hours>(loc_s);
整个计算就是上面的两行代码。接下来的两行只是流出 utc_ms
和 sec_past_hour
.
假设您的本地时区在 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
s 可以使用 .count()
成员函数转换为它们的 "representation" 类型。对于 seconds
,此表示类型将是带符号的 64 位整数。
有关 <chrono>
的更详细的视频教程,请参阅此 Cppcon 2016 presentation。本演示文稿将鼓励您尽可能避免使用 .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,000,000,或将 "million" 拼写错误的零个数。