如何将UTC时间戳转换为超过一小时的本地时间?

时间:2017-12-08 23:35:16

标签: c++ utc

我有一个大型数据集,其时间戳以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时间戳,我将能够计算出这一部分成功转换,但我还没有想到这么远。

非常感谢指导。提前谢谢。

2 个答案:

答案 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_msstd::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_mssec_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_msloc_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_ttime_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时代,但这是一个非常安全的假设。 功能