【问题标题】:boost::posix_time::time_duration overflow?boost::posix_time::time_duration 溢出?
【发布时间】:2016-10-06 22:23:02
【问题描述】:

我有以下代码从 posix_time 获取 UNIX 时间

boost::posix_time::ptime time1(boost::gregorian::date(9999,12,31));
boost::posix_time::ptime epoch(boost::gregorian::date(1970,1,1));

boost::posix_time::time_duration diff = time1-epoch;
cout<<"A: "<<time1<<endl;
cout<<"B: "<<epoch<<endl;
cout<<"C: "<<diff<<endl;

unix_time = diff.total_seconds()

给我这个输出

9999-Dec-31 00:00:00
1970-Jan-01 00:00:00
-1347834:03:51.933722624

现在diff 不应该是负数。我怎样才能正确计算?有溢出吗?

【问题讨论】:

  • long long, 但diff 已经是负数了
  • 这可能就是你要找的:en.wikipedia.org/wiki/Year_2038_problem
  • 我不使用原来的 32 位 unix 时间
  • 好信息,因为它看起来确实是这样。
  • 您是否将-DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG 设置为纳秒精度?我怀疑这是问题所在,我认为这会减少支持的日期范围(在 2262 年某处) - 尽管您需要详细调查代码以查看其失败的位置..

标签: c++ boost boost-date-time


【解决方案1】:

(顺便说一句 - 我在下面的输出中使用了 coliru,我的本地 gcc 5.3.1 和 boost 1.60 重现)

问题是你想要这个数字以秒为单位,所以让我们尝试一些基本的数学运算(看看我是否正确!):)

A: 9999-Dec-31 00:00:00
B: 1970-Jan-01 00:00:00
C: 70389504:00:00

因此差异(以小时表示)为 70389504 小时。以秒为单位:

70389504 * 60 * 60 => 253402214400 秒

现在,在库的内部,sec_type 的类型 def 默认为 boost::int32_t。所以除非设置为int64_t,否则上面的值会溢出。

至于如何覆盖它,除非你破解 date_time 库,并将 time_resolution_traits.h 中的默认值从 boost::int32_t 更改为 boost::int64_..(可能有另一种方法,但我没有'没有足够详细地研究代码来告诉你那会是什么......)

现在,对于您真正的问题,您似乎拥有这套-DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG - 我怀疑您想要纳秒精度?如果是这样,我认为您必须减少支持的日期范围。

【讨论】:

  • 谢谢!是的,我设置了DBOOST_DATE_TIME_POSIX_TIME_STD_CONFIG。是否有机会检测到溢出?
  • Erm,如果设置了标志,没有破解库将sec_type(真的是var_type)的大小设置为64位,没有办法解决这个问题......你可以提交错误报告,看看他们是否会在下一个版本中修复它?
  • ...或者像霍华德强调的那样使用上面的库 - 它似乎能够处理您所追求的范围......
【解决方案2】:

这是 boost::date_time: https://svn.boost.org/trac/boost/ticket/3109 中的一个已知问题

time_duration 可以表示比 boost::time_duration::total_seconds() 类型可以表示的秒数更大的间隔。

如果需要总秒数,最好用

time_duration td = ...
auto seconds = td.ticks() / time_duration::ticks_per_seconds();

【讨论】:

    【解决方案3】:

    您始终可以通过从零减去正/负来反转它。

    diff = 0 - diff; // if diff was negative it will be positive now.
    

    编辑 1:额外信息;

    您还公式 time1-epoch 将计算 2 个时间点之间的差异。您应该将差异添加到当前时间,这可能会符合您的喜好。 (负面结果是逻辑上的差异)。

    【讨论】:

    • 是的,但我想要 unix 时间,即(自 1970-1-1 以来的秒数)。负数并不意味着错误的结果,但在这种情况下9999-12-311970-1-1 晚,所以如果没有溢出,我认为结果应该是正数。
    • 来自WikI Unix Time:“最大可表示时间是星期二 2038-01-19”。你有一个千年虫;-)
    • 我不使用原来的 32 位 unix 时间
    • 如果您的库支持 64 位(它似乎支持 64 位,因为否则它会引发 bad_year 异常),那么我在您的代码中看不到任何错误:您从小数中减去大数,结果为负数。 10 - 100 = -90
    • 据我了解,9999-12-311970-1-1 更大。那么这将是 bigNumber-smallerNumber 的减法,应该是正数?!
    【解决方案4】:

    如果你有 C++11,也许 &lt;chrono&gt; 加上这个扩展 &lt;chrono&gt;free open source date library 会有所帮助吗?

    #include "date.h"
    #include <iostream>
    
    int
    main()
    {
        using namespace date::literals;
        auto time1 = 9999_y/dec/31;
        auto epoch = 1970_y/jan/1;
        std::chrono::seconds diff = date::sys_days{time1} - date::sys_days{epoch};
        std::cout << "A: " << time1 << '\n';
        std::cout << "B: " << epoch << '\n';
        std::cout << "C: " << diff.count() << '\n';
    }
    

    输出:

    A: 9999-12-31
    B: 1970-01-01
    C: 253402214400
    

    【讨论】:

    • 这个库可以处理纳秒精度吗?
    • @user2071938:是和不是。 &lt;chrono&gt; 有一个名为 nanoseconds 的类型,它存储在 int64_t 中。这给了它一个 +/- 292 年的范围,对于这个例子来说范围不够。如果您有 128 位类型,则可以创建自己的纳秒类型:using nanoseconds = std::chrono::duration&lt;__int128_t, std::nano&gt;;。对于您的示例,这将具有足够的范围。
    • 在我的系统上__int128_t 很难使用。例如,您不能将其流式传输到 cout
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多