使用 std::chrono 在 C++ 中输出日期和时间
Posted
技术标签:
【中文标题】使用 std::chrono 在 C++ 中输出日期和时间【英文标题】:Outputting Date and Time in C++ using std::chrono 【发布时间】:2021-12-08 19:20:46 【问题描述】:我一直在升级一些旧代码,并在可能的情况下尝试更新到 c++11。以下代码是我用来在程序中显示时间和日期的方式
#include <iostream>
#include <string>
#include <stdio.h>
#include <time.h>
const std::string return_current_time_and_date() const
time_t now = time(0);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime(buf, sizeof(buf), "%Y-%m-%d %X", &tstruct);
return buf;
我想使用 std::chrono(或类似的)以类似的格式输出当前时间和日期,但我不确定如何去做。任何帮助将不胜感激。谢谢
【问题讨论】:
如果已经有这样的问题,请查找,如果没有,请查询。 可能重复: ***.com/questions/12346260/c-date-and-time C++11 不会让你变得更好。 chrono 更多的是关于时间(某件事花了多长时间)而不是时间类型的东西。不过,您可以查看 Boost Date Time。它具有更强大的日期和时间功能。 使用计时和输出获取日期和时间?请参阅first example。 @DyP 这看起来很有希望,但我需要从函数中返回一个字符串,并且不知道如何使用 std::put_time 进行此操作 【参考方案1】:<chrono>
库只处理时间而不是日期,但 system_clock
除外,它能够将其时间点转换为 time_t
。所以使用<chrono>
日期不会有太大改善。希望我们在不久的将来能得到类似chrono::date
的东西。
也就是说,您可以通过以下方式使用<chrono>
:
#include <chrono> // chrono::system_clock
#include <ctime> // localtime
#include <sstream> // stringstream
#include <iomanip> // put_time
#include <string> // string
std::string return_current_time_and_date()
auto now = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X");
return ss.str();
请注意,std::localtime
可能会导致数据争用。 localtime_r
或类似功能可能在您的平台上可用。
更新:
使用新版 Howard Hinnant 的 date library 你可以这样写:
#include "date.h"
#include <chrono>
#include <string>
#include <sstream>
std::string return_current_time_and_date()
auto now = std::chrono::system_clock::now();
auto today = date::floor<days>(now);
std::stringstream ss;
ss << today << ' ' << date::make_time(now - today) << " UTC";
return ss.str();
这将打印出类似“2015-07-24 05:15:34.043473124 UTC”的内容。
在一个不相关的注释中,返回 const
对象在 C++11 中变得不可取; const 返回值不能被移出。我还删除了尾随 const,因为尾随 const 仅对成员函数有效,并且此函数不需要成为成员。
【讨论】:
注意一些旧的编译器可能无法识别std::put_time
。一旦我尝试使用 g++ 在 CentOS 7 上编译具有 std::put_time
的代码,它就失败了。 GCC 中std::put_time
支持的状态***.com/q/14136833/4694036
有没有类似std::put_time但返回字符串的C++函数?
@Nick No. C 函数strftime
可以让你用 C 字符串填充缓冲区。已废弃的函数asctime
将返回一个固定时间格式的 C 字符串。
谢谢,我猜你可以用字符串流做 put_time
如果您不使用using namespace date;
,<< today
将不起作用。【参考方案2】:
一个例子:
#include <iostream>
#include <chrono>
#include <ctime>
std::string getTimeStr()
std::time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
std::string s(30, '\0');
std::strftime(&s[0], s.size(), "%Y-%m-%d %H:%M:%S", std::localtime(&now));
return s;
int main()
std::cout<<getTimeStr()<<std::endl;
return 0;
输出如下:
【讨论】:
不是线程安全的请参阅Data races 投反对票:当前答案返回一个 30 字符长的字符串,末尾有很多空字符。如果您尝试将某些内容连接到它,它将不起作用。我确实建议进行编辑以使其正常工作,但被 Django 程序员拒绝....【参考方案3】:这是一个 C++20 解决方案:
#include <chrono>
#include <format>
std::string get_current_time_and_date()
auto const time = std::chrono::current_zone()
->to_local(std::chrono::system_clock::now());
return std::format(":%Y-%m-%d %X", time);
std::chrono::time_zone::to_local
将系统时钟时间点 (std::chrono::time_point<std::chrono::system_clock, TDuration>
) 转换为本地时间点 (std::chrono::local_time<TDuration>
)。然后可以使用std::format
格式化这个本地时间点,格式化选项类似于strftime
。
目前,只有 MSVC 实现了std::format
。 chrono 中添加的日历和时区
目前由 Clang 和 GCC “部分”实现,但请在此处查看更新状态:https://en.cppreference.com/w/cpp/compiler_support。有关chrono
库的更多信息,请在此处阅读:https://en.cppreference.com/w/cpp/chrono。
【讨论】:
clang 或 gcc 是否实现了<chrono>
库的时区部分?即使我们从示例中删除std::format
,上面的代码是否可以在 Godbolt 或 Wandbox 中进行测试?
最简单的找出方法是……在 Godbolt 或 Wandbox 中测试它。
实际上,我想我可以将该信息添加到答案中以使其更完整。谢谢【参考方案4】:
为了获得毫秒,我使用了 chrono 和 C 函数 localtime_r,它是线程安全的(与 std::localtime 相反)。
#include <iostream>
#include <chrono>
#include <ctime>
#include <time.h>
#include <iomanip>
int main()
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
std::time_t currentTime = std::chrono::system_clock::to_time_t(now);
std::chrono::milliseconds now2 = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
struct tm currentLocalTime;
localtime_r(¤tTime, ¤tLocalTime);
char timeBuffer[80];
std::size_t charCount std::strftime( timeBuffer, 80,
"%D %T",
¤tLocalTime)
;
if (charCount == 0) return -1;
std::cout << timeBuffer << "." << std::setfill('0') << std::setw(3) << now2.count() % 1000 << std::endl;
return 0;
对于格式:http://www.cplusplus.com/reference/ctime/strftime/
【讨论】:
由于您已经在导入 iomanip,您可以跳过使用 std::put_time 而不是 std::strftime 创建自己的缓冲区。 您可能会出现半秒,因为to_time_t
可能会截断,但也可能会舍入。
您不必应用时钟类型模板参数吗? std::chrono::system_clock::time_point<system_clock> now = std::chrono::system_clock::now();
【参考方案5】:
bames53 解决方案不错,但是在我的 VS2017 上编译不了。使用 ctime 的解决方案无法编译,因为 localtime 非常不推荐使用。带有 date.h 的那个不与当前 date.h 一起编译,即使文档说应该这样做,我也刚刚离开了 github,因为今天不能按原样流式传输。我省略了包含,但这里是有效的代码:
void TimeTest()
auto n = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(n);
std::tm buf;
localtime_s(&buf, &in_time_t);
std::cout << std::put_time(&buf, "%Y-%m-%d %X") << std::endl;
// I just added date.h from this link's guthub to the project.
// https://howardhinnant.github.io/date/date.html
void TimeTest1()
auto now = std::chrono::system_clock::now();
auto today = floor<date::days>(std::chrono::system_clock::now());
std::cout << date::year_month_day today << ' ' << date::make_time(now - today) << std::endl;
// output is
// 2018-04-08 21:19:49
// 2018-04-08 18:19:49.8408289
随时修复 bames53 解决方案并删除我的解决方案。我的文字不适合评论。我相信它可以使许多人免于悲痛。
【讨论】:
如果您添加using date::operator<<;
,您可以流式传输today
,而无需将其转换为year_month_day
。
霍华德,非常感谢您编写和分享这个库。就这一点而言,我宁愿永远不要使用 using,因为在我的日子里,我已经饱受命名空间冲突的错误和歧义之苦。另外,如果我们要准确的话,我想指出第一个示例输出本地时间,而第二个示例输出通用时间。
很高兴能帮上忙。 usings
在函数范围内是一个很好的折衷方案,因为冲突发生时更容易控制。我意识到这并不完美,但对于 std::types 的流插入运算符来说,这是最好的,由 3rd 方库编写。但就在上个月,我说服 C++ 委员会将此流操作符放在 C++20 的 namespace std::chrono
中,以便 ADL 找到它。然后它将不再需要using
。
关于输出为 UTC 的良好观察。还提供了一个更高级别的库,它提供本地时间的操作。这可以是您计算机当前的本地时区,也可以是专门指定的时区(例如“America/New_York”)。这是documentation for the time zone library。
它在 C++20 中:eel.is/c++draft/time.clock.system.nonmembers#4 供应商正在实施它。【参考方案6】:
fmt 库能够格式化tm
结构:它与 strftime 具有相同的规范。
#include <ctime>
#include <fmt/chrono.h>
std::string current_datetime(void)
std::time_t tt = std::time(nullptr);
std::tm *tm = std::localtime(&tt);
return fmt::format(":%Y%m%d", *tm);
【讨论】:
【参考方案7】:您可以通过使用 Boost lexical_cast 而不是字符串流操作来改进来自 @bames53 的答案。
这是我的工作:
#include <boost/lexical_cast.hpp>
#include <ctime>
std::string return_current_time_and_date()
auto current_time = std::time(0);
return boost::lexical_cast<std::string>(std::put_time(std::gmtime(& current_time), "%Y-%m-%d %X"));
【讨论】:
还需要iomanip en.cppreference.com/w/cpp/io/manip/put_time【参考方案8】:虽然已经给出了正确的答案,但我决定再实施一种解决方案,该解决方案也输出秒的小数部分。
您可能会注意到,在我的代码中,有时我会从 time_t
值中减去一秒,- std::chrono::seconds(1)
,这是因为根据 documentation to_time_t()
可能会舍入值而不是截断(根据 doc “如果 std: :time_t 具有较低的精度,它是实现定义的值是舍入还是截断”),因此我必须减去 1 秒才能使其截断时间。
Try it online!
#include <chrono>
#include <string>
#include <sstream>
#include <iomanip>
std::string FormatTime(std::chrono::system_clock::time_point tp)
std::stringstream ss;
auto t = std::chrono::system_clock::to_time_t(tp);
auto tp2 = std::chrono::system_clock::from_time_t(t);
if (tp2 > tp)
t = std::chrono::system_clock::to_time_t(tp - std::chrono::seconds(1));
ss << std::put_time(std::localtime(&t), "%Y-%m-%d %T")
<< "." << std::setfill('0') << std::setw(3)
<< (std::chrono::duration_cast<std::chrono::milliseconds>(
tp.time_since_epoch()).count() % 1000);
return ss.str();
std::string CurrentTimeStr()
return FormatTime(std::chrono::system_clock::now());
#include <iostream>
int main()
std::cout << CurrentTimeStr() << std::endl;
示例输出:
2021-12-02 04:10:51.876
【讨论】:
以上是关于使用 std::chrono 在 C++ 中输出日期和时间的主要内容,如果未能解决你的问题,请参考以下文章
从 C++ 中的 std::chrono::time_point 中提取年/月/日等
如何从 C++ 中的 std::chrono::year_month_day 获取工作日编号