The chrono
library, introduced in C++20, provides support for calendars, time zones, and i/o formatting and parsing operations on
time-related objects.
chrono
is a better alternative to the C/POSIX functions that operate on time_t
, tm
, or timespec
types. In comparison to C facilities, it provides better integration with other components of the C++ standard library (iostreams
and
format
). Also, it supports compile-time computation and it is thread-safe.
This rule raises an issue C/POSIX functions that can be replaced with one of the std::chrono
components:
- querying for current time (
time
, timespec_get
, clock_gettime
)
- date to time-point conversion (
mktime
, gmtime
, localtime
)
- time serialization (
ctime
, asctime
, strftime
)
- time parsing (
strptime
)
Noncompliant code example
int currentMonth() {
std::time_t tp;
std::time(&tp);
std::tm* date = std::gmtime(&tp);
return date->tm_mon + 1;
}
std::chrono::system_clock::time_point makeSomeDay() {
// Creates time_point corresponding to 2020-09-04
std::tm date{};
date.tm_year = 120;
date.tm_mon = 8;
date.tm_mday = 4;
std::time_t t = std::mktime(&date); // Noncompliant
return std::chrono::system_clock::from_time_t(t);
}
std::optional<int> yearOfTimePoint(std::chrono::system_clock::time_point tp) {
std::time_t t = std::chrono::system_clock::to_time_t(tp);
std::tm* date = std::gmtime(&t); // Noncompliant
if (!date)
return std::nullopt;
return date->tm_year + 1900;
}
std::string toString(std::chrono::system_clock::time_point tp) {
std::time_t t = std::chrono::system_clock::to_time_t(tp);
std::tm* date = std::gmtime(&t); // Noncompliant
if (!date)
throw InvalidDate();
std::string buffer(100, ' ');
std::size_t written = std::strftime(&buffer[0], buffer.size(), "%A %c", date);
buffer.resize(written);
return buffer;
}
std::string toFrenchString(std::chrono::system_clock::time_point tp) {
auto oldLocale = std::locale::global(std::locale("fr_FR.UTF-8"));
std::string result = toString(tp);
std::locale::global(oldLocale);
return result;
}
Compliant solution
std::chrono::month currentMonth() {
using namespace std::chrono;
auto dp = floor<days>(system_clock::now());
return year_month_day(dp).month();
}
std::chrono::system_clock::time_point makeSomeDay() {
using namespace std::chrono;
return sys_days(2020y/September/4);
}
std::optional<std::chrono::year> yearOfTimePoint(std::chrono::system_clock::time_point tp) {
using namespace std::chrono;
year_month_day date(floor<days>(tp));
if (!date.ok())
return std::nullopt;
return date.year();
}
std::string toString(std::chrono::system_clock::time_point tp) {
return std::format("{:%A %c}", tp); // Or "{:L%A %c}" if you want to use the global locale
}
std::string toFrenchString(std::chrono::system_clock::time_point tp) {
return std::format(std::locale("fr_FR.UTF-8"), "{:L%A %c}", tp);
}