Why can I not compare chrono::weekday's with operator<()?

Viewed 212

In the new C++20 <chrono> header there is a std::chrono::weekday type. Why can I not compare weekdays with operator< and thus sort them?

auto wd1 = Wednesday;
auto wd2 = Thursday;
if (wd1 < wd2)  // compile-time error
{
    // do something
}

test.cpp:14:13: error: invalid operands to binary expression (std::chrono::weekday and 
std::chrono::weekday)
if (wd1 < wd2)
    ~~~ ^ ~~~

Isn't Wednesday less than Thursday?

1 Answers

In the view of <chrono>, no Wednesday is not less than Thursday.

Thursday - Wednesday does indeed equal days{1}. However Wednesday - Thursday equals days{6}, not days{-1}.

In modern culture, there is disagreement about which day is the first day of the week. The <chrono> library takes the view that we do not have to agree on which day is the first day of the week. We can do meaningful computations with days of the week without such agreement.

To facilitate such computations, <chrono> views the weekdays as an independent calendar that repeats itself every 7 days, with absolutely no difference between any of the 7 day cycles. Monday follows Sunday, Thursday follows Wednesday, and Sunday follows Saturday. It is a circular range of seven values with no beginning and no end.

As a practical matter, there are two popular encodings of weekdays in terms of integral values:

  1. C encodes [Sunday, Saturday] as [0, 6].
  2. ISO encodes [Monday, Sunday] as [1, 7].

<chrono> acknowledges this by accepting [0, 7] in the weekday constructor to mean Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday, respectively. And to enable the reverse transformation weekday has two member functions:

  1. c_encoding()
  2. iso_encoding()

which return the integral value associated with the stored weekday according to those two protocols (0 or 7 for Sunday, and 1 thru 6 for Monday thru Saturday).

However, the underlying encoding of std::chrono::weekday should be considered an unimportant detail for computations involving weekday.

std::chrono::weekday is a circular range of 7 values. No value is greater than any other value. They are either equal or not equal.

Difference between any two weekday values (say x and y) results in the number of days x is ahead of y. This is true, no matter what numerical encoding you imagine represents weekday under the hood.

And this means that Wednesday is not less than Thursday. Wednesday is 6 days ahead of Thursday, and Thursday is 1 day ahead of Wednesday.

This design enables computations such as "what is the next Monday from this date" without depending on the underlying encoding:

std::chrono::sys_days
next_monday(std::chrono::sys_days x)
{
    using namespace std::chrono;
    return x + (Monday - weekday{x});
}

In English:

How many days is x's weekday behind Monday? Add that many days to x.

Related