使用 std: : chrono 在 C + + 中输出日期和时间

我一直在升级一些旧代码,并试图在可能的情况下升级到 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 (或类似的)以类似的格式输出当前的时间和日期,但不确定如何这样做。如果你能帮忙,我将不胜感激。谢谢

136738 次浏览

The <chrono> library only deals with time and not dates, except for the system_clock which has the ability to convert its timepoints to time_t. So using <chrono> for dates will not improve things much. Hopefully we get something like chrono::date in the not too distant future.

That said, you can use <chrono> in the following way:

#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();
}

Note that std::localtime may cause data races. localtime_r or similar functions may be available on your platforms.

Update:

Using a new version of Howard Hinnant's date library you can write:

#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();
}

This will print out something like "2015-07-24 05:15:34.043473124 UTC".


On an unrelated note, returning const objects has become undesirable with C++11; const return values cannot be moved from. I also removed the trailing const because trailing const is only valid for member functions and this function has no need to be a member.

You can improve the answer from @bames53 by using Boost lexical_cast instead of string stream manipulations.

Here is what I do:

#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"));
}

bames53 solutions are good, but do not compile on my VS2017. The solution with ctime does not compile because localtime is very deprecated. The one with date.h does not compile with the current date.h I just took off github even though the documentation says they should, because today cannot be streamed as is. I omitted the includes but here is code that works:

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

Feel free to fix bames53 solution and delete mine. My text just won't fit in a comment. I'm sure it can save many people from grief.

An example:

#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;


}

Output as below:

enter image description here

For getting also milliseconds, I use chrono and C function localtime_r which is thread-safe (in opposition to 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(&currentTime, &currentLocalTime);
char timeBuffer[80];
std::size_t charCount { std::strftime( timeBuffer, 80,
"%D %T",
&currentLocalTime)
};


if (charCount == 0) return -1;


std::cout << timeBuffer << "." << std::setfill('0') << std::setw(3) << now2.count() % 1000 << std::endl;
return 0;
}

For format: http://www.cplusplus.com/reference/ctime/strftime/

The fmt library has the ability to format tm structures: it has the same spec as 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);
}

Here's a C++20 solution:

#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 converts a system clock time point (std::chrono::time_point<std::chrono::system_clock, TDuration>) to a local time point (std::chrono::local_time<TDuration>). This local time point can then be formatted using std::format with formatting options similar to strftime.

Currently, only MSVC has implemented std::format. The calendar and timezone additions to chrono
are currently "partially" implemented by Clang and GCC, but check here for the updated status: https://en.cppreference.com/w/cpp/compiler_support. For more information about the chrono library, read here: https://en.cppreference.com/w/cpp/chrono.

Although correct answers were already given, I decided to implement one more solution that outputs also fractional part of second.

You may notice in my code that sometimes I subtract one second from time_t value, - std::chrono::seconds(1), it is because according to documentation to_time_t() may round value instead of truncating (according to doc "If std::time_t has lower precision, it is implementation-defined whether the value is rounded or truncated"), hence I have to subtract 1 second to make it truncated time.

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;
}

Example Output:

2021-12-02 04:10:51.876

As suggested by @AndyK, starting from C++20 you can use std::chrono::current_zone() and its method to_local(), they return std::chrono::local_time which is directly convertible to your desired string format by outputting to std::ostringstream or through std::format(). Whole function becomes very short:

#include <chrono>
#include <string>
#include <sstream>
#include <iostream>


std::string CurrentTimeStr() {
return (std::ostringstream{} << std::chrono::current_zone()->to_local(
std::chrono::system_clock::now())).str().substr(0, 23);
}


int main() {
std::cout << CurrentTimeStr() << std::endl;
}

But right now not all compilers support this current_zone() function, online GodBolt servers failed to compile it on trunk CLang and GCC, but MSVC compiles it well. Although my local laptop installation of CLang compiled it too.