Why does `std::chrono::weekday` allow but doesn't preserve values outside of valid range?

  • A+

According to section [time.cal.wd.overview]/1 of the C++ standard:

weekday represents a day of the week in the civil calendar. It normally holds values in the range 0 to 6, corresponding to Sunday through Saturday, but it may hold non-negative values outside this range.

At the same time arithmetic operations perform modulo 7 arithmetic forcing the result in the range [0, 6], e.g.

weekday wd(7); // wd.ok() == false - wd is invalid ++wd; // wd == weekday(1) // wd.ok() == true  - wd silently becomes valid 

Why does weekday have such peculiar behavior, particularly why are values outside of [0, 6] allowed but not preserved by arithmetic operations?


The weekday(unsigned wd) constructor promises to hold any value in the range [0, 255]. The rationale for this is:

  1. It's very fast.
  2. It allows a client to assign an "unused" value to something useful in the client's logic.

For an example of (2):

constexpr weekday not_a_weekday{255}; ... weekday wd = not_a_weekday; in >> wd; if (wd == not_a_weekday)     throw "oops"; 

weekday arithmetic forces the range back into [0, 6] because if you write the algorithm to do modulo 7 arithmetic, with no range checking at all, this is what naturally happens. I.e. this is the fastest thing to do.

So in summary: Performance is the rationale for the current weekday spec, combined with a sizeof which is as small as possible (which can also contribute to performance).

However given as much performance as possible, whatever behaviors are left over (occur naturally) can be beneficial to standardize and let clients take advantage of these behaviors as opposed to saying that they are Undefined Behavior TM.

Indeed, the spec avoids UB as much as possible, opting for Unspecified Behavior instead. For example weekday{300} may not store the value you want, but it can not reformat your disk, and the optimizer is not allowed to pretend the code doesn't exist.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: