C++20 std::chrono::duration 格式化的缺点
Drawbacks of C++20 std::chrono::duration formatting
我需要以易于阅读的方式打印可能大于 24 小时的 std::chrono::duration
,例如 "2 d. 09:10:11"
。
C++20 的 std::chrono::time_point
和 std::chrono::duration
formatting (based on Howard Hinnant's date library) 包含大量有用的格式说明符,但在 std::chrono::duration
中没有用于天数的说明符。最接近的是 %j
但它用零填充它。也没有说明一天中的小时数。最接近的是 %H
(但它也包括整天的小时数)和 %OH
(但它在断言小时数小于 24 时崩溃)。
我是不是漏掉了什么?
向 C++20 的 std::format
添加更多说明符是否有意义?
到目前为止我正在使用 workaround function:
#include <chrono>
#include <cstring> // std::strncmp
#include <date.h> // use Howard Hinnant's date library until C++20 is supported by compilers
#include <string>
// Workaround for C++20 std::chrono::format's inability to produce number of days in std::chrono::duration.
// Temporary format specifier for this is `%J`. It must be in the beginning of the format string.
template<typename Rep, typename Period>
std::string duration_to_str(const char* format, const std::chrono::duration<Rep, Period>& duration)
{
if (std::strncmp(format, "%J", 2))
return date::format(format, duration);
static const auto one_day = std::chrono::hours(24);
const size_t days = std::chrono::duration_cast<std::chrono::hours>(duration).count() / 24;
return std::to_string(days) + date::format(format + 2, duration - days * one_day);
}
测试:
#include <iostream>
template<typename Rep, typename Period>
void test_dur_to_str(const std::chrono::duration<Rep, Period>& duration)
{
std::cout << duration_to_str("%T", duration) << ":\n"
<< duration_to_str("%j d. %T", duration) << '\n'
<< duration_to_str("%J d. %T", duration) << "\n\n";
}
int main()
{
test_dur_to_str(std::chrono::seconds(24 * 60 * 60 - 1));
test_dur_to_str(std::chrono::seconds(24 * 60 * 60));
test_dur_to_str(std::chrono::seconds(91297));
test_dur_to_str(std::chrono::seconds(2 * 24 * 60 * 60 - 1));
test_dur_to_str(std::chrono::seconds(2 * 24 * 60 * 60));
test_dur_to_str(std::chrono::seconds(2 * 24 * 60 * 60 + 1));
test_dur_to_str(std::chrono::seconds(13 * 24 * 60 * 60 + 5));
test_dur_to_str(std::chrono::seconds(365 * 24 * 60 * 60 + 5));
test_dur_to_str(std::chrono::seconds(366 * 24 * 60 * 60 + 5));
test_dur_to_str(std::chrono::seconds(367 * 24 * 60 * 60 + 5));
}
输出:
23:59:59:
000 d. 23:59:59
0 d. 23:59:59
24:00:00:
001 d. 24:00:00
1 d. 00:00:00
25:21:37:
001 d. 25:21:37
1 d. 01:21:37
47:59:59:
001 d. 47:59:59
1 d. 23:59:59
48:00:00:
002 d. 48:00:00
2 d. 00:00:00
48:00:01:
002 d. 48:00:01
2 d. 00:00:01
312:00:05:
013 d. 312:00:05
13 d. 00:00:05
8760:00:05:
365 d. 8760:00:05
365 d. 00:00:05
8784:00:05:
366 d. 8784:00:05
366 d. 00:00:05
8808:00:05:
367 d. 8808:00:05
367 d. 00:00:05
你可以做一个 duration_cast
到 std::chrono::days
:
template<typename Rep, typename Period>
std::string duration_to_str(const char* format, const std::chrono::duration<Rep, Period>& duration)
{
if (std::strncmp(format, "%J", 2))
return date::format(format, duration);
auto num_days = std::chrono::duration_cast<date::days>(duration);
return std::to_string(num_days.count()) + date::format(format + 2, duration - num_days);
}
至于为什么不存在,chrono
的date/time格式化的目的是格式化日期和时间。日期格式生成年份和该年的天数是一种类似日期的操作。日期格式生成年、月和该月的天数也是一种类似日期的操作。然而,持续时间内的天数并不是真正的类似日期的格式化操作。
这与获取持续时间内的小时数与获取持续时间包含的 24 小时时间之间的区别是一回事。前者是在不考虑任何时间背景的情况下完成的;您只是在持续时间内获得小时数。 that 也没有格式字段。
我想展示 simplified version 解决方法功能,正如 Howard Hinnant 在他的评论中所建议的那样,对于那些可能觉得它有用的人:
#include <chrono>
#include <cstring> // std::strncmp
#include <date.h> // use Howard Hinnant's date library until C++20 is supported by compilers
#include <string>
template<typename Rep, typename Period>
std::string duration_to_str(const char* format, const std::chrono::duration<Rep, Period>& duration)
{
if (std::strncmp(format, "%J", 2))
return date::format(format, duration);
const auto days = std::chrono::duration_cast<date::days>(duration);
return std::to_string(days.count()) + date::format(format + 2, duration - days);
}
我需要以易于阅读的方式打印可能大于 24 小时的 std::chrono::duration
,例如 "2 d. 09:10:11"
。
C++20 的 std::chrono::time_point
和 std::chrono::duration
formatting (based on Howard Hinnant's date library) 包含大量有用的格式说明符,但在 std::chrono::duration
中没有用于天数的说明符。最接近的是 %j
但它用零填充它。也没有说明一天中的小时数。最接近的是 %H
(但它也包括整天的小时数)和 %OH
(但它在断言小时数小于 24 时崩溃)。
我是不是漏掉了什么?
向 C++20 的 std::format
添加更多说明符是否有意义?
到目前为止我正在使用 workaround function:
#include <chrono>
#include <cstring> // std::strncmp
#include <date.h> // use Howard Hinnant's date library until C++20 is supported by compilers
#include <string>
// Workaround for C++20 std::chrono::format's inability to produce number of days in std::chrono::duration.
// Temporary format specifier for this is `%J`. It must be in the beginning of the format string.
template<typename Rep, typename Period>
std::string duration_to_str(const char* format, const std::chrono::duration<Rep, Period>& duration)
{
if (std::strncmp(format, "%J", 2))
return date::format(format, duration);
static const auto one_day = std::chrono::hours(24);
const size_t days = std::chrono::duration_cast<std::chrono::hours>(duration).count() / 24;
return std::to_string(days) + date::format(format + 2, duration - days * one_day);
}
测试:
#include <iostream>
template<typename Rep, typename Period>
void test_dur_to_str(const std::chrono::duration<Rep, Period>& duration)
{
std::cout << duration_to_str("%T", duration) << ":\n"
<< duration_to_str("%j d. %T", duration) << '\n'
<< duration_to_str("%J d. %T", duration) << "\n\n";
}
int main()
{
test_dur_to_str(std::chrono::seconds(24 * 60 * 60 - 1));
test_dur_to_str(std::chrono::seconds(24 * 60 * 60));
test_dur_to_str(std::chrono::seconds(91297));
test_dur_to_str(std::chrono::seconds(2 * 24 * 60 * 60 - 1));
test_dur_to_str(std::chrono::seconds(2 * 24 * 60 * 60));
test_dur_to_str(std::chrono::seconds(2 * 24 * 60 * 60 + 1));
test_dur_to_str(std::chrono::seconds(13 * 24 * 60 * 60 + 5));
test_dur_to_str(std::chrono::seconds(365 * 24 * 60 * 60 + 5));
test_dur_to_str(std::chrono::seconds(366 * 24 * 60 * 60 + 5));
test_dur_to_str(std::chrono::seconds(367 * 24 * 60 * 60 + 5));
}
输出:
23:59:59:
000 d. 23:59:59
0 d. 23:59:59
24:00:00:
001 d. 24:00:00
1 d. 00:00:00
25:21:37:
001 d. 25:21:37
1 d. 01:21:37
47:59:59:
001 d. 47:59:59
1 d. 23:59:59
48:00:00:
002 d. 48:00:00
2 d. 00:00:00
48:00:01:
002 d. 48:00:01
2 d. 00:00:01
312:00:05:
013 d. 312:00:05
13 d. 00:00:05
8760:00:05:
365 d. 8760:00:05
365 d. 00:00:05
8784:00:05:
366 d. 8784:00:05
366 d. 00:00:05
8808:00:05:
367 d. 8808:00:05
367 d. 00:00:05
你可以做一个 duration_cast
到 std::chrono::days
:
template<typename Rep, typename Period>
std::string duration_to_str(const char* format, const std::chrono::duration<Rep, Period>& duration)
{
if (std::strncmp(format, "%J", 2))
return date::format(format, duration);
auto num_days = std::chrono::duration_cast<date::days>(duration);
return std::to_string(num_days.count()) + date::format(format + 2, duration - num_days);
}
至于为什么不存在,chrono
的date/time格式化的目的是格式化日期和时间。日期格式生成年份和该年的天数是一种类似日期的操作。日期格式生成年、月和该月的天数也是一种类似日期的操作。然而,持续时间内的天数并不是真正的类似日期的格式化操作。
这与获取持续时间内的小时数与获取持续时间包含的 24 小时时间之间的区别是一回事。前者是在不考虑任何时间背景的情况下完成的;您只是在持续时间内获得小时数。 that 也没有格式字段。
我想展示 simplified version 解决方法功能,正如 Howard Hinnant 在他的评论中所建议的那样,对于那些可能觉得它有用的人:
#include <chrono>
#include <cstring> // std::strncmp
#include <date.h> // use Howard Hinnant's date library until C++20 is supported by compilers
#include <string>
template<typename Rep, typename Period>
std::string duration_to_str(const char* format, const std::chrono::duration<Rep, Period>& duration)
{
if (std::strncmp(format, "%J", 2))
return date::format(format, duration);
const auto days = std::chrono::duration_cast<date::days>(duration);
return std::to_string(days.count()) + date::format(format + 2, duration - days);
}