【问题标题】:Does Howard Hinnant's date::parse() function work with floating-point durations?Howard Hinnant 的 date::parse() 函数是否适用于浮点持续时间?
【发布时间】:2020-07-21 10:15:32
【问题描述】:

我正在尝试使用 Howard Hinnant 的 Date 库将 2020-03-25T08:27:12.828Z 解析为 std::chrono::time_point<system_clock, duration<double>>

预计以下代码会输出两个相同的字符串:

#include "date.h"
#include <chrono>
#include <string>
#include <iostream>

using namespace std;
using namespace std::chrono;
using namespace date;

int main() {
  double d = 1585124832.828;

  time_point<system_clock, duration<double>> t{duration<double>{d}}, t1;

  string s {format("%FT%TZ", t) };
  cout << s << "\n";

  stringstream ss {s};
  ss >> parse("%FT%TZ", t1);
  cout << format("%FT%TZ", t1) << "\n";

}

但我明白了:

2020-03-25T08:27:12.828000Z
1970-01-01T00:00:00.000000Z

当我声明tt1 如下:

time_point<system_clock, milliseconds> t{duration_cast<milliseconds>(duration<double>{d})}, t1;

代码按预期工作,即输出两条相同的行

【问题讨论】:

    标签: datetime c++11 chrono


    【解决方案1】:

    可以解析浮点数,但你真的不想这样做。建议您使用milliseconds 进行修复。

    解释:

    当您格式化双精度秒时,它使用fixed 格式,默认为 6 位小数。这就是为什么您会在 .828 之后看到 3 个尾随零。

    在解析时,预期精度由输入类型的精度驱动,即使 rep 是浮点数。所以duration&lt;double&gt; 它只解析秒的组成部分。然后它开始寻找尾随的Z 并找到.。这会导致解析失败。如果解析字符串中没有Z,它不会失败,但它也不会解析秒的小数部分。

    如果您将time_point 更改为双基microseconds,那么它会再次起作用:

    time_point<system_clock, duration<double, micro>> t{duration<double>{d}}, t1;
    

    但我认为这种方式过于神秘和微妙,它还有一个你还没有遇到的问题:在 C++17 中,round 由供应商提供为std::chrono::round,它用于parse 的引擎盖。而 round 的 C++17 版本不允许目标 duration 具有浮点 rep。因此,您的代码甚至无法在 C++17 或更高版本中编译。

    使用基于整数的milliseconds 避免了解析浮点值的所有这些复杂性。如果您愿意,您仍然可以将结果转换回duration&lt;double&gt;

    一个微妙的建议:

    time_point<system_clock, milliseconds> t{round<milliseconds>(duration<double>{d})}, t1;
    

    在将基于浮点的reps 转换为基于整数的reps 时,我喜欢使用round 而不是duration_cast。当底层double完全 表示所需值并且duration_cast 在错误的方向(接近零)截断时,这可以避免一个错误。 round 将向最接近的可表示值四舍五入。

    上面可以用date::sys_time模板化类型别名进一步简化:

    sys_time<milliseconds> t{round<milliseconds>(duration<double>{d})}, t1;
    

    上面是完全等价的。 sys_time&lt;duration&gt;time_point&lt;system_clock, duration&gt; 的类型别名。在 C++20 中,它通过新的 CTAD 规则进一步简化:

    sys_time t{round<milliseconds>(duration<double>{d})};
    

    &lt;milliseconds&gt; 是从参数的类型推导出来的 (C++20)。虽然你必须单独声明t1,或者给t1一个milliseconds初始值(例如, t1{0ms};)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-07-07
      • 1970-01-01
      • 2014-08-27
      • 1970-01-01
      • 1970-01-01
      • 2013-10-14
      • 1970-01-01
      相关资源
      最近更新 更多