std::chrono::time_point
转换为字符串?
例如:"201601161125"
。std::chrono::time_point
转换为字符串?
例如:"201601161125"
。现在可以轻松地在 C++20 中完成此操作:
#include <chrono>
#include <format>
#include <iostream>
#include <string>
int
main()
{
using namespace std::chrono_literals;
std::chrono::time_point tp = std::chrono::sys_days{2016y/1/16} + 11h + 25min;
std::string s = std::format("{:%Y%m%d%H%M}", tp);
std::cout << s << '\n';
}
输出:
201601161125
Howard Hinnant的免费、开源、仅包含头文件、可移植的日期/时间库是一种现代化的方法,它不通过旧的C API传递数据,并且不需要丢弃所有的亚秒信息。这个库也正在提议标准化。
格式化有很多灵活性。最简单的方法就是直接输出:
#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
为了找到system_clock::time_point
的流操作符(我的库不能将其插入到namespace std::chrono
中),需要使用using namespace date;
。在这种格式下不会丢失任何信息:您的system_clock::time_point
的完整精度将被输出(我在macOS上运行时是microseconds
)。
其他格式可以使用完整的strftime
类似的格式标志,并进行轻微扩展以处理诸如小数秒之类的内容。以下是另一个示例,它以毫秒精度输出:
#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
,这样就更清楚哪些函数和类型来自哪个命名空间。 - einpoklumfloor
最初在名称空间date
中,但从C++17开始在名称空间std::chrono
中。到了C++20,所有内容都将在std::chrono
中。 - Howard Hinnantdate::format("%FT%TZ", p)
产生的字符串中亚秒部分末尾的零(和.
,如果需要)?其中p
是system_clock::time_point
。 - C.M.format
,例如上述示例中截断到毫秒
。在运行时没有自动检测尾随零的方法。唯一的方法是对生成的字符串进行自定义后处理(反向搜索零)。 - Howard Hinnant最灵活的方法是将其转换为struct tm
,然后使用strftime
(就像时间版的sprintf
)。类似这样:
最灵活的方法是将其转换为 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
的文档。
如果你有localtime_s
或者localtime_r
可用,你应该优先使用它们而不是localtime
。
还有许多其他方法来完成这个任务,但大多数情况下更容易使用的方法都会生成一些预定义的字符串表示。你可以将上述所有内容"隐藏"在一个函数中以方便使用。
struct tm
只有秒数,不包括任何更小的时间单位测量。 - srdjan.veljkovic以下函数将chrono
中的time_point转换为字符串(序列化)。
<code>#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;
}
</code>
时区
time_point
数据类型没有内部表示时区,因此,通过将其转换为 std::tm
(使用函数 gmtime
或 localtime
)来聚合时区。不建议从输入中加/减时区,因为这样会导致使用 %Z
显示错误的时区,因此最好设置正确的本地时间(依赖于操作系统)并使用 localtime()
。
技术与用户友好的序列化
对于技术用途,硬编码的时间格式是一个好的解决方案。然而,为了向用户显示,应该使用 locale
来检索用户偏好并以该格式显示时间戳。
C++20
自 C++20 起,我们拥有了很好的序列化和解析函数,用于 time_point 和 duration。
std::chrono::to_stream
std::chrono::format
std::string_view
来优化此代码,否则,const char*
也是一种可能性。 - Adrian Maire#include <chrono>
#include <iostream>
#include <iomanip>
#include <sstream>
using Clock = std::chrono::high_resolution_clock;
static std::string timePointToString(const Clock::time_point &tp, const std::string &format, bool withMs = true, bool utc = true)
{
const Clock::time_point::duration tt = tp.time_since_epoch();
const time_t durS = std::chrono::duration_cast<std::chrono::seconds>(tt).count();
std::ostringstream ss;
if (const std::tm *tm = (utc ? std::gmtime(&durS) : std::localtime(&durS))) {
ss << std::put_time(tm, format.c_str());
if (withMs) {
const long long durMs = std::chrono::duration_cast<std::chrono::milliseconds>(tt).count();
ss << std::setw(3) << std::setfill('0') << int(durMs - durS * 1000);
}
}
// gmtime/localtime() returned null ?
else {
ss << "<FORMAT ERROR>";
}
return ss.str();
}
int main() {
const auto tp = Clock::now();
std::cout << timePointToString(tp, "%Z %Y-%m-%d %H:%M:%S.") << std::endl;
return 0;
}
> GMT 2022-04-30 13:44:09.720
测试:https://www.mycompiler.io/view/43wsMbrMcmx
尽管它仅附加了毫秒,并且它们不是模板的一部分...但这将额外增加费用!
随着C++20的推出(正如Adrian Maire的回答中所提到的),这将变得更加容易。
#include <chrono>
#include <format>
#include <string>
#include <iostream>
int main()
{
auto t = std::chrono::system_clock::now();
std::string s = std::format("{0:%F %R %Z}", t);
std::cout << s << '\n';
return 0;
}
std::format
,但希望在新版本中很快能够实现。(你可以使用预处理宏__has_include(<format>)
和__cpp_lib_format
来检查。)"%F %T %Z"
)类似于strftime()
或者std::put_time()
(尽管我还没有检查它们之间的区别),并且在https://en.cppreference.com/w/cpp/chrono/system_clock/formatter有记录。
std::stringstream
中,然后使用stringstream的成员函数.str()
将其转换为字符串吗? - Ziezi