Search code examples
c++datec++20c++-chrono

C++ 20 chrono: How to compare time_point with month_day?


Is there a modern and elegant way to determine if the month and day in a time_point variable match a given month_day variable?

For example, I want to know if today is Christmas. I have the following code:

#include <chrono>

bool IsTodayChristmas()
{
    using namespace std::chrono;

    constexpr month_day Christmas = {December / 25};
    auto Now = system_clock::now();

    // return Now == Christmas; // How to?
}

Modern and elegant: I mean if possible, I would prefer not to use old C types (something like std::time_t and std::tm) and string comparisons (something like std::put_time).

Any help would be appreciated.


Solution

  • You can convert system_clock::now() to a std::chrono::year_month_day type via a std::chrono::sys_days. In practice this might look something like

    #include <chrono>
    
    bool IsTodayChristmas() {
        using namespace std::chrono;
    
        constexpr month_day Christmas = {December / 25};
        auto Now = year_month_day{floor<days>(system_clock::now())};
    
        // either
        return Now == Christmas / Now.year();
        // or
        return Now.month() / Now.day() == Christmas;
    }
    

    As Howard Hinnant pointed out, this will determine Christmas in UTC. You're more likely to be after Christmas in the local time zone: to do so, we must first transform Now into our local time zone: (Note std::chrono::current_zone is not yet provided by libstdc++ or libc++, as far as I can tell.)

    bool IsTodayChristmas() {
        using namespace std::chrono;
    
        constexpr month_day Christmas = {December / 25};
        auto Now_local = current_zone()->to_local(system_clock::now());
        auto Today = year_month_day{floor<days>(Now_local)};
    
        return Today == Christmas / Today.year();
    }