In the new C++20 <chrono>
header there is a std::chrono::weekday
type. Why can I not compare weekday
s 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?
The + operator (concatenation) works on Strings even though Java doesn't support operator overloading; it's simply handled as a special case in the compiler, resolving to StringBuilder.append(). Similarly, == could have been handled as a special case.
Its normal range is [0, 6], for Sunday through Saturday, but it can hold any value in the range [0, 255]. Seven named constants are predefined in the std::chrono namespace for the seven days of the week. weekday is a TriviallyCopyable StandardLayoutType .
Why does this problem occur? In the case of floating-point numbers, the relational operator (==) does not produce correct output, this is due to the internal precision errors in rounding up floating-point numbers. In the above example, we can see the inaccuracy in comparing two floating-point numbers using “==” operator.
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:
<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:
c_encoding()
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With