iso_week
This paper fully documents an
ISO week date calendar
that is fully interoperable with
date.
This entire library is implemented in a single header: iso_week.h and is open source using the MIT license.
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!
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.
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
daysis astd::chrono::durationwith a tick period of 24 hours. This definition is not an SI unit but is accepted for use with SI.daysis the resultant type when subtracting twosys_dayss.using days = std::chrono::duration <int, std::ratio_multiply<std::ratio<24>, std::chrono::hours::period>>;
weeks
weeksis astd::chrono::durationwith a tick period of 7 days. This definition is widely recognized and predates the Gregorian calendar. It is consistent with ISO 8601.weekswill implicitly convert todaysbut not vice-versa.using weeks = std::chrono::duration <int, std::ratio_multiply<std::ratio<7>, days::period>>;
years
yearsis astd::chrono::durationwith a tick period of 365.2425 days. This definition accurately describes the length of the average year in the ISO week calendar.yearsis the resultant type when subtracting twoyearfield-based time points.yearsis not implicitly convertible todaysorweeksnor vice-versa.using years = std::chrono::duration <int, std::ratio_multiply<std::ratio<146097, 400>, days::period>>;
sys_days
sys_daysis astd::chrono::time_pointusingstd::chrono::system_clockanddays. This makessys_daysinteroperable withstd::chrono::system_clock::time_point. It is simply a count of days since the epoch ofstd::chrono::system_clockwhich in every implementation is Jan. 1, 1970.sys_daysis a serial-based time point with a resolution ofdays.using sys_days = std::chrono::time_point<std::chrono::system_clock, days>;
last_week
last_weekis astructthat isCopyConstructible. There exists aconstexprinstance oflast_weeknamedlast. 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
explicitqualifier 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 tolast_week. This addresses the concern expressed in LWG 2510.
weekdaySynopsis
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 literalsOverview
weekdayrepresents 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 anyunsignedvalue, which will be subsequently truncated to fit intoweekday's internal storage.weekdayis equality comparable.weekdayis 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. Howeverweekday'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 aweekdayfor debugging purposes.weekdayhas explicit conversions to and fromunsigned. There are 7weekdayconstants, one for each day of the week.A
weekdaycan be implicitly constructed from asys_days. This is the computation that discovers the day of the week of an arbitrary date.A
weekdaycan be implicitly converted to or from adate::weekday.iso_week::weekdayanddate::weekdayare distinct types, though they represent very similar concepts.date::weekdaycan be indexed, andiso_week::weekdaycan not.date::weekdayis encoded as [0, 6] representing [Sunday, Saturday], whileiso_week::weekdayis encoded as [1, 7] representing [Monday, Sunday]. The conversion functions will correctly translate between these encodings.Specification
weekdayis a trivially copyable class type.weekdayis a standard-layout class type.weekdayis a literal class type.explicit constexpr weekday::weekday(unsigned wd) noexcept;Effects: Constructs an object of type
weekdayby constructingwd_withwd.constexpr weekday(const sys_days& dp) noexcept;Effects: Constructs an object of type
weekdayby computing what day of the week corresponds to thesys_days dp, and representing that day of the week inwd_.Example: If
dprepresents 1970-01-01, the constructedweekdayshall represent Thursday by storing 4 inwd_.constexpr weekday(date::weekday wd) noexcept;Effects: Constructs an object of type
weekdayfrom adate::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 setswd_to 0.Returns:
*this.weekday weekday::operator++(int) noexcept;Effects:
++(*this).Returns: A copy of
*thisas it existed on entry to this member function.weekday& weekday::operator--() noexcept;Effects: If
wd_ != 0,--wd_. Otherwise setswd_to 6.Returns:
*this.weekday weekday::operator--(int) noexcept;Effects:
--(*this).Returns: A copy of
*thisas 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::weekdayconstructed 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
weekdayfor whichok() == trueand is found as if by incrementing (or decrementing ify < days{0})x,ytimes. Ifweekday.ok() == falseprior to this operation, behaves as if*thisis first brought into the range [1, 7] by modular arithmetic. [Note: For exampleweekday{0}becomesweekday{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() == trueandy.ok() == true.Returns: A value of
daysin the range ofdays{0}todays{6}inclusive.Remarks: The returned value
dshall satisfy the equality:y + d == x.Example:
sat - sun == days{6}.std::ostream& operator<<(std::ostream& os, const weekday& wd);Effects: If
ok() == trueoutputs the same string that would be output for the weekday field byasctime, assuming the conversionunsigned{date::weekday{*this}}. Otherwise outputsunsigned{wd} << " is not a valid weekday".Returns:
os.
weeknumSynopsis
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
weeknumrepresents 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 anyunsignedvalue, which will be subsequently truncated to fit intoweeknum's internal storage.weeknumis equality and less-than comparable, and participates in basic arithmetic withweeksrepresenting the quantity between any twoweeknum's. One can stream out aweeknumfor debugging purposes.weeknumhas explicit conversions to and fromunsigned.Specification
weeknumis a trivially copyable class type.weeknumis a standard-layout class type.weeknumis a literal class type.explicit constexpr weeknum::weeknum(unsigned wn) noexcept;Effects: Constructs an object of type
weeknumby constructingwn_withwn.weeknum& weeknum::operator++() noexcept;Effects:
++wn_.Returns:
*this.weeknum weeknum::operator++(int) noexcept;Effects:
++(*this).Returns: A copy of
*thisas 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
*thisas 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_wis output asW05.constexpr weeknum operator "" _w(unsigned long long wn) noexcept;Returns:
weeknum{static_cast<unsigned>(wn)}.
yearSynopsis
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
yearrepresents a year in the ISO week date calendar. It shall represent values in the range[min(), max()]. It can be constructed with anyintvalue, which will be subsequently truncated to fit intoyear's internal storage.yearis equality and less-than comparable, and participates in basic arithmetic withyearsrepresenting the quantity between any twoyear's. One can form ayearliteral with_y. And one can stream out ayearfor debugging purposes.yearhas explicit conversions to and fromint.Specification
yearis a trivially copyable class type.yearis a standard-layout class type.yearis a literal class type.explicit constexpr year::year(int y) noexcept;Effects: Constructs an object of type
yearby constructingy_withy.year& year::operator++() noexcept;Effects:
++y_.Returns:
*this.year year::operator++(int) noexcept;Effects:
++(*this).Returns: A copy of
*thisas 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
*thisas 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
yearconstructed with the minimum representable year number. This year shall be a value such thatsys_days{min()/1_w/mon} + Unit{0}, whereUnitis one ofmicroseconds,milliseconds,seconds,minutes, orhours, there shall be no overflow. [Note:nanosecondsis intentionally omitted from this list. — end note]static constexpr year year::max() noexcept;Returns: A
yearconstructed with the maximum representable year number. This year shall be a value such thatsys_days{max()/last/sun} + Unit{0}, whereUnitis one ofmicroseconds,milliseconds,seconds,minutes, orhours, there shall be no overflow. [Note:nanosecondsis 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
yintoos. 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_weeknumSynopsis
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_weeknumis simply a collection of ayearand aweeknum. It represents a specific week of a year, but not the day of the week. One can perform year-oriented arithmetic with ayear_weeknum. Andyear_weeknumis equality and less-than comparable.Specification
year_weeknumis a trivially copyable class type.year_weeknumis a standard-layout class type.year_weeknumis 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_weeknumby constructingy_withyandwn_withwn.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_lastweekSynopsis
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_lastweekrepresents a ISO weekyearand the last week of that year. One can perform year-oriented arithmetic with ayear_lastweek. Andyear_lastweekis equality and less-than comparable.Specification
year_lastweekis a trivially copyable class type.year_lastweekis a standard-layout class type.year_lastweekis a literal class type.explicit constexpr year_lastweek::year_lastweek(const iso_week::year& y) noexcept;Effects: Constructs an object of type
year_lastweekby constructingy_withy.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_weekdaySynopsis
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_weekdayis simply a collection of aweeknumand aweekday. It represents a specific week and day of the week, but an unspecified year.weeknum_weekdayis equality and less-than comparable.Specification
weeknum_weekdayis a trivially copyable class type.weeknum_weekdayis a standard-layout class type.weeknum_weekdayis 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_weekdayby constructingwn_withwnandwd_withwd.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_weekdaySynopsis
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_weekdayrepresents a weekday in the last week of an unspecified year.lastweek_weekdayis equality and less-than comparable.Specification
lastweek_weekdayis a trivially copyable class type.lastweek_weekdayis a standard-layout class type.lastweek_weekdayis a literal class type.explicit constexpr lastweek_weekday::lastweek_weekday(const iso_week::weekday& wd) noexcept;Effects: Constructs an object of type
lastweek_weekdayby constructingwd_withwd.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_weekdaySynopsis
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_weekdayrepresents ayear,weeknum, andweekdayin the ISO week date calendar. One can observe each field.year_weeknum_weekdaysupports year-oriented arithmetic. There is an implicit conversion to and fromsys_days. There is also an implicit conversion fromyear_lastweek_weekday.year_weeknum_weekdayis equality and less-than comparable.Specification
year_weeknum_weekdayis a trivially copyable class type.year_weeknum_weekdayis a standard-layout class type.year_weeknum_weekdayis 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_weekdayby constructingy_withy,wn_withwn, andwd_withwd.constexpr year_weeknum_weekday::year_weeknum_weekday(const year_lastweek_weekday& x) noexcept;Effects: Constructs an object of type
year_weeknum_weekdayby constructingy_withx.year(),wn_withx.weeknum(), andwd_withx.weekday().constexpr year_weeknum_weekday::year_weeknum_weekday(const sys_days& dp) noexcept;Effects: Constructs an object of type
year_weeknum_weekdaywhich corresponds to the date represented bydp.Remarks: For any value of
year_weeknum_weekday,x, for whichx.ok()istrue, this equality will also betrue: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_dayswhich 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_weekdaySynopsis
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_weekdayrepresents ayear, andweekdayin the last week of the ISO week date calendar. One can observe each field.year_lastweek_weekdaysupports year-oriented arithmetic. There is an implicit conversion tosys_days.year_lastweek_weekdayis equality and less-than comparable.Specification
year_lastweek_weekdayis a trivially copyable class type.year_lastweek_weekdayis a standard-layout class type.year_lastweek_weekdayis 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_weekdayby constructingy_withy, andwd_withwd.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_dayswhich 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.
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:
year/weeknum/weekdayweeknum/weekday/yearweekday/weeknum/yearThe 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
lastto indicate the last week of the year.Sub-field-types such as
year_weeknumandweeknum_weekdaycan 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 typeint.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
2015refers to ayearor aweekday. 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}.