Daily bit(e) of C++ | std::chrono — relative “pseudo-dates”

Šimon Tóth
2 min readMay 18, 2024

--

Daily bit(e) of C++ ♻️75, Expressing relative “pseudo-dates” using the C++20 std::chrono date support.

One of the very useful features of the C++20 extension to std::chrono is support for relative “pseudo-dates”.

Particularly when working with real-world events, we often describe dates in relative terms, such as the last day in May or the second Friday in June.

Expressing such dates in code without explicit support is cumbersome, as it typically requires hand-rolled logic.

The std::chrono library directly supports expressing the last day and weekday of a month and also supports expressions for the nth weekday of a month (e.g., the 2nd Sunday in June).

#include <chrono>
#include <cassert>

using namespace std::chrono;


// Last day in a month
auto last_day_in_feb = February/last;
// decltype(last_day_in_feb) == std::chrono::month_day_last

// Find leaping years in 2024..2104
for (auto year = 2024y; year <= 2104y; ++year) {
auto maybe_leap = year/last_day_in_feb;
// same as: year/Februrary/last
// decltype(maybe_leap) == std::chrono::year_month_day_last

assert(maybe_leap.ok());
if (maybe_leap.day() == 29d) { // requires maybe_leap.ok()
// 2024, 2028, 2032, ..., 2096, 2104
}
}


// Last weekday in a month
auto last_sunday = December/Sunday[last];
// decltype(last_sunday) == std::chrono::month_weekday_last

// Iterate over the last Sundays in 2024..2030
for (auto year = 2024y; year <= 2030y; ++year) {
auto pseudo = year/last_sunday;
// same as: year/December/Sunday[last];
// decltype(pseudo) == std::chrono::year_month_weekday_last

// Convert to the actual year_month_day
std::chrono::year_month_day actual{pseudo};

/*
2024-12-29
2025-12-28
2026-12-27
...
*/
}


// nth weekday in a month
// US Thanksgiving date, 4th Thursday in November
auto thanksgiving = November/Thursday[4]; // ordinal, not index
// decltype(thanksgiving) == std::chrono::month_weekday

for (auto year = 2024y; year <= 2030y; year++) {
// As long as the expression is not ambiguous,
// the order doesn't matter
year_month_day date{thanksgiving/year};

/*
2024-11-28
2025-11-27
2026-11-26
...
*/
}

Open the example in Compiler Explorer.

--

--

Šimon Tóth

20 years worth of Software Engineering experience distilled into easily digestible articles.