【问题标题】:How to convert std::chrono::time_point to string如何将 std::chrono::time_point 转换为字符串
【发布时间】:2016-04-23 18:21:55
【问题描述】:

如何将std::chrono::time_point 转换为字符串? 例如:"201601161125"

【问题讨论】:

  • 您是否尝试过将其插入std::stringstream,然后使用stringstream的成员函数.str()将其转换为字符串?
  • 不,我没有。我会去做。如果您的提示有效,我会通知您。
  • 参见:howardhinnant.github.io/date_v2.html“日期时间类型怎么样?”部分

标签: c++11 chrono


【解决方案1】:

Howard Hinnant's free, open source, header-only, portable date/time library 是一种现代方法,它不会通过旧的 C API 进行通信,并且不需要您丢弃所有亚秒级信息。这个库也是proposed for standardization

格式有很大的灵活性。最简单的方法就是直接流出:

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

int
main()
{
    using namespace date;
    std::cout << std::chrono::system_clock::now() << '\n';
}

这只是为我输出:

2017-09-15 13:11:34.356648

需要using namespace date; 才能找到system_clock::time_point 的流操作符(我的lib 将其插入namespace std::chrono 是不合法的)。这种格式不会丢失任何信息:您的 system_clock::time_point 的完整精度将被输出(microseconds 我在 macOS 上运行它)。

完整的strftime-like formatting flags 套件可用于其他格式,并带有小的扩展来处理小数秒等问题。这是另一个以毫秒精度输出的示例:

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

int
main()
{
    using namespace date;
    using namespace std::chrono;
    std::cout << format("%D %T %Z\n", floor<milliseconds>(system_clock::now()));
}

这只是为我输出:

09/15/17 13:17:40.466 UTC

【讨论】:

  • 我觉得这里的例子最好不要using namespace whatever,这样更清楚哪些函数和类型来自哪个命名空间。
  • 其中一个问题是命名空间随着时间而变化:floor 在命名空间 date 中,但从 C++17 开始在命名空间 std::chrono 中。到 C++20 时,一切都将在 std::chrono 中。
  • @HowardHinnant 是否有一种简单的方法可以在date::format("%FT%TZ", p) 生成的字符串的亚秒部分中丢弃尾随零(以及.,如果需要),其中psystem_clock::time_point
  • 控制输出精度的最佳方式是将输入的精度截断为format,如上例中截断为milliseconds。在运行时没有自动检测尾随零的方法。这样做的唯一方法是对生成的字符串进行自定义后处理(反向搜索零)。
【解决方案2】:

最灵活的方法是将其转换为struct tm,然后使用strftime(时间类似于sprintf)。比如:

std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t now_c = std::chrono::system_clock::to_time_t(now);
std::tm now_tm = *std::localtime(&now_c);
/// now you can format the string as you like with `strftime`

查找 strftime here 的文档。

如果您有localtime_slocaltime_r 可用,则应优先使用localtime

还有许多其他方法可以做到这一点,但是,虽然大多数情况下更容易使用,但这些方法会产生一些预定义的字符串表示。您可以将上述所有内容“隐藏”在一个函数中以方便使用。

【讨论】:

  • 为什么这比使用 Hinnant 先生的图书馆更好?
  • 先生。 Hinnant 的库还不是 C++ 标准的一部分,而 strftime() 长期以来一直是 C 标准的一部分。似乎在 C++20 中,Hinnant 先生的库将成为 C++ 标准的一部分——当这种情况发生时,很难做出坚定的偏好(这将取决于您的需求和经验)。
  • 本地时间不是线程安全的!
【解决方案3】:

代码解决方案

以下函数将chrono time_point 转换为字符串(序列化)。

#include <chrono>
#include <iomanip>
#include <sstream>

using time_point = std::chrono::system_clock::time_point;
std::string serializeTimePoint( const time_point& time, const std::string& format)
{
    std::time_t tt = std::chrono::system_clock::to_time_t(time);
    std::tm tm = *std::gmtime(&tt); //GMT (UTC)
    //std::tm tm = *std::localtime(&tt); //Locale time-zone, usually UTC by default.
    std::stringstream ss;
    ss << std::put_time( &tm, format.c_str() );
    return ss.str();
}

// example
int main()
{
    time_point input = std::chrono::system_clock::now();
    std::cout << serializeTimePoint(input, "UTC: %Y-%m-%d %H:%M:%S") << std::endl;

}

时区

time_point 数据类型没有时区的内部表示,因此,时区通过转换为 std::tm(通过函数 gmtimelocaltime)聚合。不建议从输入中添加/减去时区,因为%Z 会显示不正确的时区,因此,最好设置正确的本地时间(取决于操作系统)并使用@987654329 @。

技术与用户友好的序列化

对于技术用途,硬编码时间格式是一个很好的解决方案。但是,要向用户显示,应该使用locale 来检索用户偏好并以该格式显示时间戳。

C++20

从 C++20 开始,我们为 time_point 和 duration 提供了很好的序列化和解析函数。

  • std::chrono::to_stream
  • std::chrono::format

【讨论】:

  • 您从文字创建 std::string 然后从中获取 c_str() => 引擎盖下的冗余 malloc。有 std::string_view 用于此类目的。
  • 正确,如果你有C++17的权限,你可以用std::string_view优化这段代码,否则const char*也是可能的。
猜你喜欢
  • 1970-01-01
  • 2020-05-30
  • 1970-01-01
  • 2018-07-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-08
相关资源
最近更新 更多