iso_week

# `iso_week`

## Contents

- Introduction
- Implementation
- Overview
- Reference

## Introduction

This paper fully documents an ISO week date calendar that is fully interoperable with `date`.

## Implementation

This entire library is implemented in a single header: iso_week.h and is open source using the MIT license.

## Overview

This library creates field types that hold the year, week number and weekday associated with a ISO week date. For example, to specify the Saturday of the 51st week of 2015 one can say:

>     #include "iso_week.h"
>     #include <iostream>

>     int
>     main()
>     {
>         using namespace iso_week::literals;
>         auto iso_date = sat/51/2015;
>         std::cout << iso_date << '\n';
>     }

The output of this program is:

>     2015-W51-Sat

In this example `iso_date` has type `iso_week::year_weeknum_weekday`, and this type does nothing but hold the three quantities: `year`, `weeknum` and `weekday`. This is such trivial functionality that it almost seems useless. Anyone can write a type to be constructed from three values, and then print them back out when requested.

The real power of `year_weeknum_weekday` is that it can implicitly convert to and from `sys_days`. And `sys_days` is just a type alias for:

>     std::chrono::time_point<std::chrono::system_clock, days>

This is the exact same `sys_days` used by the `date` and time zone libraries. And so by simply having conversions to and from `sys_days`, `iso_week::year_weeknum_weekday` becomes seamlessly interoperable with all of the types in `date` and time zone such as `date::year_month_day` and `date::Zone`:

>     #include "date.h"
>     #include "iso_week.h"
>     #include "tz.h"
>     #include <iostream>

>     int
>     main()
>     {
>         using namespace std::chrono;
>         using namespace date;
>         using namespace iso_week;
>         auto zone = locate_zone("America/New_York");
>         auto now = zone->to_local(system_clock::now());
>         auto dp = floor<days>(now.first);
>         auto iso_date = year_weeknum_weekday{dp};
>         auto civil_date = year_month_day{dp};
>         auto time = make_time(duration_cast<minutes>(now.first-dp));
>         std::cout << "It is currently " << time << ' ' << now.second << " on "
>                   << iso_date << " which is also " << civil_date << '\n';
>     }

Which just output for me:

>     It is currently 18:33 EST on 2015-W51-Sat which is also 2015-12-19

Or if you want to find the civil date of the last day of the ISO week year for 2015, then (knowning the last day of the week is Sunday in this calendar) it is:

>     using namespace iso_week::literals;
>     std::cout << date::year_month_day{2015_y/last/sun} << '\n';

Which will output:

>     2016-01-03

And of course one can convert in the opposite direction:

>     using namespace date::literals;
>     std::cout << iso_week::year_weeknum_weekday{2016_y/1/3} << '\n';

Which will output:

>     2015-W53-Sun

In particular, note that for this day, the `iso_week::year` is 2015 and the `date::year` is 2016.

This brings us to an important type-safety feature of these libraries: The `iso_week::year` and the `date::year` are two distinct types. They represent concepts that are very similar. They almost always have the same value for the same `sys_days`. But as in this example, they are occasionally different. It is not unheard of for computer systems to conflate these two very similar types, resulting in bugs that are hard to find because they are relatively rare. Having the C++ type system help you keep these similar but different concepts distinct is a solid step towards finding bugs at compile time!

## Reference

Here is a detailed specification of the entire library. This specification is detailed enough that you could write your own implementation from it if desired. But feel free to use this one instead. Each type, and each operation is simple and predictable.

durations |
| `days`
| `weeks`
| `years`
time_point |
| `sys_days`
types |
| `last_week`
| `weekday`
| `weeknum`
| `year`
| `year_weeknum`
| `year_lastweek`
| `weeknum_weekday`
| `lastweek_weekday`
| `year_weeknum_weekday`
| `year_lastweek_weekday`
date composition operators |
| `constexpr year_weeknum operator/(const year& y, const weeknum& wn) noexcept;`
| `constexpr year_weeknum operator/(const year& y, int wn) noexcept;`
| `constexpr year_lastweek operator/(const year& y, last_week wn) noexcept;`
| `constexpr weeknum_weekday operator/(const weeknum& wn, const weekday& wd) noexcept;`
| `constexpr weeknum_weekday operator/(const weeknum& wn, int wd) noexcept;`
| `constexpr weeknum_weekday operator/(const weekday& wd, const weeknum& wn) noexcept;`
| `constexpr weeknum_weekday operator/(const weekday& wd, int wn) noexcept;`
| `constexpr lastweek_weekday operator/(const last_week& wn, const weekday& wd) noexcept;`
| `constexpr lastweek_weekday operator/(const last_week& wn, int wd) noexcept;`
| `constexpr lastweek_weekday operator/(const weekday& wd, const last_week& wn) noexcept;`
| `constexpr year_weeknum_weekday operator/(const year_weeknum& ywn, const weekday& wd) noexcept;`
| `constexpr year_weeknum_weekday operator/(const year_weeknum& ywn, int wd) noexcept;`
| `constexpr year_weeknum_weekday operator/(const weeknum_weekday& wnwd, const year& y) noexcept;`
| `constexpr year_weeknum_weekday operator/(const weeknum_weekday& wnwd, int y) noexcept;`
| `constexpr year_lastweek_weekday operator/(const year_lastweek& ylw, const weekday& wd) noexcept;`
| `constexpr year_lastweek_weekday operator/(const year_lastweek& ylw, int wd) noexcept;`
| `constexpr year_lastweek_weekday operator/(const lastweek_weekday& lwwd, const year& y) noexcept;`
| `constexpr year_lastweek_weekday operator/(const lastweek_weekday& lwwd, int y) noexcept;`

Everything here is contained in the namespace `iso_week`. The literal operators, and the constexpr field literals (e.g. `sun`, `last`, etc.) are in namespace `iso_week::literals` and imported into namespace `iso_week`.

### `days`

> `days` is a `std::chrono::duration` with a tick period of 24 hours. This definition is not an SI unit but is accepted for use with SI. `days` is the resultant type when subtracting two `sys_days`s.

>     using days = std::chrono::duration
>         <int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;

### `weeks`

> `weeks` is a `std::chrono::duration` with a tick period of 7 days. This definition is widely recognized and predates the Gregorian calendar. It is consistent with ISO 8601. `weeks` will implicitly convert to `days` but not vice-versa.

>     using weeks = std::chrono::duration
>         <int, std::ratio_multiply<std::ratio<7>, days::period>>;

### `years`

> `years` is a `std::chrono::duration` with a tick period of 365.2425 days. This definition accurately describes the length of the average year in the ISO week calendar. `years` is the resultant type when subtracting two `year` field-based time points. `years` is not implicitly convertible to `days` or `weeks` nor vice-versa.

>     using years = std::chrono::duration
>         <int, std::ratio_multiply<std::ratio<146097, 400>, days::period>>;

### `sys_days`

> `sys_days` is a `std::chrono::time_point` using `std::chrono::system_clock` and `days`. This makes `sys_days` interoperable with `std::chrono::system_clock::time_point`. It is simply a count of days since the epoch of `std::chrono::system_clock` which in every implementation is Jan. 1, 1970. `sys_days` is a serial-based time point with a resolution of `days`.

>     using sys_days = std::chrono::time_point<std::chrono::system_clock, days>;

### `last_week`

> `last_week` is a `struct` that is `CopyConstructible`. There exists a `constexpr` instance of `last_week` named `last`. This is simply a tag type. It is used to indicate the last week of the year.

>     struct last_week
>     {
>         explicit last_week() = default;
>     };

>     inline namespace literals
>     {

>     constexpr iso_week::last_week last{};

>     }

> I am leading the C++ standard here a little with the `explicit` qualifier on the default constructor. This compiles today, but doesn't have quite the desired semantics. But it will when CWG 1518 passes. This will make it so that `{}` won't implicitly convert to `last_week`. This addresses the concern expressed in LWG 2510.

### `weekday`

> Synopsis

>     class weekday
>     {
>         unsigned char wd_;  // exposition only
>     public:
>         explicit constexpr weekday(unsigned wd) noexcept;
>         constexpr weekday(const sys_days& dp) noexcept;
>         constexpr weekday(date::weekday wd) noexcept;
>         explicit weekday(int) = delete;

>         weekday& operator++() noexcept;
>         weekday operator++(int) noexcept;
>         weekday& operator--() noexcept;
>         weekday operator--(int) noexcept;

>         weekday& operator+=(const days& d) noexcept;
>         weekday& operator-=(const days& d) noexcept;

>         constexpr explicit operator unsigned() const noexcept;
>         constexpr operator date::weekday() const noexcept;
>         constexpr bool ok() const noexcept;
>     };

>     constexpr bool operator==(const weekday& x, const weekday& y) noexcept;
>     constexpr bool operator!=(const weekday& x, const weekday& y) noexcept;

>     constexpr weekday operator+(const weekday& x, const days&    y) noexcept;
>     constexpr weekday operator+(const days&    x, const weekday& y) noexcept;
>     constexpr weekday operator-(const weekday& x, const days&    y) noexcept;
>     constexpr days    operator-(const weekday& x, const weekday& y) noexcept;

>     std::ostream& operator<<(std::ostream& os, const weekday& wd);

>     inline namespace literals
>     {
>     constexpr weekday mon{1u};
>     constexpr weekday tue{2u};
>     constexpr weekday wed{3u};
>     constexpr weekday thu{4u};
>     constexpr weekday fri{5u};
>     constexpr weekday sat{6u};
>     constexpr weekday sun{7u};
>     }  // namespace literals

> Overview

> `weekday` represents a day of the week in the ISO week calendar. It should only be representing values in the range 1 to 7, corresponding to Monday thru Sunday. However it may hold values outside this range. It can be constructed with any `unsigned` value, which will be subsequently truncated to fit into `weekday`'s internal storage. `weekday` is equality comparable. `weekday` is not less-than comparable because there is no universal consensus on which day is the first day of the week. This design chooses the encoding of 1 to 7 to represent Monday thru Sunday only because this is consistent with ISO 8601. However `weekday`'s comparison and arithmetic operations treat the days of the week as a circular range, with no beginning and no end. One can stream out a `weekday` for debugging purposes. `weekday` has explicit conversions to and from `unsigned`. There are 7 `weekday` constants, one for each day of the week.

> A `weekday` can be implicitly constructed from a `sys_days`. This is the computation that discovers the day of the week of an arbitrary date.

> A `weekday` can be implicitly converted to or from a `date::weekday`. `iso_week::weekday` and `date::weekday` are distinct types, though they represent very similar concepts. `date::weekday` can be indexed, and `iso_week::weekday` can not. `date::weekday` is encoded as [0, 6] representing [Sunday, Saturday], while `iso_week::weekday` is encoded as [1, 7] representing [Monday, Sunday]. The conversion functions will correctly translate between these encodings.

> Specification

> `weekday` is a trivially copyable class type. `weekday` is a standard-layout class type. `weekday` is a literal class type.

>     explicit constexpr weekday::weekday(unsigned wd) noexcept;

> > Effects: Constructs an object of type `weekday` by constructing `wd_` with `wd`.

>     constexpr weekday(const sys_days& dp) noexcept;

> > Effects: Constructs an object of type `weekday` by computing what day of the week corresponds to the `sys_days dp`, and representing that day of the week in `wd_`.

> > Example: If `dp` represents 1970-01-01, the constructed `weekday` shall represent Thursday by storing 4 in `wd_`.

>     constexpr weekday(date::weekday wd) noexcept;

> > Effects: Constructs an object of type `weekday` from a `date::weekday`. This changes the underlying encoding from [0, 6] -> [sun, sat] to [1, 7] -> [mon, sun].

>     weekday& weekday::operator++() noexcept;

> > Effects: If `wd_ != 6`, `++wd_`. Otherwise sets `wd_` to 0.

> > Returns: `*this`.

>     weekday weekday::operator++(int) noexcept;

> > Effects: `++(*this)`.

> > Returns: A copy of `*this` as it existed on entry to this member function.

>     weekday& weekday::operator--() noexcept;

> > Effects: If `wd_ != 0`, `--wd_`. Otherwise sets `wd_` to 6.

> > Returns: `*this`.

>     weekday weekday::operator--(int) noexcept;

> > Effects: `--(*this)`.

> > Returns: A copy of `*this` as it existed on entry to this member function.

>     weekday& weekday::operator+=(const days& d) noexcept;

> > Effects: `*this = *this + d`.

> > Returns: `*this`.

>     weekday& weekday::operator-=(const days& d) noexcept;

> > Effects: `*this = *this - d`.

> > Returns: `*this`.

>     constexpr explicit weekday::operator unsigned() const noexcept;

> > Returns: `wd_`.

>     constexpr operator date::weekday() const noexcept;

> > Returns: An object of type `date::weekday` constructed from `*this`. This changes the underlying encoding from [1, 7] -> [mon, sun] to [0, 6] -> [sun, sat].

>     constexpr bool weekday::ok() const noexcept;

> > Returns: `1 <= wd_ && wd_ <= 7`.

>     constexpr bool operator==(const weekday& x, const weekday& y) noexcept;

> > Returns: `unsigned{x} == unsigned{y}`.

>     constexpr bool operator!=(const weekday& x, const weekday& y) noexcept;

> > Returns: `!(x == y)`.

>     constexpr weekday  operator+(const weekday&  x, const days& y) noexcept;

> > Returns: A `weekday` for which `ok() == true` and is found as if by incrementing (or decrementing if `y < days{0}`) `x`, `y` times. If `weekday.ok() == false` prior to this operation, behaves as if `*this` is first brought into the range [1, 7] by modular arithmetic. [Note: For example `weekday{0}` becomes `weekday{7}`. — end note]

> > Complexity: O(1) with respect to the value of `y`. That is, repeated increments or decrements is not a valid implementation.

> > Example: `sun + days{6} == sat`.

>     constexpr weekday  operator+(const days& x, const weekday&  y) noexcept;

> > Returns: `y + x`.

>     constexpr weekday  operator-(const weekday&  x, const days& y) noexcept;

> > Returns: `x + -y`.

>     constexpr days operator-(const weekday&  x, const weekday&  y) noexcept;

> > Requires: `x.ok() == true` and `y.ok() == true`.

> > Returns: A value of `days` in the range of `days{0}` to `days{6}` inclusive.

> > Remarks: The returned value `d` shall satisfy the equality: `y + d == x`.

> > Example: `sat - sun == days{6}`.

>     std::ostream& operator<<(std::ostream& os, const weekday& wd);

> > Effects: If `ok() == true` outputs the same string that would be output for the weekday field by `asctime`, assuming the conversion `unsigned{date::weekday{*this}}`. Otherwise outputs `unsigned{wd} << " is not a valid weekday"`.

> > Returns: `os`.

### `weeknum`

> Synopsis

>     class weeknum
>     {
>         unsigned char wn_;  // exposition only

>     public:
>         explicit constexpr weeknum(unsigned wn) noexcept;

>         weeknum& operator++() noexcept;
>         weeknum operator++(int) noexcept;
>         weeknum& operator--() noexcept;
>         weeknum operator--(int) noexcept;

>         weeknum& operator+=(const weeks& w) noexcept;
>         weeknum& operator-=(const weeks& w) noexcept;

>         constexpr explicit operator unsigned() const noexcept;
>         constexpr bool ok() const noexcept;
>     };

>     constexpr bool operator==(const weeknum& x, const weeknum& y) noexcept;
>     constexpr bool operator!=(const weeknum& x, const weeknum& y) noexcept;
>     constexpr bool operator< (const weeknum& x, const weeknum& y) noexcept;
>     constexpr bool operator> (const weeknum& x, const weeknum& y) noexcept;
>     constexpr bool operator<=(const weeknum& x, const weeknum& y) noexcept;
>     constexpr bool operator>=(const weeknum& x, const weeknum& y) noexcept;

>     constexpr weeknum operator+(const weeknum& x, const weeks&   y) noexcept;
>     constexpr weeknum operator+(const weeks&   x, const weeknum& y) noexcept;
>     constexpr weeknum operator-(const weeknum& x, const weeks&   y) noexcept;
>     constexpr weeks   operator-(const weeknum& x, const weeknum& y) noexcept;

>     std::ostream& operator<<(std::ostream& os, const weeknum& wn);

>     inline namespace literals
>     {

>     constexpr weeknum operator "" _w(unsigned long long wn) noexcept;

>     }

> Overview

> `weeknum` represents a week number of of the ISO week-year [1, 53]. It should only be representing values in the range 1 to 53. However it may hold values outside this range. It can be constructed with any `unsigned` value, which will be subsequently truncated to fit into `weeknum`'s internal storage. `weeknum` is equality and less-than comparable, and participates in basic arithmetic with `weeks` representing the quantity between any two `weeknum`'s. One can stream out a `weeknum` for debugging purposes. `weeknum` has explicit conversions to and from `unsigned`.

> Specification

> `weeknum` is a trivially copyable class type. `weeknum` is a standard-layout class type. `weeknum` is a literal class type.

>     explicit constexpr weeknum::weeknum(unsigned wn) noexcept;

> > Effects: Constructs an object of type `weeknum` by constructing `wn_` with `wn`.

>     weeknum& weeknum::operator++() noexcept;

> > Effects: `++wn_`.

> > Returns: `*this`.

>     weeknum weeknum::operator++(int) noexcept;

> > Effects: `++(*this)`.

> > Returns: A copy of `*this` as it existed on entry to this member function.

>     weeknum& weeknum::operator--() noexcept;

> > Effects: `--wn_`.

> > Returns: `*this`.

>     weeknum weeknum::operator--(int) noexcept;

> > Effects: `--(*this)`.

> > Returns: A copy of `*this` as it existed on entry to this member function.

>     weeknum& weeknum::operator+=(const weeks& w) noexcept;

> > Effects: `*this = *this + w`.

> > Returns: `*this`.

>     weeknum& weeknum::operator-=(const weeks& w) noexcept;

> > Effects: `*this = *this - w`.

> > Returns: `*this`.

>     constexpr explicit weeknum::operator unsigned() const noexcept;

> > Returns: `wn_`.

>     constexpr bool weeknum::ok() const noexcept;

> > Returns: `1 <= wn_ && wn_ <= 53`.

>     constexpr bool operator==(const weeknum& x, const weeknum& y) noexcept;

> > Returns: `unsigned{x} == unsigned{y}`.

>     constexpr bool operator!=(const weeknum& x, const weeknum& y) noexcept;

> > Returns: `!(x == y)`.

>     constexpr bool operator< (const weeknum& x, const weeknum& y) noexcept;

> > Returns: `unsigned{x} < unsigned{y}`.

>     constexpr bool operator> (const weeknum& x, const weeknum& y) noexcept;

> > Returns: `y < x`.

>     constexpr bool operator<=(const weeknum& x, const weeknum& y) noexcept;

> > Returns: `!(y < x)`.

>     constexpr bool operator>=(const weeknum& x, const weeknum& y) noexcept;

> > Returns: `!(x < y)`.

>     constexpr weeknum  operator+(const weeknum&  x, const weeks& y) noexcept;

> > Returns: `weeknum{unsigned{x} + static_cast<unsigned>(y.count())}`

>     constexpr weeknum  operator+(const weeks& x, const weeknum&  y) noexcept;

> > Returns: `y + x`.

>     constexpr weeknum  operator-(const weeknum&  x, const weeks& y) noexcept;

> > Returns: `x + -y`.

>     constexpr weeks operator-(const weeknum&  x, const weeknum&  y) noexcept;

> > Returns: `weeks{static_cast<weeks::rep>(unsigned{x}) - static_cast<weeks::rep>(unsigned{y})}`.

>     std::ostream& operator<<(std::ostream& os, const weeknum& wn);

> > Effects: Inserts 'W' followed by a decimal integral text representation of length 2, prefixed by '0' if the value is less than or equal to 9.

> > Returns: `os`.

> > Example: `5_w` is output as `W05`.

>     constexpr weeknum operator "" _w(unsigned long long wn) noexcept;

> > Returns: `weeknum{static_cast<unsigned>(wn)}`.

### `year`

> Synopsis

>     class year
>     {
>         short y_;  // exposition only

>     public:
>         explicit constexpr year(int y) noexcept;

>         year& operator++() noexcept;
>         year operator++(int) noexcept;
>         year& operator--() noexcept;
>         year operator--(int) noexcept;

>         year& operator+=(const years& y) noexcept;
>         year& operator-=(const years& y) noexcept;

>         constexpr explicit operator int() const noexcept;
>         constexpr bool ok() const noexcept;

>         static constexpr year min() noexcept;
>         static constexpr year max() noexcept;
>     };

>     constexpr bool operator==(const year& x, const year& y) noexcept;
>     constexpr bool operator!=(const year& x, const year& y) noexcept;
>     constexpr bool operator< (const year& x, const year& y) noexcept;
>     constexpr bool operator> (const year& x, const year& y) noexcept;
>     constexpr bool operator<=(const year& x, const year& y) noexcept;
>     constexpr bool operator>=(const year& x, const year& y) noexcept;

>     constexpr year  operator+(const year&  x, const years& y) noexcept;
>     constexpr year  operator+(const years& x, const year&  y) noexcept;
>     constexpr year  operator-(const year&  x, const years& y) noexcept;
>     constexpr years operator-(const year&  x, const year&  y) noexcept;

>     std::ostream& operator<<(std::ostream& os, const year& y);

>     inline namespace literals
>     {
>     constexpr year operator "" _y(unsigned long long y) noexcept;
>     }

> Overview

> `year` represents a year in the ISO week date calendar. It shall represent values in the range `[min(), max()]`. It can be constructed with any `int` value, which will be subsequently truncated to fit into `year`'s internal storage. `year` is equality and less-than comparable, and participates in basic arithmetic with `years` representing the quantity between any two `year`'s. One can form a `year` literal with `_y`. And one can stream out a `year` for debugging purposes. `year` has explicit conversions to and from `int`.

> Specification

> `year` is a trivially copyable class type. `year` is a standard-layout class type. `year` is a literal class type.

>     explicit constexpr year::year(int y) noexcept;

> > Effects: Constructs an object of type `year` by constructing `y_` with `y`.

>     year& year::operator++() noexcept;

> > Effects: `++y_`.

> > Returns: `*this`.

>     year year::operator++(int) noexcept;

> > Effects: `++(*this)`.

> > Returns: A copy of `*this` as it existed on entry to this member function.

>     year& year::operator--() noexcept;

> > Effects: `--y_`.

> > Returns: `*this`.

>     year year::operator--(int) noexcept;

> > Effects: `--(*this)`.

> > Returns: A copy of `*this` as it existed on entry to this member function.

>     year& year::operator+=(const years& y) noexcept;

> > Effects: `*this = *this + y`.

> > Returns: `*this`.

>     year& year::operator-=(const years& y) noexcept;

> > Effects: `*this = *this - y`.

> > Returns: `*this`.

>     constexpr explicit year::operator int() const noexcept;

> > Returns: `y_`.

>     constexpr bool year::ok() const noexcept;

> > Returns: `min() <= *this && *this <= max()`.

>     static constexpr year year::min() noexcept;

> > Returns: A `year` constructed with the minimum representable year number. This year shall be a value such that `sys_days{min()/1_w/mon} + Unit{0}`, where `Unit` is one of `microseconds`, `milliseconds`, `seconds`, `minutes`, or `hours`, there shall be no overflow. [Note: `nanoseconds` is intentionally omitted from this list. — end note]

>     static constexpr year year::max() noexcept;

> > Returns: A `year` constructed with the maximum representable year number. This year shall be a value such that `sys_days{max()/last/sun} + Unit{0}`, where `Unit` is one of `microseconds`, `milliseconds`, `seconds`, `minutes`, or `hours`, there shall be no overflow. [Note: `nanoseconds` is intentionally omitted from this list. — end note]

>     constexpr bool operator==(const year& x, const year& y) noexcept;

> > Returns: `int{x} == int{y}`.

>     constexpr bool operator!=(const year& x, const year& y) noexcept;

> > Returns: `!(x == y)`.

>     constexpr bool operator< (const year& x, const year& y) noexcept;

> > Returns: `int{x} < int{y}`.

>     constexpr bool operator> (const year& x, const year& y) noexcept;

> > Returns: `y < x`.

>     constexpr bool operator<=(const year& x, const year& y) noexcept;

> > Returns: `!(y < x)`.

>     constexpr bool operator>=(const year& x, const year& y) noexcept;

> > Returns: `!(x < y)`.

>     constexpr year  operator+(const year&  x, const years& y) noexcept;

> > Returns: `year{int{x} + y.count()}`.

>     constexpr year  operator+(const years& x, const year&  y) noexcept;

> > Returns: `y + x`.

>     constexpr year  operator-(const year&  x, const years& y) noexcept;

> > Returns: `x + -y`.

>     constexpr years operator-(const year&  x, const year&  y) noexcept;

> > Returns: `years{int{x} - int{y}}`.

>     constexpr year operator "" _y(unsigned long long y) noexcept;

> > Returns: `year{static_cast<int>(y)}`.

>     std::ostream& operator<<(std::ostream& os, const year& y);

> > Effects: Inserts a signed decimal integral text representation of `y` into `os`. If the year is less than four decimal digits, pads the year with `'0'` to four digits. If the year is negative, prefixes with `'-'`.

> > Returns: `os`.

>     constexpr year operator "" _y(unsigned long long y) noexcept;

> > Returns: `year{static_cast<int>(y)}`.

### `year_weeknum`

> Synopsis

>     class year_weeknum
>     {
>         iso_week::year    y_;   // exposition only
>         iso_week::weeknum wn_;  // exposition only

>     public:
>         constexpr year_weeknum(const iso_week::year& y, const iso_week::weeknum& wn) noexcept;

>         constexpr iso_week::year    year()    const noexcept;
>         constexpr iso_week::weeknum weeknum() const noexcept;

>         year_weeknum& operator+=(const years& dy) noexcept;
>         year_weeknum& operator-=(const years& dy) noexcept;

>         constexpr bool ok() const noexcept;
>     };

>     constexpr bool operator==(const year_weeknum& x, const year_weeknum& y) noexcept;
>     constexpr bool operator!=(const year_weeknum& x, const year_weeknum& y) noexcept;
>     constexpr bool operator< (const year_weeknum& x, const year_weeknum& y) noexcept;
>     constexpr bool operator> (const year_weeknum& x, const year_weeknum& y) noexcept;
>     constexpr bool operator<=(const year_weeknum& x, const year_weeknum& y) noexcept;
>     constexpr bool operator>=(const year_weeknum& x, const year_weeknum& y) noexcept;

>     constexpr year_weeknum operator+(const year_weeknum& ym, const years& dy) noexcept;
>     constexpr year_weeknum operator+(const years& dy, const year_weeknum& ym) noexcept;
>     constexpr year_weeknum operator-(const year_weeknum& ym, const years& dy) noexcept;

>     std::ostream& operator<<(std::ostream& os, const year_weeknum& ym);

> Overview

> `year_weeknum` is simply a collection of a `year` and a `weeknum`. It represents a specific week of a year, but not the day of the week. One can perform year-oriented arithmetic with a `year_weeknum`. And `year_weeknum` is equality and less-than comparable.

> Specification

> `year_weeknum` is a trivially copyable class type. `year_weeknum` is a standard-layout class type. `year_weeknum` is a literal class type.

>     constexpr year_weeknum::year_weeknum(const iso_week::year& y, const iso_week::weeknum& wn) noexcept;

> > Effects: Constructs an object of type `year_weeknum` by constructing `y_` with `y` and `wn_` with `wn`.

>     constexpr iso_week::year year_weeknum::year() const noexcept;

> > Returns: `y_`.

>     constexpr iso_week::weeknum year_weeknum::weeknum() const noexcept;

> > Returns: `wn_`.

>     year_weeknum& year_weeknum::operator+=(const years& dy) noexcept;

> > Effects: `*this = *this + dy`.

> > Returns: `*this`.

>     year_weeknum& year_weeknum::operator-=(const years& dy) noexcept;

> > Effects: `*this = *this - dy`.

> > Returns: `*this`.

>     constexpr bool year_weeknum::ok() const noexcept;

> > Returns: `y_.ok() && 1_w <= wn_ && wn_ <= (y_/last).weeknum()`.

>     constexpr bool operator==(const year_weeknum& x, const year_weeknum& y) noexcept;

> > Returns: `x.year() == y.year() && x.weeknum() == y.weeknum()`.

>     constexpr bool operator!=(const year_weeknum& x, const year_weeknum& y) noexcept;

> > Returns: `!(x == y)`.

>     constexpr bool operator<(const year_weeknum& x, const year_weeknum& y) noexcept;

> > Returns: `x.year() < y.year() ? true : (x.year() > y.year() ? false : (x.weeknum() < y.weeknum()))`.

>     constexpr bool operator>(const year_weeknum& x, const year_weeknum& y) noexcept;

> > Returns: `y < x`.

>     constexpr bool operator<=(const year_weeknum& x, const year_weeknum& y) noexcept;

> > Returns: `!(y < x)`.

>     constexpr bool operator>=(const year_weeknum& x, const year_weeknum& y) noexcept;

> > Returns: `!(x < y)`.

>     constexpr year_weeknum operator+(const year_weeknum& ym, const years& dy) noexcept;

> > Returns: `(ym.year() + dy) / ym.weeknum()`.

>     constexpr year_weeknum operator+(const years& dy, const year_weeknum& ym) noexcept;

> > Returns: `ym + dy`.

>     constexpr year_weeknum operator-(const year_weeknum& ym, const years& dy) noexcept;

> > Returns: `ym + -dy`.

>     std::ostream& operator<<(std::ostream& os, const year_weeknum& ywn);

> > Effects: `os << ywn.year() << '-' << ywn.weeknum()`.

> > Returns: `os`.

### `year_lastweek`

> Synopsis

>     class year_lastweek
>     {
>         iso_week::year y_;  // exposition only

>     public:
>         explicit constexpr year_lastweek(const iso_week::year& y) noexcept;

>         constexpr iso_week::year    year()    const noexcept;
>         constexpr iso_week::weeknum weeknum() const noexcept;

>         year_lastweek& operator+=(const years& dy) noexcept;
>         year_lastweek& operator-=(const years& dy) noexcept;

>         constexpr bool ok() const noexcept;
>     };

>     constexpr bool operator==(const year_lastweek& x, const year_lastweek& y) noexcept;
>     constexpr bool operator!=(const year_lastweek& x, const year_lastweek& y) noexcept;
>     constexpr bool operator< (const year_lastweek& x, const year_lastweek& y) noexcept;
>     constexpr bool operator> (const year_lastweek& x, const year_lastweek& y) noexcept;
>     constexpr bool operator<=(const year_lastweek& x, const year_lastweek& y) noexcept;
>     constexpr bool operator>=(const year_lastweek& x, const year_lastweek& y) noexcept;

>     constexpr year_lastweek operator+(const year_lastweek& ym, const years& dy) noexcept;
>     constexpr year_lastweek operator+(const years& dy, const year_lastweek& ym) noexcept;
>     constexpr year_lastweek operator-(const year_lastweek& ym, const years& dy) noexcept;

>     std::ostream& operator<<(std::ostream& os, const year_lastweek& ym);

> Overview

> `year_lastweek` represents a ISO week `year` and the last week of that year. One can perform year-oriented arithmetic with a `year_lastweek`. And `year_lastweek` is equality and less-than comparable.

> Specification

> `year_lastweek` is a trivially copyable class type. `year_lastweek` is a standard-layout class type. `year_lastweek` is a literal class type.

>     explicit constexpr year_lastweek::year_lastweek(const iso_week::year& y) noexcept;

> > Effects: Constructs an object of type `year_lastweek` by constructing `y_` with `y`.

>     constexpr iso_week::year year_lastweek::year() const noexcept;

> > Returns: `y_`.

>     constexpr iso_week::weeknum year_lastweek::weeknum() const noexcept;

> > Returns: The ISO week number for the last week of the year `y_`.

>     year_lastweek& year_lastweek::operator+=(const years& dy) noexcept;

> > Effects: `*this = *this + dy`.

> > Returns: `*this`.

>     year_lastweek& year_lastweek::operator-=(const years& dy) noexcept;

> > Effects: `*this = *this - dy`.

> > Returns: `*this`.

>     constexpr bool year_lastweek::ok() const noexcept;

> > Returns: `y_.ok()`.

>     constexpr bool operator==(const year_lastweek& x, const year_lastweek& y) noexcept;

> > Returns: `x.year() == y.year()`.

>     constexpr bool operator!=(const year_lastweek& x, const year_lastweek& y) noexcept;

> > Returns: `!(x == y)`.

>     constexpr bool operator<(const year_lastweek& x, const year_lastweek& y) noexcept;

> > Returns: `x.year() < y.year()`.

>     constexpr bool operator>(const year_lastweek& x, const year_lastweek& y) noexcept;

> > Returns: `y < x`.

>     constexpr bool operator<=(const year_lastweek& x, const year_lastweek& y) noexcept;

> > Returns: `!(y < x)`.

>     constexpr bool operator>=(const year_lastweek& x, const year_lastweek& y) noexcept;

> > Returns: `!(x < y)`.

>     constexpr year_lastweek operator+(const year_lastweek& ym, const years& dy) noexcept;

> > Returns: `year_lastweek{ym.year() + dy}`.

>     constexpr year_lastweek operator+(const years& dy, const year_lastweek& ym) noexcept;

> > Returns: `ym + dy`.

>     constexpr year_lastweek operator-(const year_lastweek& ym, const years& dy) noexcept;

> > Returns: `ym + -dy`.

>     std::ostream& operator<<(std::ostream& os, const year_lastweek& ywn);

> > Effects: `os << ywn.year() << "-W last"`.

> > Returns: `os`.

### `weeknum_weekday`

> Synopsis

>     class weeknum_weekday
>     {
>         iso_week::weeknum wn_;  // exposition only
>         iso_week::weekday wd_;  // exposition only

>     public:
>         constexpr weeknum_weekday(const iso_week::weeknum& wn,
>                                   const iso_week::weekday& wd) noexcept;

>         constexpr iso_week::weeknum weeknum() const noexcept;
>         constexpr iso_week::weekday weekday() const noexcept;

>         constexpr bool ok() const noexcept;
>     };

>     constexpr bool operator==(const weeknum_weekday& x, const weeknum_weekday& y) noexcept;
>     constexpr bool operator!=(const weeknum_weekday& x, const weeknum_weekday& y) noexcept;
>     constexpr bool operator< (const weeknum_weekday& x, const weeknum_weekday& y) noexcept;
>     constexpr bool operator> (const weeknum_weekday& x, const weeknum_weekday& y) noexcept;
>     constexpr bool operator<=(const weeknum_weekday& x, const weeknum_weekday& y) noexcept;
>     constexpr bool operator>=(const weeknum_weekday& x, const weeknum_weekday& y) noexcept;

>     std::ostream& operator<<(std::ostream& os, const weeknum_weekday& md);

> Overview

> `weeknum_weekday` is simply a collection of a `weeknum` and a `weekday`. It represents a specific week and day of the week, but an unspecified year. `weeknum_weekday` is equality and less-than comparable.

> Specification

> `weeknum_weekday` is a trivially copyable class type. `weeknum_weekday` is a standard-layout class type. `weeknum_weekday` is a literal class type.

>     constexpr weeknum_weekday::weeknum_weekday(const iso_week::weeknum& wn,
>                                                const iso_week::weekday& wd) noexcept;

> > Effects: Constructs an object of type `weeknum_weekday` by constructing `wn_` with `wn` and `wd_` with `wd`.

>     constexpr iso_week::weeknum weeknum_weekday::weeknum() const noexcept;

> > Returns: `wn_`.

>     constexpr iso_week::weekday weeknum_weekday::weekday() const noexcept;

> > Returns: `wd_`.

>     constexpr bool weeknum_weekday::ok() const noexcept;

> > Returns: `wn_.ok() && wd_.ok()`.

>     constexpr bool operator==(const weeknum_weekday& x, const weeknum_weekday& y) noexcept;

> > Returns: `x.weeknum() == y.weeknum() && x.weekday() == y.weekday()`.

>     constexpr bool operator!=(const weeknum_weekday& x, const weeknum_weekday& y) noexcept;

> > Returns: `!(x == y)`.

>     constexpr bool operator<(const weeknum_weekday& x, const weeknum_weekday& y) noexcept;

> > Returns: `x.weeknum() < y.weeknum() ? true : (x.weeknum() > y.weeknum() ? false : (unsigned{x.weekday()} < unsigned{y.weekday()}))`.

>     constexpr bool operator>(const weeknum_weekday& x, const weeknum_weekday& y) noexcept;

> > Returns: `y < x`.

>     constexpr bool operator<=(const weeknum_weekday& x, const weeknum_weekday& y) noexcept;

> > Returns: `!(y < x)`.

>     constexpr bool operator>=(const weeknum_weekday& x, const weeknum_weekday& y) noexcept;

> > Returns: `!(x < y)`.

>     std::ostream& operator<<(std::ostream& os, const weeknum_weekday& md);

> > Effects: `os << md.weeknum() << '-' << md.weekday()`.

> > Returns: `os`.

### `lastweek_weekday`

> Synopsis

>     class lastweek_weekday
>     {
>         iso_week::weekday wd_;  // exposition only

>     public:
>         explicit constexpr lastweek_weekday(const iso_week::weekday& wd) noexcept;

>         constexpr iso_week::weekday weekday() const noexcept;

>         constexpr bool ok() const noexcept;
>     };

>     constexpr bool operator==(const lastweek_weekday& x, const lastweek_weekday& y) noexcept;
>     constexpr bool operator!=(const lastweek_weekday& x, const lastweek_weekday& y) noexcept;
>     constexpr bool operator< (const lastweek_weekday& x, const lastweek_weekday& y) noexcept;
>     constexpr bool operator> (const lastweek_weekday& x, const lastweek_weekday& y) noexcept;
>     constexpr bool operator<=(const lastweek_weekday& x, const lastweek_weekday& y) noexcept;
>     constexpr bool operator>=(const lastweek_weekday& x, const lastweek_weekday& y) noexcept;

>     std::ostream& operator<<(std::ostream& os, const lastweek_weekday& md);

> Overview

> `lastweek_weekday` represents a weekday in the last week of an unspecified year. `lastweek_weekday` is equality and less-than comparable.

> Specification

> `lastweek_weekday` is a trivially copyable class type. `lastweek_weekday` is a standard-layout class type. `lastweek_weekday` is a literal class type.

>     explicit constexpr lastweek_weekday::lastweek_weekday(const iso_week::weekday& wd) noexcept;

> > Effects: Constructs an object of type `lastweek_weekday` by constructing `wd_` with `wd`.

>     constexpr iso_week::weekday lastweek_weekday::weekday() const noexcept;

> > Returns: `wd_`.

>     constexpr bool lastweek_weekday::ok() const noexcept;

> > Returns: `wd_.ok()`.

>     constexpr bool operator==(const lastweek_weekday& x, const lastweek_weekday& y) noexcept;

> > Returns: `x.weekday() == y.weekday()`.

>     constexpr bool operator!=(const lastweek_weekday& x, const lastweek_weekday& y) noexcept;

> > Returns: `!(x == y)`.

>     constexpr bool operator<(const lastweek_weekday& x, const lastweek_weekday& y) noexcept;

> > Returns: `unsigned{x.weekday()} < unsigned{y.weekday()}`.

>     constexpr bool operator>(const lastweek_weekday& x, const lastweek_weekday& y) noexcept;

> > Returns: `y < x`.

>     constexpr bool operator<=(const lastweek_weekday& x, const lastweek_weekday& y) noexcept;

> > Returns: `!(y < x)`.

>     constexpr bool operator>=(const lastweek_weekday& x, const lastweek_weekday& y) noexcept;

> > Returns: `!(x < y)`.

>     std::ostream& operator<<(std::ostream& os, const lastweek_weekday& md);

> > Effects: `os << "W last-" << md.weekday()`.

> > Returns: `os`.

### `year_weeknum_weekday`

> Synopsis

>     class year_weeknum_weekday
>     {
>         iso_week::year    y_;   // exposition only
>         iso_week::weeknum wn_;  // exposition only
>         iso_week::weekday wd_;  // exposition only

>     public:
>         constexpr year_weeknum_weekday(const iso_week::year& y, const iso_week::weeknum& wn,
>                                        const iso_week::weekday& wd) noexcept;
>         constexpr year_weeknum_weekday(const year_lastweek_weekday& x) noexcept;
>         constexpr year_weeknum_weekday(const sys_days& dp) noexcept;

>         year_weeknum_weekday& operator+=(const years& y) noexcept;
>         year_weeknum_weekday& operator-=(const years& y) noexcept;

>         constexpr iso_week::year    year()    const noexcept;
>         constexpr iso_week::weeknum weeknum() const noexcept;
>         constexpr iso_week::weekday weekday() const noexcept;

>         constexpr operator sys_days() const noexcept;
>         constexpr bool ok() const noexcept;
>     };

>     constexpr bool operator==(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;
>     constexpr bool operator!=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;
>     constexpr bool operator< (const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;
>     constexpr bool operator> (const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;
>     constexpr bool operator<=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;
>     constexpr bool operator>=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;

>     constexpr year_weeknum_weekday operator+(const year_weeknum_weekday& x, const years& y) noexcept;
>     constexpr year_weeknum_weekday operator+(const years& y, const year_weeknum_weekday& x) noexcept;
>     constexpr year_weeknum_weekday operator-(const year_weeknum_weekday& x, const years& y) noexcept;

>     std::ostream& operator<<(std::ostream& os, const year_weeknum_weekday& x);

> Overview

> `year_weeknum_weekday` represents a `year`, `weeknum`, and `weekday` in the ISO week date calendar. One can observe each field. `year_weeknum_weekday` supports year-oriented arithmetic. There is an implicit conversion to and from `sys_days`. There is also an implicit conversion from `year_lastweek_weekday`. `year_weeknum_weekday` is equality and less-than comparable.

> Specification

> `year_weeknum_weekday` is a trivially copyable class type. `year_weeknum_weekday` is a standard-layout class type. `year_weeknum_weekday` is a literal class type.

>     constexpr year_weeknum_weekday::year_weeknum_weekday(const iso_week::year& y,
>                                                          const iso_week::weeknum& wn,
>                                                          const iso_week::weekday& wd) noexcept;

> > Effects: Constructs an object of type `year_weeknum_weekday` by constructing `y_` with `y`, `wn_` with `wn`, and `wd_` with `wd`.

>     constexpr year_weeknum_weekday::year_weeknum_weekday(const year_lastweek_weekday& x) noexcept;

> > Effects: Constructs an object of type `year_weeknum_weekday` by constructing `y_` with `x.year()`, `wn_` with `x.weeknum()`, and `wd_` with `x.weekday()`.

>     constexpr year_weeknum_weekday::year_weeknum_weekday(const sys_days& dp) noexcept;

> > Effects: Constructs an object of type `year_weeknum_weekday` which corresponds to the date represented by `dp`.

> > Remarks: For any value of `year_weeknum_weekday`, `x`, for which `x.ok()` is `true`, this equality will also be `true`: `x == year_weeknum_weekday{sys_days{x}}`.

>     year_weeknum_weekday& year_weeknum_weekday::operator+=(const years& y) noexcept;

> > Effectx: `*this = *this + y`.

> > Returns: `*this`.

>     year_weeknum_weekday& year_weeknum_weekday::operator-=(const years& y) noexcept;

> > Effectx: `*this = *this - y`.

> > Returns: `*this`.

>     constexpr iso_week::year year_weeknum_weekday::year() const noexcept;

> > Returns: `y_`.

>     constexpr iso_week::weeknum year_weeknum_weekday::weeknum() const noexcept;

> > Returns: `wn_`.

>     constexpr iso_week::weekday year_weeknum_weekday::weekday() const noexcept;

> > Returns: `wd_`.

>     constexpr year_weeknum_weekday::operator sys_days() const noexcept;

> > Returns: A `sys_days` which represents the date represented by `*this`.

>     constexpr bool year_weeknum_weekday::ok() const noexcept;

> > Returns: `y_.ok() && wd_.ok() && 1_w <= wn_ && wn_ <= year_lastweek{y_}.weeknum()`.

>     constexpr bool operator==(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;

> > Returns: `x.year() == y.year() && x.weeknum() == y.weeknum() && x.weekday() == y.weekday()`.

>     constexpr bool operator!=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;

> > Returns: `!(x == y)`.

>     constexpr bool operator<(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;

> > Returns: `x.year() < y.year() ? true : (x.year() > y.year() ? false : (x.weeknum() < y.weeknum() ? true : (x.weeknum() > y.weeknum() ? false : (unsigned{x.weekday()} < unsigned{y.weekday()}))))`.

>     constexpr bool operator>(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;

> > Returns: `y < x`.

>     constexpr bool operator<=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;

> > Returns: `!(y < x)`.

>     constexpr bool operator>=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept;

> > Returns: `!(x < y)`.

>     constexpr year_weeknum_weekday operator+(const year_weeknum_weekday& x, const years& y) noexcept;

> > Returns: `(x.year() + y) / x.weeknum() / x.weekday()`.

>     constexpr year_weeknum_weekday operator+(const years& y, const year_weeknum_weekday& x) noexcept;

> > Returns: `x + y`.

>     constexpr year_weeknum_weekday operator-(const year_weeknum_weekday& x, const years& y) noexcept;

> > Returns: `x + -y`.

>     std::ostream& operator<<(std::ostream& os, const year_weeknum_weekday& x);

> > Effects: `os << x.year() << '-' << x.weeknum() << '-' << x.weekday()`.

> > Returns: `os`.

### `year_lastweek_weekday`

> Synopsis

>     class year_lastweek_weekday
>     {
>         iso_week::year    y_;   // exposition only
>         iso_week::weekday wd_;  // exposition only

>     public:
>         constexpr year_lastweek_weekday(const iso_week::year& y,
>                                         const iso_week::weekday& wd) noexcept;

>         year_lastweek_weekday& operator+=(const years& y) noexcept;
>         year_lastweek_weekday& operator-=(const years& y) noexcept;

>         constexpr iso_week::year    year()    const noexcept;
>         constexpr iso_week::weeknum weeknum() const noexcept;
>         constexpr iso_week::weekday weekday() const noexcept;

>         constexpr operator sys_days() const noexcept;
>         constexpr bool ok() const noexcept;
>     };

>     constexpr bool operator==(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;
>     constexpr bool operator!=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;
>     constexpr bool operator< (const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;
>     constexpr bool operator> (const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;
>     constexpr bool operator<=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;
>     constexpr bool operator>=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;

>     constexpr year_lastweek_weekday operator+(const year_lastweek_weekday& x, const years& y) noexcept;
>     constexpr year_lastweek_weekday operator+(const years& y, const year_lastweek_weekday& x) noexcept;
>     constexpr year_lastweek_weekday operator-(const year_lastweek_weekday& x, const years& y) noexcept;

>     std::ostream& operator<<(std::ostream& os, const year_lastweek_weekday& x);

> Overview

> `year_lastweek_weekday` represents a `year`, and `weekday` in the last week of the ISO week date calendar. One can observe each field. `year_lastweek_weekday` supports year-oriented arithmetic. There is an implicit conversion to `sys_days`. `year_lastweek_weekday` is equality and less-than comparable.

> Specification

> `year_lastweek_weekday` is a trivially copyable class type. `year_lastweek_weekday` is a standard-layout class type. `year_lastweek_weekday` is a literal class type.

>     constexpr year_lastweek_weekday::year_lastweek_weekday(const iso_week::year& y,
>                                                            const iso_week::weekday& wd) noexcept;

> > Effects: Constructs an object of type `year_lastweek_weekday` by constructing `y_` with `y`, and `wd_` with `wd`.

>     year_lastweek_weekday& year_lastweek_weekday::operator+=(const years& y) noexcept;

> > Effectx: `*this = *this + y`.

> > Returns: `*this`.

>     year_lastweek_weekday& year_lastweek_weekday::operator-=(const years& y) noexcept;

> > Effectx: `*this = *this - y`.

> > Returns: `*this`.

>     constexpr iso_week::year year_lastweek_weekday::year() const noexcept;

> > Returns: `y_`.

>     constexpr iso_week::weeknum year_lastweek_weekday::weeknum() const noexcept;

> > Returns: `(y_ / last).weeknum()`.

>     constexpr iso_week::weekday year_lastweek_weekday::weekday() const noexcept;

> > Returns: `wd_`.

>     constexpr year_lastweek_weekday::operator sys_days() const noexcept;

> > Returns: A `sys_days` which represents the date represented by `*this`.

>     constexpr bool year_lastweek_weekday::ok() const noexcept;

> > Returns: `y_.ok() && wd_.ok()`.

>     constexpr bool operator==(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;

> > Returns: `x.year() == y.year() && x.weekday() == y.weekday()`.

>     constexpr bool operator!=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;

> > Returns: `!(x == y)`.

>     constexpr bool operator<(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;

> > Returns: `x.year() < y.year() ? true : (x.year() > y.year() ? false : (unsigned{x.weekday()} < unsigned{y.weekday()}))`.

>     constexpr bool operator>(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;

> > Returns: `y < x`.

>     constexpr bool operator<=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;

> > Returns: `!(y < x)`.

>     constexpr bool operator>=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept;

> > Returns: `!(x < y)`.

>     constexpr year_lastweek_weekday operator+(const year_lastweek_weekday& x, const years& y) noexcept;

> > Returns: `(x.year() + y) / last / x.weekday()`.

>     constexpr year_lastweek_weekday operator+(const years& y, const year_lastweek_weekday& x) noexcept;

> > Returns: `x + y`.

>     constexpr year_lastweek_weekday operator-(const year_lastweek_weekday& x, const years& y) noexcept;

> > Returns: `x + -y`.

>     std::ostream& operator<<(std::ostream& os, const year_lastweek_weekday& x);

> > Effects: `os << x.year() << "-W last-" << x.weekday()`.

> > Returns: `os`.

### date composition operators

> To understand this API it is not necessary for you to memorize each of these operators. Indeed, that would be detrimental to understanding this API. Instead it is sufficient to known that this collection of operators implement constructions in 3 orders:

> 1. `year/weeknum/weekday`
> 2. `weeknum/weekday/year`
> 3. `weekday/weeknum/year`

> The first component in each order must be properly typed, the following components may be specified with the proper type or an `int`.

> Anywhere a "weeknum" is required one can also specify `last` to indicate the last week of the year.

> Sub-field-types such as `year_weeknum` and `weeknum_weekday` can be created by simply not applying the second division operator for any of the three orders. For example:

> >     year_weeknum ym = 2015_y/52_w;
> >     weeknum_weekday md1 = 52_w/thu;
> >     weeknum_weekday md2 = thu/52_w;

> Everything not intended as above is caught as a compile-time error, with the notable exception of an expression that consists of nothing but `int`, which of course has type `int`.

> >     auto a = 2015/4/4;       // a == int(125)
> >     auto b = 2015_y/4/4;     // b == year_weeknum_weekday{year(2015), week(4), weekday(4)}
> >     auto c = 2015_y/thu/4_w; // error: invalid operands to binary expression ('iso_week::year' and 'iso_week::weekday')
> >     auto d = 2015/4_w/4;     // error: invalid operands to binary expression ('int' and 'const iso_week::weeknum')

> The last example may be clear to a human reader. But the compiler doesn't know if `2015` refers to a `year` or a `weekday`. Instead of guessing, the compiler flags it as an error.

> In short, you will either write unambiguous and readable code, or you will get a compile-time error.

> `year_weeknum`:

>     constexpr year_weeknum operator/(const year& y, const weeknum& wn) noexcept;

> > Returns: `{y, wn}`.

>     constexpr year_weeknum operator/(const year& y, int wn) noexcept;

> > Returns: `y / weeknum(wn)`.

> `year_lastweek`:

>     constexpr year_lastweek operator/(const year& y, last_week) noexcept;

> > Returns: `year_lastweek{y}`.

> `weeknum_weekday`:

>     constexpr weeknum_weekday operator/(const weeknum& wn, const weekday& wd) noexcept;

> > Returns: `{wn, wd}`.

>     constexpr weeknum_weekday operator/(const weeknum& wn, int wd) noexcept;

> > Returns: `wn / weekday{static_cast<unsigned>(wd)}`.

>     constexpr weeknum_weekday operator/(const weekday& wd, const weeknum& wn) noexcept;

> > Returns: `wn / wd`.

>     constexpr weeknum_weekday operator/(const weekday& wd, int wn) noexcept;

> > Returns: `weeknum{static_cast<unsigned>(wn)} / wd`.

> `lastweek_weekday`:

>     constexpr lastweek_weekday operator/(const last_week&, const weekday& wd) noexcept;

> > Returns: `lastweek_weekday{wd}`.

>     constexpr lastweek_weekday operator/(const last_week& wn, int wd) noexcept;

> > Returns: `wn / weekday{static_cast<unsigned>(wd)}`.

>     constexpr lastweek_weekday operator/(const weekday& wd, const last_week& wn) noexcept;

> > Returns: `wn / wd`.

> `year_weeknum_weekday`:

>     constexpr year_weeknum_weekday operator/(const year_weeknum& ywn, const weekday& wd) noexcept;

> > Returns: `{ywn.year(), ywn.weeknum(), wd}`.

>     constexpr year_weeknum_weekday operator/(const year_weeknum& ywn, int wd) noexcept;

> > Returns: `ywn / weekday{static_cast<unsigned>(wd)}`.

>     constexpr year_weeknum_weekday operator/(const weeknum_weekday& wnwd, const year& y) noexcept;

> > Returns: `{y, wnwd.weeknum(), wnwd.weekday()}`.

>     constexpr year_weeknum_weekday operator/(const weeknum_weekday& wnwd, int y) noexcept;

> > Returns: `wnwd / year{y}`.

> `year_lastweek_weekday`:

>     constexpr year_lastweek_weekday operator/(const year_lastweek& ylw, const weekday& wd) noexcept;

> > Returns: `{ylw.year(), wd}`.

>     constexpr year_lastweek_weekday operator/(const year_lastweek& ylw, int wd) noexcept;

> > Returns: `ylw / weekday{static_cast<unsigned>(wd)}`.

>     constexpr year_lastweek_weekday operator/(const lastweek_weekday& lwwd, const year& y) noexcept;

> > Returns: `{y, lwwd.weekday()}`.

>     constexpr year_lastweek_weekday operator/(const lastweek_weekday& lwwd, int y) noexcept;

> > Returns: `lwwd / year{y}`.