【问题标题】:Limitations on C++ chrono library?C++ chrono 库的限制?
【发布时间】:2020-05-07 10:57:39
【问题描述】:

我从一个更大的项目中提取了以下简单代码。我试图通过提取日、月、年来模拟期货日期。 我正在使用 std::chrono 库。过了一定天数(我的电脑上大约 8835 天),日期就出错了。 我已经尝试过:

  • 使用 g++ 优化标志
  • 使用 valgrind 启动
  • 寻找有关限制的计时文档

你能重现这种行为吗?

// COMPILE OK && RUN KO (wandbox)
// g++ prog.cc -O2 -march=native -std=c++11

// COMPILE OK && RUN OK (wandbox)
// clang++ prog.cc -Wall -Wextra -std=c++11

#include <iostream>
#include <chrono>

using namespace std;

int main(int ac, char* av[])
{
  (void) ac; (void) av;
  auto faketime = chrono::system_clock::now();

  for( int i=0; i<100000; ++i) {
    // doDaily();
    faketime += chrono::hours(24);
    time_t ftime = chrono::system_clock::to_time_t(faketime);
    if( i% 1000 == 0)
         cout << "faketime (" << ftime << ") is : " << ctime(&ftime) << endl;
  } 
  auto currtime = chrono::system_clock::now();
  time_t cutime = chrono::system_clock::to_time_t(currtime);
  cout << "currtime is : " << ctime(&cutime);
  return 0;
} 

RESULT(第三行出错):

[...]
faketime (9105738161) is : Tue Jul 20 20:42:41 2258
faketime (9192138161) is : Mon Apr 15 20:42:41 2261
faketime (-9168205912) is : Wed Jun 21 21:27:07 1679
faketime (-9081805912) is : Tue Mar 17 21:27:07 1682
faketime (-8995405912) is : Mon Dec 11 21:27:07 1684
currtime is : Thu May  7 12:48:56 2020

已编辑:

  • 在哪里出错了。
  • 我已经在https://wandbox.org/ 上测试了这段代码:我可以用 gcc 11 重现这个问题,但它可以在 clang++ 上正常工作
  • 似乎存在限制,但只能使用 g++ 编译。

【问题讨论】:

  • 输出有什么问题?我猜是年份,但可能更清楚
  • time_t 是整数秒。
  • 请注意,您有 2 个限制要检查、chrono 和 ctime/time_t。
  • 您是否尝试过打印您的time_t 的整数值?您是否尝试过使用 C++20 formatter 而不是首先转换为 time_t?显示的日期与 32 位 UNIX 纪元溢出不对应,因此值得仔细检查转换是否有损耗。
  • 大家好,感谢您的回答。好吧,我想这就是我将开始下一次调查的地方:bug 这正是我现在所面临的。它没有解释为什么 clang++ 能够处理这个错误......

标签: c++ datetime chrono


【解决方案1】:

您在system_clock::time_point 中遇到溢出。

system_clock::time_point 的精度因平台而异:

  • gcc:纳秒
  • Windows:1/10 微秒
  • clang/libc++:微秒

表示在所有三个平台上都是相同的:有符号的 64 位整数。而这一切都符合要求。

64 有符号位的纳秒为您提供大约 +/-292 年的范围。对于system_clock,此范围以 1970-01-01 为中心。所以2262年溢出是正常的。

如果您需要更大的范围,可以降低精度。例如:

auto faketime = chrono::time_point_cast<chrono::microseconds>(chrono::system_clock::now());

可以使用time_point 静态成员函数min()max() 以编程方式检查time_point 的限制。

更新

微秒的范围约为 +/-292 年。我不确定ctime 的范围是多少,但如果它可以格式化过去/未来的日期,我会感到惊讶。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-02
    • 1970-01-01
    • 2017-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多