Chameleon
Chameleon

Reputation: 2137

Current time and date in C++20 days

I fast read the C++ reference about new chrono classes but I found them a little bit complicated.

So, the question is, how to re-write this code in C++20, to get year, month, day, hour, minute, second?

Are there any changes? I ask because of this minor problem with std::localtime: It is thread-unsafe. tm will be destroyed after next call to std::localtime.

std::time_t t = std::time(nullptr);
std::tm *tm = std::localtime(&t);
int year = tm->tm_year + 1900;
int month = tm->tm_mon + 1;
int day = tm->tm_mday;
int hour = tm->tm_hour;
int minute = tm->tm_min;
int second = tm->tm_sec;

Upvotes: 5

Views: 2733

Answers (1)

Howard Hinnant
Howard Hinnant

Reputation: 218750

#include <chrono>

int
main()
{
    using namespace std::chrono;

    // Get a local time_point with system_clock::duration precision
    auto now = zoned_time{current_zone(), system_clock::now()}.get_local_time();

    // Get a local time_point with days precision
    auto ld = floor<days>(now);

    // Convert local days-precision time_point to a local {y, m, d} calendar
    year_month_day ymd{ld};

    // Split time since local midnight into {h, m, s, subseconds}
    hh_mm_ss hms{now - ld};

    // This part not recommended.  Stay within the chrono type system.
    int year{ymd.year()};
    int month = unsigned{ymd.month()};
    int day = unsigned{ymd.day()};
    int hour = hms.hours().count();
    int minute = hms.minutes().count();
    int second = hms.seconds().count();
}

I've tried to explain what each line of code does with a comment. I'm happy to elaborate further if anything is not clear.

This is all threadsafe.

More information:

Another and perhaps even more concise way to compute now is:

auto now = current_zone()->to_local(system_clock::now());

This results in the exact same type and value for now.

I used zoned_time above because it is (in general) a higher-level abstraction than calling member functions of a time_zone directly. In both examples the type of now is a simple std::chrono::time_point that is offset from system_clock::time_point by the UTC offset associated with the time_zone at this point in time.

In contrast zoned_time carries much more information. For example it knows about:

  • The name of the time_zone.
  • The abbreviation for the time_zone at this point in time.
  • The UTC offset of the time_zone at this point in time, and subsequently can produce both the local time and the UTC equivalent time.
  • The valid range of the offset/abbreviation pair.

Therefore a zoned_time is much more flexible for jobs like formatting as it can display the abbreviation and/or the UTC offset. And a zoned_time can also be more easily used to find out the equivalent time in other time zones.

Nevertheless, all of that extra information isn't actually used in this simple example, and is thus why I'm exposing the alternative of calling the to_local() member function of time_zone directly.

For the simple case of finding the local time, both techniques have identical behavior and performance, so it comes down to a matter of readability for choosing the preferred approach.

Upvotes: 8

Related Questions