Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c++20

chrono

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?

like image 674
Howard Hinnant Avatar asked Jan 13 '21 02:01

Howard Hinnant


People also ask

Why doesn't the + operator work on strings?

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.

What is the range of weekday in C++?

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 the relational operator (==) not produce correct output?

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.


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.

like image 184
Howard Hinnant Avatar answered Sep 19 '22 22:09

Howard Hinnant