From 105bd7df89d78c41c73ace6c30cd71b5f4312ab5 Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Wed, 4 May 2016 20:43:02 -0400 Subject: [PATCH] Initial commit --- date.html | 6628 +++++++++++++++++++++++++++++++++++++++++++++++++ iso_week.html | 2924 ++++++++++++++++++++++ tz.html | 2106 ++++++++++++++++ 3 files changed, 11658 insertions(+) create mode 100644 date.html create mode 100644 iso_week.html create mode 100644 tz.html diff --git a/date.html b/date.html new file mode 100644 index 0000000..d01eefe --- /dev/null +++ b/date.html @@ -0,0 +1,6628 @@ + + + + date + + + + + +
+
+
+Howard E. Hinnant
+2015-09-19
+ Creative
+Commons License
This work is licensed +under a Creative +Commons Attribution 4.0 International License. +
+
+

date

+ +

Contents

+ + + +

Introduction

+ +

+This paper fully documents a date and time library for use with C++11 and C++14. +

+ +

Implementation

+ +

+This entire library is implemented in a single header: +date.h and is +open source (with generous open source terms — not generous enough? Contact me, I'm +flexible). +

+ +

+It uses the algorithms from +chrono-Compatible Low-Level Date Algorithms. +If you want detailed explanations of the algorithms, go there. +

+ +

+It performs best with C++14, which has vastly improved constexpr rules. +However, the library will auto-adopt to C++11, sacrificing several constexpr +declarations. In C++11, this will effectively transfer some computations that should be +done at compile-time to run-time. Porting to C++98/03 has not been attempted. +

+ +

Overview

+ +

+This library builds date and date/time support on top of the <chrono> +library. However it does not support timezones nor leap seconds. A +separate library is provided, built on top of this one, for timezone +and leap second support. Thus you only pay for such support if you need it. +

+ +

Major Concepts

+ +

+A date on a calendar is a time point with a resolution of one day. This is not +conceptually different from std::chrono::system_clock::time_point which is a +time point with a resolution of std::chrono::system_clock::period (typically +on the order of a microsecond or nanosecond). Time points are divided into two basic +types: +

+ +
    +
  1. serial-based
  2. +
  3. field-based
  4. +
+ +

+This terminology is gratefully borrowed from +N3344. In +short, a serial-based time point stores a single count of time durations from some epoch. +std::chrono::system_clock::time_point is an example of a serial-based +time point. A count of days from some epoch is also a serial-based time point. +A field-based time point represents the same concept, but with several fields that +are typically used for human consumption. For example one might represent the time of day +with the number of seconds since midnight (serial-based), or with a structure such +as {hours, minutes, seconds} since midnight (field-based). Similarly +one can represent a date with a count of days, or with a {year, month, day} +structure. Both representations are useful, and each has its strengths and weaknesses. +

+ +

Major Types

+ +

+This library is composed of many types. But here are the most important ones: +

+ +
    +
  1. day_point: A count of days since system_clock's epoch. This +is a serial-based time point with a resolution of one day.
  2. +
  3. year_month_day: A type that holds a year (e.g. 2015), a month +(encoded as 1 thru 12), and a day (encoded as 1 thru 31). This is a field-based time +point with a resolution of one day.
  4. +
  5. year_month_weekday: A type that holds a year (e.g. 2015), a month +(encoded as 1 thru 12), a day of the week (encoded as 0 thru 6), and an index in the range +[1, 5] indicating if this is the first, second, etc. weekday of the indicated month. This +is a field-based time point with a resolution of one day.
  6. +
  7. +year_month: A type that holds a year and a month. This is a field-based +time point with a resolution of one month. This time point implements month-based +arithmetic, which other field-based time points can reuse. +
  8. +
+ +

Examples

+ +

+The entire library is in namespace date. The examples in this +overview assume: +

+ +
+using namespace date;
+using namespace std::chrono;
+
+ +

+in order to cut down on the verbosity. +

+ +

Example: Constructing dates

+ +year_month_day + +

+constexpr dates can be constructed from literals in any one of 3 orders: +

+ +
+constexpr auto x1 = 2015_y/mar/22;
+constexpr auto x2 = mar/22/2015;
+constexpr auto x3 = 22_d/mar/2015;
+
+ +

+x1, x2 and x3 all have the type: +year_month_day, and are all equal to one another. Any other order, +or any ambiguity is caught at compile time. These three orders were chosen +because these are the +three orders that people actually use. +

+ +

+Integral types can be converted to year, month, or +day to create run time values: +

+ +
+int y = 2015;
+int m = 3;
+int d = 22;
+auto x1 = year(y)/m/d;
+auto x2 = month(m)/d/y;
+auto x3 = day(d)/m/y;
+
+ +

+As long as the type of the first date component is known, the following components become +unambiguous and can be formed either with the proper type, or with an int +expression. And since there is only one order with day in the middle, that +order need only properly type the day to remain unambiguous: +

+ +
+auto x = m/day(d)/y;
+
+ +

+No matter the order of the year, month and +day specifiers, and no matter whether some of the fields implicitly +convert from int, the type of these expressions is +year_month_day. However because of auto, it is very +often unimportant how to spell the somewhat verbose type name +year_month_day. The compiler knows how to spell the type, and the +meaning is clear to the human reader without an explicit type. +

+ +

+If there is any ambiguity, the code will not compile. If the code +does compile, it will be unambiguous and quite readable. +

+ +year_month_day_last + +

+Anywhere you can specify a day you can instead specify last +to indicate the last day of the month for that year: +

+ +
+constexpr auto x1 = 2015_y/feb/last;
+constexpr auto x2 = feb/last/2015;
+constexpr auto x3 = last/feb/2015;
+
+ +

+Instead of constructing a year_month_day, these expressions construct a +year_month_day_last. This type always represents the last day of a +year and month. year_month_day_last will +implicitly convert to year_month_day. Note though that because of +auto both the reader and the writer of the code can very often remain +blissfully ignorant of the spelling of year_month_day_last. The API of +year_month_day and year_month_day_last are virtually identical +so that the learning curve is shallow, and generic code usually does not need to know +which type it is operating on. +

+ +year_month_weekday + +

+Anywhere you can specify a day you can instead specify an indexed +weekday to indicate the nth weekday of the month for that year: +

+ +
+constexpr auto x1 = 2015_y/mar/sun[4];
+constexpr auto x2 = mar/sun[4]/2015;
+constexpr auto x3 = sun[4]/mar/2015;
+
+ +

+The type constructed is year_month_weekday which will implicitly convert to +and from a day_point. If you want to convert to a +year_month_day you can do so explicitly, which will implicitly convert to +day_point and back: +

+ +
+constexpr auto x4 = year_month_day(x3);
+
+ +year_month_weekday_last + +

+weekday's can be indexed with last and used as above: +

+ +
+constexpr auto x1 = 2015_y/mar/sun[last];
+constexpr auto x2 = mar/sun[last]/2015;
+constexpr auto x3 = sun[last]/mar/2015;
+constexpr auto x4 = year_month_day(x3);
+cout << x3 << '\n';
+cout << x4 << '\n';
+
+ +

+This creates an object of type year_month_weekday_last. The above code +outputs: +

+ +
+2015/Mar/Sun[last]
+2015-03-29
+
+ +Escape hatch from the cute syntax + +

+If you hate the cute syntax, don't use it. Every type has a descriptive name, +and public type-safe constructors to do the same job. The "cute syntax" is a +non-friended and zero-abstraction-penalty layer on top of a complete lower-level +API. +

+ +
+constexpr auto x1 = 2015_y/mar/sun[last];
+constexpr auto x2 = year_month_weekday_last(year(2015), month(3), weekday_last(weekday(0)));
+static_assert(x1 == x2,                                   "No matter the API, x1 and x2 have the same value ...");
+static_assert(is_same<decltype(x1), decltype(x2)>::value, "... and are the same type");
+cout << x1 << '\n';
+cout << x2 << '\n';
+
+2015/Mar/Sun[last]
+2015/Mar/Sun[last]
+
+ +

Example: Today

+ +

+To get today as a day_point, use system_clock::now() and +floor to convert the time_point to a +day_point: +

+ +
+auto today = floor<days>(system_clock::now());
+cout << today << '\n';
+
+ +

+Currently this outputs for me: +

+ +
+2015-03-22
+
+ +

+To get today as a year_month_day, get a day_point as above and +convert it to a year_month_day: +

+ +
+auto today = year_month_day{floor<days>(system_clock::now())};
+cout << today << '\n';
+
+ +

+Which again currently outputs for me: +

+ +
+2015-03-22
+
+ +

+To get today as a year_month_weekday, get a day_point as above and +convert it to a year_month_weekday: +

+ +
+auto today = year_month_weekday{floor<days>(system_clock::now())};
+cout << today << '\n';
+
+ +

+Currently this outputs for me: +

+ +
+2015/Mar/Sun[4]
+
+ +

+This indicates that today (2015-03-22) is the fourth Sunday of Mar., 2015. +

+ +

Example: Contrast with C

+ +

+Just about everything C++ has for date handling, it inherits from C. I thought it +would be fun to contrast an example that comes from the C standard with this library. +

+ +

+From the C standard: 7.27.2.3 The mktime function, paragraph 4: +

+ +
+

+EXAMPLE What day of the week is July 4, 2001? +

+ +
+#include <stdio.h>
+#include <time.h>
+
+static const char *const wday[] =
+{
+    "Sunday", "Monday", "Tuesday", "Wednesday",
+    "Thursday", "Friday", "Saturday", "-unknown-"
+};
+
+int
+main()
+{
+    struct tm time_str;
+    time_str.tm_year   = 2001 - 1900;
+    time_str.tm_mon    = 7 - 1;
+    time_str.tm_mday   = 4;
+    time_str.tm_hour   = 0;
+    time_str.tm_min    = 0;
+    time_str.tm_sec    = 0;
+    time_str.tm_isdst  = -1;
+    if (mktime(&time_str) == (time_t)(-1))
+        time_str.tm_wday = 7;
+    printf("%s\n", wday[time_str.tm_wday]);
+}
+
+ +
+ +

+This program outputs: +

+ +
+Wednesday
+
+ +

+Coding the same problem up in this library looks like: +

+ +
+#include "date.h"
+#include <iostream>
+
+int
+main()
+{
+    using namespace date;
+    std::cout << weekday(jul/4/2001) << '\n';
+}
+
+ +

+which outputs: +

+ +
+Wed
+
+ +

+And if we really want to show off, this can all be done at compile time: +

+ +
+#include "date.h"
+
+int
+main()
+{
+    using namespace date;
+    static_assert(weekday(2001_y/jul/4) == wed, "");
+}
+
+ +

+(Date ordering was switched simply to assure the gentle reader that we're not hung up on +m/d/y ordering.) +

+ +

Errors

+ +

+No exceptions are thrown in the entire library, except those that might be thrown from +std::ostream when streaming values to a std::ostream. Most of +the types have a constexpr const member function named ok() +which returns true if the object represents a valid date, or date component, +and otherwise returns false. However it is perfectly fine (and sometimes +actually useful) for these objects to contain invalid dates or date components. For +example, here is a very simple and remarkably efficient program to output the odd Fridays +of every month in 2015: +

+ +
+int
+main()
+{
+    using namespace std;
+    using namespace date;
+    for (auto m = 1; m <= 12; ++m)
+    {
+        auto meet = year_month_day(m/fri[1]/2015);
+        cout << meet << '\n';
+        meet = meet.year()/meet.month()/(meet.day()+weeks(2));
+        cout << meet << '\n';
+        meet = meet.year()/meet.month()/(meet.day()+weeks(2));
+        if (meet.ok())
+            cout << meet << '\n';
+    }
+}
+
+ +

+There is a relatively expensive (expense is relative here — maybe as much as 100ns) +conversion from year_month_weekday to year_month_day at the top +of the loop to find the first Friday of the month. This computation can never fail. And +after that it is dirt cheap to find the 3rd Friday — you just have to add 2 weeks to +the day field. This computation also can never fail. And it is similarly cheap to find +the 5th Friday of each month. However, not every month has a fifth Friday. But +nevertheless it is ok to form such a year_month_day. The computation can +never fail, though it may render an invalid date. Afterwards one can simply ask: Did I +create a valid date? If so, print it out, otherwise just continue on. +

+ +

+This program is easy to read, easy to write, will fail to compile if any careless errors +are made, and extremely high performance. The date computations are dwarfed by the run +time costs of the I/O. +

+ +

+Because practically nothing throws exceptions, this entire library is liberally sprinkled +with noexcept. +

+ +

+A few of the operations have a precondition that ok() == true. These are +generally conversions to day_point, and month-oriented and weekday-oriented +arithmetic. Anywhere there is a precondition, and those places are few, the precondition +is checkable with ok(). +

+ +

+This library catches many errors (especially ambiguity errors) at compile time. What's +left over is left up to ok(). Sometimes !ok() will represent an +error, and other times it will simply represent something innocuous that can be ignored +(such as in the example above). If !ok() actually represents an error that +must be dealt with, the choice of whether to assert or throw is made by the client of +this library. +

+ +

Efficiency

+ +

+In N3344 +Pacifico, Meredith and Lakos present a thorough survey of date types and their performance. +This library has been strongly influenced by this excellent paper. +year_month_day is equivalent to what N3344 terms YMD_4. And +day_point is equivalent to what N3344 terms HH_SERIAL_RAW_4. +

+ +

+N3344 +aptly demonstrates that field-based date structures are good at some operations and poor +at others. And serial-based implementations are generally good at what the field-based +data structures are poor at, and poor at what the field-based data structures are good at. + Indeed, this is the genesis of the design of this library: Provide both data structures +and let the conversions among the data structures be provided by algorithms as shown in +chrono-Compatible Low-Level Date Algorithms. +And additionally, just provide the API for each data structure that it can do efficiently. +

+ + + +

+To demonstrate the efficiency of constructing a year_month_day, a hypothetical +factory function has been created in the table below. And this is compared with a +simplistic struct YMD_4 and an obvious factory function for that. Each is +compiled using clang at an optimization of -O2 or higher. +

+ +
+ + + + + + + + + + + + + + + + + +
year_month_day constructor assembly
+
+date::year_month_day
+make_year_month_day(int y, int m, int d)
+{
+    using namespace date;
+    return year(y)/m/d;
+}
+
+
+
+struct YMD_4
+{
+    std::int16_t year;
+    std::uint8_t month;
+    std::uint8_t day;
+};
+
+YMD_4
+make_YMD_4(int y, int m, int d)
+{
+    return {static_cast<std::int16_t>(y),
+            static_cast<std::uint8_t>(m),
+            static_cast<std::uint8_t>(d)};
+}
+
+
+
+	.globl	__Z19make_year_month_dayiii
+	.align	4, 0x90
+__Z19make_year_month_dayiii:
+	.cfi_startproc
+## BB#0:
+	pushq	%rbp
+Ltmp2:
+	.cfi_def_cfa_offset 16
+Ltmp3:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+Ltmp4:
+	.cfi_def_cfa_register %rbp
+	shll	$24, %edx
+	shll	$16, %esi
+	andl	$16711680, %esi
+	movzwl	%di, %eax
+	orl	%edx, %eax
+	orl	%esi, %eax
+	popq	%rbp
+	retq
+	.cfi_endproc
+
+
+
+	.globl	__Z10make_YMD_4iii
+	.align	4, 0x90
+__Z10make_YMD_4iii:
+	.cfi_startproc
+## BB#0:
+	pushq	%rbp
+Ltmp2:
+	.cfi_def_cfa_offset 16
+Ltmp3:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+Ltmp4:
+	.cfi_def_cfa_register %rbp
+	shll	$24, %edx
+	shll	$16, %esi
+	andl	$16711680, %esi
+	movzwl	%di, %eax
+	orl	%esi, %eax
+	orl	%edx, %eax
+	popq	%rbp
+	retq
+	.cfi_endproc
+
+
+ +
+ +

+One can see that the generated assembler is virtually identical for these two factory +functions. I.e. the code size and run time overhead of the "cute syntax" for constructing +a year_month_day is zero, at least in optimized builds. +

+ +

+A similar experiment is made for constructing a day_point from a count of +days held in an int. To do this one must first create a days +duration, and then construct the day_point from the days +duration. This is contrasted with the very simplistic struct SERIAL_4. +

+ +
+ + + + + + + + + + + + + + + + + +
day_point constructor assembly
+
+date::day_point
+make_day_point(int z)
+{
+    using namespace date;
+    return day_point{days{z}};
+}
+
+
+
+struct SERIAL_4
+{
+    std::int32_t count;
+};
+
+SERIAL_4
+make_SERIAL_4(int z)
+{
+    return {z};
+}
+
+
+
+	.globl	__Z14make_day_pointi
+	.align	4, 0x90
+__Z14make_day_pointi:
+	.cfi_startproc
+## BB#0:
+	pushq	%rbp
+Ltmp2:
+	.cfi_def_cfa_offset 16
+Ltmp3:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+Ltmp4:
+	.cfi_def_cfa_register %rbp
+	movl	%edi, %eax
+	popq	%rbp
+	retq
+	.cfi_endproc
+
+
+
+	.globl	__Z13make_SERIAL_4i
+	.align	4, 0x90
+__Z13make_SERIAL_4i:
+	.cfi_startproc
+## BB#0:
+	pushq	%rbp
+Ltmp2:
+	.cfi_def_cfa_offset 16
+Ltmp3:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+Ltmp4:
+	.cfi_def_cfa_register %rbp
+	movl	%edi, %eax
+	popq	%rbp
+	retq
+	.cfi_endproc
+
+
+ +
+ +

+It is easy to see that the generated code is identical, and thus there is no overhead +associated with the day_point type. It is also noteworthy that the code for +this construction does not actually come from this date library, but instead +comes from your std::lib header <chrono>. days is nothing +but a type-alias for a std::chrono::duration, and +day_point is nothing but a type-alias for a +std::chrono::time_point (thus the inspiration for the name +day_point). So this is also evidence that there is zero overhead for the +type-safe system of the <chrono> library. +

+ + +

+One final example taken from real-world code. Below are two ways of implementing a system +which counts seconds since Jan. 1, 2000: One that uses this library and another that +simply stores the count of seconds in a long. A utility is needed to convert +that count to Unix Time, which simply +involves shifting the epoch to Jan. 1, 1970. +

+ +
+ + + + + + + + + + + + + + + + + +
Shift epoch from jan/1/2000 to jan/1/1970
+
+using time_point = std::chrono::time_point<std::chrono::system_clock,
+                                           std::chrono::seconds>;
+
+time_point
+shift_epoch(time_point t)
+{
+    using namespace date;
+    return t + (day_point(jan/1/2000) - day_point(jan/1/1970));
+}
+
+
+
+long
+shift_epoch(long t)
+{
+    return t + 946684800;
+}
+
+
+
+	.globl	__Z11shift_epochNSt3__16chrono10time_pointINS0...
+	.align	4, 0x90
+__Z11shift_epochNSt3__16chrono10time_pointINS0...
+	.cfi_startproc
+## BB#0:
+	pushq	%rbp
+Ltmp0:
+	.cfi_def_cfa_offset 16
+Ltmp1:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+Ltmp2:
+	.cfi_def_cfa_register %rbp
+	leaq	946684800(%rdi), %rax
+	popq	%rbp
+	retq
+	.cfi_endproc
+
+
+
+	.globl	__Z11shift_epochl
+	.align	4, 0x90
+__Z11shift_epochl:
+	.cfi_startproc
+## BB#0:
+	pushq	%rbp
+Ltmp0:
+	.cfi_def_cfa_offset 16
+Ltmp1:
+	.cfi_offset %rbp, -16
+	movq	%rsp, %rbp
+Ltmp2:
+	.cfi_def_cfa_register %rbp
+	leaq	946684800(%rdi), %rax
+	popq	%rbp
+	retq
+	.cfi_endproc
+
+
+ +
+ +

+On the left we have a strongly typed solution which makes it explicit that the code is +adding a time duration equal to the difference between the two epochs. Though verbose, +the code is easy to read. On the right we have the maximally efficient, and yet relatively +cryptic implementation with long. As it turns out, there are 946,684,800 +seconds between these two epochs ... who knew? +

+ +

+clang generates identical assembly for these two functions at -O2 and higher. That +is, the sub-expression (day_point(jan/1/2000) - day_point(jan/1/1970)) is +reduced down to a number of days (10,957) at compile time, and then this +sub-expression, which has type days is added to a time_point +with a resolution of seconds, which causes the compiler to convert +days{10957} to seconds{946684800}, again at compile time. +

+ +

+And in the strongly typed case, if in the future one decides that one wants to count +milliseconds instead of seconds, that can be changed in one place: +

+ +
+
+using time_point = std::chrono::time_point<std::chrono::system_clock,
+                                           std::chrono::milliseconds>;
+
+
+ +

+Upon recompile the compiler automatically updates the compile-time constant in +shift_epoch from 946684800 to 946684800000 (and everywhere else such as +where you perform the epoch shift in the reverse direction). +

+ +

What about a date-time type?

+ +

+You already have a good one. It is called +std::chrono::system_clock::time_point. And it is completely interoperable +with this library. std::chrono::system_clock::time_point is a pointer to +a particular instant of time, with high precision (that precision is specified differently +on each platform). As we saw earlier, one can get a high-precision time_point +representing now with: +

+ +
+auto tp = system_clock::now();
+
+ +

+This library provides a stream insertion operator for +system_clock::time_point (in namespace date). +

+ +
+std::cout << tp << '\n';
+
+ +

+This currently outputs for me: +

+ +
+2015-04-19 18:24:42.770911
+
+ +

+One can turn that into a time_point with the precision of a day (which +has a type alias called day_point) with: +

+ +
+auto dp = floor<days>(tp);
+
+ +

+And one can convert that day-oriented time_point into a +{year, month, day} field type with: +

+ +
+auto ymd = year_month_day(dp);
+
+ +

+This section explains how to extract the time of day from the above information. +dp can also be though of as a time_point to the beginning of the +current day (in the UTC timezone). And so one can get the time duration +since midnight by subtracting the day-precision time_point from the high +precision time_point: tp-dp. This results in a high precision +std::chrono::duration representing the time since midnight. +

+ +

+This high precision duration can be broken down into hours, minutes, seconds, +and fractions of a second with a time_of_day object, which is most easily +created by using the make_time factory function: +

+ +
+auto time = make_time(tp-dp);
+
+ +

+Now both ymd and time can simply be printed out: +

+ +
+std::cout << ymd << ' ' << time << '\n';
+
+ +

+Which will result in something like: +

+ +
+2015-04-19 18:24:42.770911
+
+ +

+Indeed, this is exactly what the stream insertion operator for +system_clock::time_point does. So if you don't like the default format, +this is how you pick apart a system_clock::time_point so you can output it +in whatever format you prefer. +

+ +

+The above is the current date and time in the UTC timezone with microsecond precision. +On the platform I'm writing this, system_clock::time_point counts +microseconds. When you run this code on your platform, the library will automatically +adapt to the precision supported by your platform's implementation of +system_clock::time_point. +

+ +

+If you prefer output in a local time zone, you will need to discover your current UTC +offset and add that to tp prior to applying floor. +Your current UTC offset is a function of both your UTC time point tp, and +your location. This functionality is not offered by this library, but can be built on top +of it. For example here is such a library. But as a simplistic +example, here is code that assumes an Eastern US location and daylight savings rules +currently in effect: +

+ +
+std::chrono::hours
+utc_offset_Eastern_US(std::chrono::system_clock::time_point tp)
+{
+    using namespace date;
+    using namespace std::chrono;
+    constexpr auto EST = -5h;
+    constexpr auto EDT = -4h;
+    const auto y = year_month_day(floor<days>(tp)).year();
+    const auto begin = day_point(sun[2]/mar/y) + 2h - EST; // EDT begins at this UTC time
+    const auto end   = day_point(sun[1]/nov/y) + 2h - EDT; // EST begins at this UTC time
+    if (tp < begin || end <= tp)
+        return EST;
+    return EDT;
+}
+...
+auto tp = system_clock::now();
+tp += utc_offset_Eastern_US(tp);                // tp now in Eastern US timezone
+std::cout << tp << '\n';
+
+2015-04-19 14:24:42.770911
+
+ +

+And if you prefer your output in a 12-hour format with a precision of only minutes, that +is also easily accomplished: +

+ +
+auto tp = system_clock::now();
+tp += utc_offset_Eastern_US(tp);
+const auto tpm = floor<minutes>(tp);            // truncate to minutes precision
+const auto dp = floor<days>(tpm);
+const auto ymd = year_month_day(dp);
+auto time = make_time(tpm-dp);                  // minutes since midnight
+time.make12();                                  // change to 12-hour format
+std::cout << ymd << ' ' << time << '\n';
+
+2015-04-19 2:24pm
+
+ +

Extensibility

+ +

+The hub of this library is day_point. This is a serial-based time +point which simply counts the days since (or before) jan/1/1970. And +ironically this all important hub is nothing but a type alias to a std-defined type. That +is, the central theme this library is built around is nothing more than this: +

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

+Types such as year_month_day and year_month_weekday provide +implicit conversions to and from day_point, and because of this, the C++ +language provides explicit conversions between year_month_day and +year_month_weekday. +

+ +

+You can easily build your own types that implicitly convert to and from +day_point, and when you do, you automatically gain explicit convertibility to +and from every other type which ties into day_point. For example, here is +how you could create a custom type that models the ISO week-based calendar: +

+ +
+class iso_week
+{
+    date::year    y_;
+    date::weeks   w_;
+    date::weekday wd_;
+
+public:
+    constexpr iso_week(date::day_point dp) noexcept
+        : iso_week(iso_week_from_day_point(dp))
+        {}
+
+    constexpr iso_week(date::year y, date::weeks w, date::weekday wd) noexcept
+        : y_(y)
+        , w_(w)
+        , wd_(wd)
+        {}
+
+    constexpr operator date::day_point() const noexcept
+    {
+        using namespace date;
+        return iso_week_start(y_) + w_ - weeks{1} + (wd_ - mon);
+    }
+
+    friend std::ostream& operator<<(std::ostream& os, const iso_week& x)
+    {
+        return os << x.y_ << "-W(" << x.w_.count() << ")-" << x.wd_;
+    }
+
+private:
+    static
+    constexpr
+    date::day_point
+    iso_week_start(date::year y) noexcept
+    {
+        using namespace date;
+        return day_point(thu[1]/jan/y) - (thu-mon);
+    }
+
+    static
+    constexpr
+    iso_week
+    iso_week_from_day_point(date::day_point dp) noexcept
+    {
+        using namespace date;
+        using namespace std::chrono;
+        auto y = year_month_day(dp).year();
+        auto start = iso_week_start(y);
+        if (dp < start)
+        {
+            --y;
+            start = iso_week_start(y);
+        }
+        else
+        {
+            auto const next_start = iso_week_start(y+years{1});
+            if (dp >= next_start)
+            {
+                ++y;
+                start = next_start;
+            }
+        }
+        return {y, duration_cast<weeks>(dp - start) + weeks{1}, weekday{dp}};
+    }
+};
+
+ +

+The rules for the ISO week-based calendar are fairly simple: +

+ +
    +
  1. Weeks begin with Monday and end on Sunday.
  2. +
  3. The year begins on the Monday prior to the first Thursday in January.
  4. +
  5. A date is specified by the week number [1 - 53], day of the week [Mon - Sun], and year +number.
  6. +
  7. The year number is the same as the civil year number for the Thursday that follows the +start of the week-based year.
  8. +
+ +

+With that in mind, one can easily create a field-based data structure that holds +a year, a week number, and a day of the week, and then provides conversions +to and from day_point. +

+ +

+The key points of this class (for interoperability) are the constructor +iso_week(date::day_point dp) and the operator date::day_point(). +

+ +

+To aid in these computations a private helper function is created to compute the +day_point corresponding to the first day of the week-based year. And according +to rule 2, this can be elegantly coded as: +

+ +
+return day_point(thu[1]/jan/y) - (thu-mon);
+
+ +

+That is, first find the first Thursday in January for year y, and then subtract +the number of days required to find the Monday before this day. This could have been done +with days{3}. But I chose to code this as (thu-mon). +Computationally and performance wise, these two choices are identical: they both subtract +the literal 3. I chose the latter because I believe it to be more readable. +"3" is just a magic constant. But "(thu-mon)" is the number of +days Thursday is past Monday. +

+ +

+The constructor iso_week(date::day_point dp) has to first discover which +ISO week-based year the day_point dp falls into. Most often this is the +same as the civil (year_month_day) year number associated dp. +But because the week-based year may start a few days earlier or later than +jan/1, the week-based year number may be one less or one greater than the +civil year number associated dp. Once the proper start of the week-based year +is nailed down (in start), the translation to the field-based +iso_week is trivial: +

+ +
+return {y, duration_cast<weeks>(dp - start) + weeks{1}, weekday{dp}};
+
+ +

+The conversion from iso_week to day_point is even easier: +

+ +
+return iso_week_start(y_) + w_ - weeks{1} + (wd_ - mon);
+
+ +

+It is the the start of the week-based year, plus the number of weeks (minus one since this +count is 1-based), plus the number of days the weekday is past Monday. Note +that because weekday subtraction is treated as a circular range (always +results in a number of days in the range [0, 6]), the logic at this level is simplified. +That is, Sunday is 6 days past Monday, not one day before it (and Monday is still one day +past Sunday). So the encoding used for weekday is irrelevant; safely +encapsulated within weekday. Said differently, weekday +arithmetic is unsigned, modulo 7. +

+ +

+With the above code, one can now write programs such as the one below which demonstrates +easy convertibility among the date field-types and your custom +field-type. +

+ +
+int
+main()
+{
+    using namespace date;
+    using namespace std;
+    using namespace std::chrono;
+    auto dp = floor<days>(system_clock::now());
+    auto ymd = year_month_day(dp);
+    cout << ymd << '\n';
+    auto iso = iso_week(ymd);
+    cout << iso << '\n';
+    auto ymwd = year_month_weekday(iso);
+    cout << ymwd << '\n';
+    assert(year_month_day(iso) == ymd);
+}
+
+ +

+Which will output something like: +

+ +
+2015-05-20
+2015-W(21)-Wed
+2015/May/Wed[3]
+
+ +

+As long as you can relate your custom field-based structure (be it the Julian +calendar, the Hindu calendar, or the Maya calendar) to the number of days before and after +civil 1970-01-01, you can achieve interoperability with every other field-based +structure that does so. And obviously you can then also convert your custom calendar to +UTC (std::chrono::system_clock::time_point). This is the Rosetta Stone of +time keeping. +

+ +

+For an example of a fully developed +ISO week date calendar +which is fully interoperable with this library via the technique described above see +iso_week. +

+ +

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
 months
 years
  
time_point 
 day_point
  
types 
 last_spec
  
 day
 month
 year
  
 weekday
 weekday_indexed
 weekday_last
  
 month_day
 month_day_last
 month_weekday
 month_weekday_last
  
 year_month
  
 year_month_day
 year_month_day_last
 year_month_weekday
 year_month_weekday_last
  
 time_of_day
  
date composition operators 
 constexpr year_month operator/(const year& y, const month& m) noexcept;
 constexpr year_month operator/(const year& y, int m) noexcept;
  
 constexpr month_day operator/(const month& m, const day& d) noexcept;
 constexpr month_day operator/(const month& m, int d) noexcept;
 constexpr month_day operator/(int m, const day& d) noexcept;
 constexpr month_day operator/(const day& d, const month& m) noexcept;
 constexpr month_day operator/(const day& d, int m) noexcept;
  
 constexpr month_day_last operator/(const month& m, last_spec) noexcept;
 constexpr month_day_last operator/(int m, last_spec) noexcept;
 constexpr month_day_last operator/(last_spec, const month& m) noexcept;
 constexpr month_day_last operator/(last_spec, int m) noexcept;
  
 constexpr month_weekday operator/(const month& m, const weekday_indexed& wdi) noexcept;
 constexpr month_weekday operator/(int m, const weekday_indexed& wdi) noexcept;
 constexpr month_weekday operator/(const weekday_indexed& wdi, const month& m) noexcept;
 constexpr month_weekday operator/(const weekday_indexed& wdi, int m) noexcept;
  
 constexpr month_weekday_last operator/(const month& m, const weekday_last& wdl) noexcept;
 constexpr month_weekday_last operator/(int m, const weekday_last& wdl) noexcept;
 constexpr month_weekday_last operator/(const weekday_last& wdl, const month& m) noexcept;
 constexpr month_weekday_last operator/(const weekday_last& wdl, int m) noexcept;
  
 constexpr year_month_day operator/(const year_month& ym, const day& d) noexcept;
 constexpr year_month_day operator/(const year_month& ym, int d) noexcept;
 constexpr year_month_day operator/(const year& y, const month_day& md) noexcept;
 constexpr year_month_day operator/(int y, const month_day& md) noexcept;
 constexpr year_month_day operator/(const month_day& md, const year& y) noexcept;
 constexpr year_month_day operator/(const month_day& md, int y) noexcept;
  
 constexpr year_month_day_last operator/(const year_month& ym, last_spec) noexcept;
 constexpr year_month_day_last operator/(const year& y, const month_day_last& mdl) noexcept;
 constexpr year_month_day_last operator/(int y, const month_day_last& mdl) noexcept;
 constexpr year_month_day_last operator/(const month_day_last& mdl, const year& y) noexcept;
 constexpr year_month_day_last operator/(const month_day_last& mdl, int y) noexcept;
  
 constexpr year_month_weekday operator/(const year_month& ym, const weekday_indexed& wdi) noexcept;
 constexpr year_month_weekday operator/(const year& y, const month_weekday& mwd) noexcept;
 constexpr year_month_weekday operator/(int y, const month_weekday& mwd) noexcept;
 constexpr year_month_weekday operator/(const month_weekday& mwd, const year& y) noexcept;
 constexpr year_month_weekday operator/(const month_weekday& mwd, int y) noexcept;
  
 constexpr year_month_weekday_last operator/(const year_month& ym, const weekday_last& wdl) noexcept;
 constexpr year_month_weekday_last operator/(const year& y, const month_weekday_last& mwdl) noexcept;
 constexpr year_month_weekday_last operator/(int y, const month_weekday_last& mwdl) noexcept;
 constexpr year_month_weekday_last operator/(const month_weekday_last& mwdl, const year& y) noexcept;
 constexpr year_month_weekday_last operator/(const month_weekday_last& mwdl, int y) noexcept;
  
time_of_day factory functions 
  +
+template <class Rep, class Period>
+constexpr
+time_of_day<std::chrono::duration<Rep, Period>>
+make_time(std::chrono::duration<Rep, Period> d) noexcept;
+
  +
+constexpr
+time_of_day<std::chrono::hours>
+make_time(std::chrono::hours h, unsigned md) noexcept;
+
  +
+constexpr
+time_of_day<std::chrono::minutes>
+make_time(std::chrono::hours h, std::chrono::minutes m, unsigned md) noexcept;
+
  +
+constexpr
+time_of_day<std::chrono::seconds>
+make_time(std::chrono::hours h, std::chrono::minutes m, std::chrono::seconds s,
+          unsigned md) noexcept;
+
  +
+template <class Rep, class Period,
+          class = std::enable_if_t<std::ratio_less<Period, std::ratio<1>>::value>>
+constexpr
+time_of_day<std::chrono::duration<Rep, Period>>
+make_time(std::chrono::hours h, std::chrono::minutes m, std::chrono::seconds s,
+          std::chrono::duration<Rep, Period> sub_s, unsigned md) noexcept
+
  +
+template <class Duration>
+inline
+std::ostream&
+operator<<(std::ostream& os,
+           const std::chrono::time_point<std::chrono::system_clock, Duration>& tp);
+
+ +

+Everything here is contained in the namespace date. The literal operators, +and the constexpr field literals (e.g. sun, jan, etc.) are +in namespace date_literals and imported into namespace date. +

+ +

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 +day_points. +

+
+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 +Gregorian 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. However +years will implicitly convert to months. +

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

months

+ +
+

+months is a std::chrono::duration with a tick period of +1/12 of a year. This definition accurately describes the length of +the average month in the Gregorian calendar. months is the resultant type +when subtracting two month field-based time points. months is +not implicitly convertible to days or weeks nor vice-versa. +months will not implicitly convert to years. +

+
+using months = std::chrono::duration
+    <int, std::ratio_divide<years::period, std::ratio<12>>>;
+
+ +

day_point

+ +
+

+day_point is a std::chrono::time_point using +std::chrono::system_clock and days. This makes +day_point 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. day_point is a serial-based time point with a resolution of +days. +

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

last_spec

+ +
+

+last_spec is a struct that is CopyConstructible. +There exists a constexpr instance of last_spec named +last. This is simply a tag type. It is used to indicate the last day of +a month, or the last weekday of a month. +

+
+constexpr struct last_spec {} last{};
+
+
+ +

day

+ +
+

Synopsis

+ +
+class day
+{
+    unsigned char d_;  // exposition only
+public:
+    explicit constexpr day(unsigned d) noexcept;
+
+    day& operator++() noexcept;
+    day operator++(int) noexcept;
+    day& operator--() noexcept;
+    day operator--(int) noexcept;
+
+    day& operator+=(const days& d) noexcept;
+    day& operator-=(const days& d) noexcept;
+
+    constexpr explicit operator unsigned() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const day& x, const day& y) noexcept;
+constexpr bool operator!=(const day& x, const day& y) noexcept;
+constexpr bool operator< (const day& x, const day& y) noexcept;
+constexpr bool operator> (const day& x, const day& y) noexcept;
+constexpr bool operator<=(const day& x, const day& y) noexcept;
+constexpr bool operator>=(const day& x, const day& y) noexcept;
+
+constexpr day  operator+(const day&  x, const days& y) noexcept;
+constexpr day  operator+(const days& x, const day&  y) noexcept;
+constexpr day  operator-(const day&  x, const days& y) noexcept;
+constexpr days operator-(const day&  x, const day&  y) noexcept;
+
+constexpr day operator "" _d(unsigned long long d) noexcept;
+std::ostream& operator<<(std::ostream& os, const day& d);
+
+ +

Overview

+ +

+day represents a day of a month. It should only be representing values in +the range 1 to 31. However it may hold values outside this range. It can be constructed +with any unsigned value, which will be subsequently truncated to fit into +day's internal storage. day is equality and less-than +comparable, and participates in basic arithmetic with days representing the +quantity between any two day's. One can form a day literal with +_d. And one can stream out a day for debugging purposes. +day has explicit conversions to and from unsigned. +

+ +

Specification

+ +

+day is a trivially copyable class type.
+day is a standard-layout class type.
+day is a literal class type.
+

+ +
+explicit constexpr day::day(unsigned d) noexcept;
+
+ +
+

+Effects: Constructs an object of type day by constructing +d_ with d. +

+
+ +
+day& day::operator++() noexcept;
+
+ +
+

+Effects: ++d_. +

+

+Returns: *this. +

+
+ +
+day day::operator++(int) noexcept;
+
+ +
+

+Effects: ++(*this). +

+

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

+
+ +
+day& day::operator--() noexcept;
+
+ +
+

+Effects: --d_. +

+

+Returns: *this. +

+
+ +
+day day::operator--(int) noexcept;
+
+ +
+

+Effects: --(*this). +

+

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

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

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

+

+Returns: *this. +

+
+ +
+day& day::operator-=(const days& d) noexcept;
+
+ +
+

+Effects: *this = *this - d. +

+

+Returns: *this. +

+
+ +
+constexpr explicit day::operator unsigned() const noexcept;
+
+ +
+

+Returns: d_. +

+
+ +
+constexpr bool day::ok() const noexcept;
+
+ +
+

+Returns: 1 <= d_ && d_ <= 31. +

+
+ +
+constexpr bool operator==(const day& x, const day& y) noexcept;
+
+ +
+

+Returns: unsigned{x} == unsigned{y}. +

+
+ +
+constexpr bool operator!=(const day& x, const day& y) noexcept;
+
+ +
+

+Returns: !(x == y). +

+
+ +
+constexpr bool operator< (const day& x, const day& y) noexcept;
+
+ +
+

+Returns: unsigned{x} < unsigned{y}. +

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

+Returns: y < x. +

+
+ +
+constexpr bool operator<=(const day& x, const day& y) noexcept;
+
+ +
+

+Returns: !(y < x). +

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

+Returns: !(x < y). +

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

+Returns: day{unsigned{x} + y.count()}. +

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

+Returns: y + x. +

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

+Returns: x + -y. +

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

+Returns: days{static_cast<days::rep>(unsigned{x} - unsigned{y})}. +

+
+ +
+constexpr day operator "" _d(unsigned long long d) noexcept;
+
+ +
+

+Returns: day{static_cast<unsigned>(d)}. +

+
+ +
+std::ostream& operator<<(std::ostream& os, const day& d);
+
+ +
+

+Effects: Inserts a decimal integral text representation of d into +os. Single digit values are prefixed with '0'. +

+

+Returns: os. +

+
+ +
+ +

month

+ +
+

Synopsis

+ +
+class month
+{
+    unsigned char m_;  // exposition only
+public:
+    explicit constexpr month(unsigned m) noexcept;
+
+    month& operator++() noexcept;
+    month operator++(int) noexcept;
+    month& operator--() noexcept;
+    month operator--(int) noexcept;
+
+    month& operator+=(const months& m) noexcept;
+    month& operator-=(const months& m) noexcept;
+
+    constexpr explicit operator unsigned() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const month& x, const month& y) noexcept;
+constexpr bool operator!=(const month& x, const month& y) noexcept;
+constexpr bool operator< (const month& x, const month& y) noexcept;
+constexpr bool operator> (const month& x, const month& y) noexcept;
+constexpr bool operator<=(const month& x, const month& y) noexcept;
+constexpr bool operator>=(const month& x, const month& y) noexcept;
+
+constexpr month  operator+(const month&  x, const months& y) noexcept;
+constexpr month  operator+(const months& x,  const month& y) noexcept;
+constexpr month  operator-(const month&  x, const months& y) noexcept;
+constexpr months operator-(const month&  x,  const month& y) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const month& m);
+
+constexpr month jan{1};
+constexpr month feb{2};
+constexpr month mar{3};
+constexpr month apr{4};
+constexpr month may{5};
+constexpr month jun{6};
+constexpr month jul{7};
+constexpr month aug{8};
+constexpr month sep{9};
+constexpr month oct{10};
+constexpr month nov{11};
+constexpr month dec{12};
+
+ +

Overview

+ +

+month represents a month of a year. It should only be representing values in +the range 1 to 12. However it may hold values outside this range. It can be constructed +with any unsigned value, which will be subsequently truncated to fit into +month's internal storage. month is equality and less-than +comparable, and participates in basic arithmetic with months representing the +quantity between any two month's. One can stream out a month +for debugging purposes. month has explicit conversions to and from +unsigned. There are 12 month constants, one for each month of +the year. +

+ +

Specification

+ +

+month is a trivially copyable class type.
+month is a standard-layout class type.
+month is a literal class type.
+

+ +
+explicit constexpr month::month(unsigned m) noexcept;
+
+ +
+

+Effects: Constructs an object of type month by constructing +m_ with m. +

+
+ +
+month& month::operator++() noexcept;
+
+ +
+

+Effects: If m_ != 12, ++m_. Otherwise sets +m_ to 1. +

+

+Returns: *this. +

+
+ +
+month month::operator++(int) noexcept;
+
+ +
+

+Effects: ++(*this). +

+

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

+
+ +
+month& month::operator--() noexcept;
+
+ +
+

+Effects: If m_ != 1, --m_. Otherwise sets +m_ to 12. +

+

+Returns: *this. +

+
+ +
+month month::operator--(int) noexcept;
+
+ +
+

+Effects: --(*this). +

+

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

+
+ +
+month& month::operator+=(const months& m) noexcept;
+
+ +
+

+Effects: *this = *this + m. +

+

+Returns: *this. +

+
+ +
+month& month::operator-=(const months& m) noexcept;
+
+ +
+

+Effects: *this = *this - m. +

+

+Returns: *this. +

+
+ +
+constexpr explicit month::operator unsigned() const noexcept;
+
+ +
+

+Returns: m_. +

+
+ +
+constexpr bool month::ok() const noexcept;
+
+ +
+

+Returns: 1 <= m_ && m_ <= 12. +

+
+ +
+constexpr bool operator==(const month& x, const month& y) noexcept;
+
+ +
+

+Returns: unsigned{x} == unsigned{y}. +

+
+ +
+constexpr bool operator!=(const month& x, const month& y) noexcept;
+
+ +
+

+Returns: !(x == y). +

+
+ +
+constexpr bool operator< (const month& x, const month& y) noexcept;
+
+ +
+

+Returns: unsigned{x} < unsigned{y}. +

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

+Returns: y < x. +

+
+ +
+constexpr bool operator<=(const month& x, const month& y) noexcept;
+
+ +
+

+Returns: !(y < x). +

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

+Returns: !(x < y). +

+
+ +
+constexpr month  operator+(const month&  x, const months& y) noexcept;
+
+ +
+

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

+

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

+

+Example: feb + months{11} == jan. +

+
+ +
+constexpr month  operator+(const months& x, const month&  y) noexcept;
+
+ +
+

+Returns: y + x. +

+
+ +
+constexpr month  operator-(const month&  x, const months& y) noexcept;
+
+ +
+

+Returns: x + -y. +

+
+ +
+constexpr months operator-(const month&  x, const month&  y) noexcept;
+
+ +
+

+Requires: x.ok() == true and y.ok() == true. +

+

+Returns: A value of months in the range of months{0} to +months{11} inclusive. +

+

+Remarks: The returned value m shall satisfy the equality: +y + m == x. +

+

+Example: jan - feb == months{11} . +

+
+ +
+std::ostream& operator<<(std::ostream& os, const month& m);
+
+ +
+

+Effects: If ok() == true outputs the same string that would be +output for the month field by asctime. Otherwise outputs +unsigned{m} << " is not a valid month". +

+

+Returns: os. +

+
+ +
+ +

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 bool is_leap() const 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;
+
+constexpr year operator "" _y(unsigned long long y) noexcept;
+std::ostream& operator<<(std::ostream& os, const year& y);
+
+ +

Overview

+ +

+year represents a year in the Gregorian 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 bool year::is_leap() const noexcept;
+
+ +
+

+Returns: true if *this represents a leap year, else +returns false. +

+
+ +
+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 +day_point(min()/jan/1) + 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 +day_point(max()/dec/31) + 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. +

+
+ +
+ +

weekday

+ +
+

Synopsis

+ +
+class weekday
+{
+    unsigned char wd_;  // exposition only
+public:
+    explicit constexpr weekday(unsigned wd) noexcept;
+    constexpr weekday(const day_point& dp) noexcept;
+
+    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 bool ok() const noexcept;
+    constexpr weekday_indexed operator[](unsigned index) const noexcept;
+    constexpr weekday_last operator[](last_spec) 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);
+
+constexpr weekday sun{0};
+constexpr weekday mon{1};
+constexpr weekday tue{2};
+constexpr weekday wed{3};
+constexpr weekday thu{4};
+constexpr weekday fri{5};
+constexpr weekday sat{6};
+
+ +

Overview

+ +

+weekday represents a day of the week in the Gregorian calendar. It should +only be representing values in the range 0 to 6, corresponding to Sunday thru Saturday. +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 0 to 6 to +represent Sunday thru Saturday only because this is consistent with existing C and C++ +practice. 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 day_point. This +is the computation that discovers the day of the week of an arbitrary date. +

+ +

+A weekday can be indexed with either unsigned or +last. This produces new types which represent the first, second, third, +fourth, fifth or last weekdays of a month. +

+ +

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 day_point& dp) noexcept;
+
+ +
+

+Effects: Constructs an object of type weekday by computing what day +of the week corresponds to the day_point 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_. +

+
+ +
+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 bool weekday::ok() const noexcept;
+
+ +
+

+Returns: wd_ <= 6. +

+
+ +
+constexpr weekday_indexed weekday::operator[](unsigned index) const noexcept;
+
+ +
+

+Returns: {*this, index}. +

+
+ +
+constexpr weekday_last weekday::operator[](last_spec) const noexcept;
+
+ +
+

+Returns: weekday_last{*this}. +

+
+ +
+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 [0, 6] by modular +arithmetic. [Note: For example weekday{7} becomes +weekday{0}. — end note] +

+

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

+

+Example: mon + days{6} == sun. +

+
+ +
+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: sun - mon == 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. Otherwise outputs +unsigned{wd} << " is not a valid weekday". +

+

+Returns: os. +

+
+ +
+ +

weekday_indexed

+ +
+

Synopsis

+ +
+class weekday_indexed
+{
+    date::weekday    wd_;     // exposition only
+    unsigned char    index_;  // exposition only
+
+public:
+    constexpr weekday_indexed(const date::weekday& wd, unsigned index) noexcept;
+
+    constexpr date::weekday weekday() const noexcept;
+    constexpr unsigned index() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const weekday_indexed& x, const weekday_indexed& y) noexcept;
+constexpr bool operator!=(const weekday_indexed& x, const weekday_indexed& y) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const weekday_indexed& wdi);
+
+ +

Overview

+ +

+weekday_indexed represents a weekday and a small index in the +range 1 to 5. This class is used to represent the first, second, third, fourth or fifth +weekday of a month. It is most easily constructed by indexing a weekday. +

+ +

+[Example: +

+ +
+constexpr auto wdi = sun[2];  // wdi is the second Sunday of an as yet unspecified month
+static_assert(wdi.weekday() == sun);
+static_assert(wdi.index() == 2);
+
+ +

+— end example:] +

+ +

Specification

+ +

+weekday_indexed is a trivially copyable class type.
+weekday_indexed is a standard-layout class type.
+weekday_indexed is a literal class type.
+

+ +
+constexpr weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) noexcept;
+
+ +
+

+Effects: Constructs an object of type weekday_indexed by constructing +wd_ with wd and index_ with index. +

+
+ +
+constexpr weekday weekday_indexed::weekday() const noexcept;
+
+ +
+

+Returns: wd_. +

+
+ +
+constexpr unsigned weekday_indexed::index() const noexcept;
+
+ +
+

+Returns: index_. +

+
+ +
+constexpr bool weekday_indexed::ok() const noexcept;
+
+ +
+

+Returns: wd_.ok() && 1 <= index_ && index_ <= 5. +

+
+ +
+constexpr bool operator==(const weekday_indexed& x, const weekday_indexed& y) noexcept;
+
+ +
+

+Returns: x.weekday() == y.weekday() && x.index() == y.index(). +

+
+ +
+constexpr bool operator!=(const weekday_indexed& x, const weekday_indexed& y) noexcept;
+
+ +
+

+Returns: !(x == y). +

+
+ +
+std::ostream& operator<<(std::ostream& os, const weekday_indexed& wdi);
+
+ +
+

+Effects: Inserts +os << wdi.weekday() << '[' << wdi.index() << ']'. +

+

+Returns: os. +

+
+ +
+ +

weekday_last

+ +
+

Synopsis

+ +
+class weekday_last
+{
+    date::weekday wd_;  // exposition only
+
+public:
+    explicit constexpr weekday_last(const date::weekday& wd) noexcept;
+
+    constexpr date::weekday weekday() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const weekday_last& x, const weekday_last& y) noexcept;
+constexpr bool operator!=(const weekday_last& x, const weekday_last& y) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const weekday_last& wdl);
+
+ +

Overview

+ +

+weekday_last represents the last weekday of a month. +It is most easily constructed by indexing a weekday with last. +

+ +

+[Example: +

+ +
+constexpr auto wdl = sun[last];  // wdl is the last Sunday of an as yet unspecified month
+static_assert(wdl.weekday() == sun);
+
+ +

+— end example:] +

+ +

Specification

+ +

+weekday_last is a trivially copyable class type.
+weekday_last is a standard-layout class type.
+weekday_last is a literal class type.
+

+ +
+explicit constexpr weekday_last::weekday_last(const date::weekday& wd) noexcept;
+
+ +
+

+Effects: Constructs an object of type weekday_last by constructing +wd_ with wd. +

+
+ +
+constexpr weekday weekday_last::weekday() const noexcept;
+
+ +
+

+Returns: wd_. +

+
+ +
+constexpr bool weekday_last::ok() const noexcept;
+
+ +
+

+Returns: wd_.ok(). +

+
+ +
+constexpr bool operator==(const weekday_last& x, const weekday_last& y) noexcept;
+
+ +
+

+Returns: x.weekday() == y.weekday(). +

+
+ +
+constexpr bool operator!=(const weekday_last& x, const weekday_last& y) noexcept;
+
+ +
+

+Returns: !(x == y). +

+
+ +
+std::ostream& operator<<(std::ostream& os, const weekday_last& wdl);
+
+ +
+

+Effects: Inserts +os << wdi.weekday() << "[last]". +

+

+Returns: os. +

+
+ +
+ +

month_day

+ +
+

Synopsis

+ +
+class month_day
+{
+    date::month m_;  // exposition only
+    date::day   d_;  // exposition only
+
+public:
+    constexpr month_day(const date::month& m, const date::day& d) noexcept;
+
+    constexpr date::month month() const noexcept;
+    constexpr date::day day() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const month_day& x, const month_day& y) noexcept;
+constexpr bool operator!=(const month_day& x, const month_day& y) noexcept;
+constexpr bool operator< (const month_day& x, const month_day& y) noexcept;
+constexpr bool operator> (const month_day& x, const month_day& y) noexcept;
+constexpr bool operator<=(const month_day& x, const month_day& y) noexcept;
+constexpr bool operator>=(const month_day& x, const month_day& y) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const month_day& md);
+
+ +

Overview

+ +

+month_day represents a specific day of a specific +month, but with an unspecified year. One can observe the +different components. One can assign a new value. month_day is equality +comparable and less-than comparable. One can stream out a month_day for +debugging purposes. +

+ +

Specification

+ +

+month_day is a trivially copyable class type.
+month_day is a standard-layout class type.
+month_day is a literal class type.
+

+ +
+constexpr month_day::month_day(const date::month& m, const date::day& d) noexcept;
+
+ +
+

+Effects: Constructs an object of type month_day by constructing +m_ with m, and d_ with d. +

+
+ +
+constexpr month month_day::month() const noexcept;
+
+ +
+

+Returns: m_. +

+
+ +
+constexpr day month_day::day() const noexcept;
+
+ +
+

+Returns: d_. +

+
+ +
+constexpr bool month_day::ok() const noexcept;
+
+ +
+

+Returns: true if m_.ok() is true, and if +1_d <= d_, and if d_ <= the number of days in month +m_. For m_ == feb the number of days is considered to be 29. +Otherwise returns false. +

+
+ +
+constexpr bool operator==(const month_day& x, const month_day& y) noexcept;
+
+ +
+

+Returns: x.month() == y.month() && x.day() == y.day() +

+
+ +
+constexpr bool operator!=(const month_day& x, const month_day& y) noexcept;
+
+ +
+

+Returns: !(x == y) +

+
+ +
+constexpr bool operator< (const month_day& x, const month_day& y) noexcept;
+
+ +
+

+Returns: If x.month() < y.month() returns true. Else +if x.month() > y.month() returns false. Else returns +x.day() < y.day(). +

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

+Returns: y < x. +

+
+ +
+constexpr bool operator<=(const month_day& x, const month_day& y) noexcept;
+
+ +
+

+Returns: !(y < x). +

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

+Returns: !(x < y). +

+
+ +
+std::ostream& operator<<(std::ostream& os, const month_day& md);
+
+ +
+

+Effects: Inserts +os << md.month() << '/' << md.day(). +

+

+Returns: os. +

+
+ +
+ +

month_day_last

+ +
+

Synopsis

+ +
+class month_day_last
+{
+    date::month m_;  // exposition only
+
+public:
+    constexpr explicit month_day_last(const date::month& m) noexcept;
+
+    constexpr date::month month() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const month_day_last& x, const month_day_last& y) noexcept;
+constexpr bool operator!=(const month_day_last& x, const month_day_last& y) noexcept;
+constexpr bool operator< (const month_day_last& x, const month_day_last& y) noexcept;
+constexpr bool operator> (const month_day_last& x, const month_day_last& y) noexcept;
+constexpr bool operator<=(const month_day_last& x, const month_day_last& y) noexcept;
+constexpr bool operator>=(const month_day_last& x, const month_day_last& y) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const month_day_last& mdl);
+
+ +

Overview

+ +

+month_day_last represents the last day of a month. +It is most easily constructed using the expression m/last or +last/m, where m is an expression with type month. +

+ +

+[Example: +

+ +
+constexpr auto mdl = feb/last;  // mdl is the last day of February of an as yet unspecified year
+static_assert(mdl.month() == feb);
+
+ +

+— end example:] +

+ +

Specification

+ +

+month_day_last is a trivially copyable class type.
+month_day_last is a standard-layout class type.
+month_day_last is a literal class type.
+

+ +
+constexpr explicit month_day_last::month_day_last(const date::month& m) noexcept;
+
+ +
+

+Effects: Constructs an object of type month_day_last by constructing +m_ with m. +

+
+ +
+constexpr month month_day_last::month() const noexcept;
+
+ +
+

+Returns: m_. +

+
+ +
+constexpr bool month_day_last::ok() const noexcept;
+
+ +
+

+Returns: m_.ok(). +

+
+ +
+constexpr bool operator==(const month_day_last& x, const month_day_last& y) noexcept;
+
+ +
+

+Returns: x.month() == y.month(). +

+
+ +
+constexpr bool operator!=(const month_day_last& x, const month_day_last& y) noexcept;
+
+ +
+

+Returns: !(x == y) +

+
+ +
+constexpr bool operator< (const month_day_last& x, const month_day_last& y) noexcept;
+
+ +
+

+Returns: x.month() < y.month(). +

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

+Returns: y < x. +

+
+ +
+constexpr bool operator<=(const month_day_last& x, const month_day_last& y) noexcept;
+
+ +
+

+Returns: !(y < x). +

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

+Returns: !(x < y). +

+
+ +
+std::ostream& operator<<(std::ostream& os, const month_day_last& mdl);
+
+ +
+

+Effects: Inserts +os << mdl.month() << "/last". +

+

+Returns: os. +

+
+ +
+ +

month_weekday

+ +
+

Synopsis

+ +
+class month_weekday
+{
+    date::month           m_;    // exposition only
+    date::weekday_indexed wdi_;  // exposition only
+public:
+    constexpr month_weekday(const date::month& m, const date::weekday_indexed& wdi) noexcept;
+
+    constexpr date::month month() const noexcept;
+    constexpr date::weekday_indexed weekday_indexed() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const month_weekday& x, const month_weekday& y) noexcept;
+constexpr bool operator!=(const month_weekday& x, const month_weekday& y) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const month_weekday& mwd);
+
+ +

Overview

+ +

+month_weekday represents the nth weekday of a +month, of an as yet unspecified year. To do this the +month_weekday stores a month and a weekday_indexed. +

+ +

Specification

+ +

+month_weekday is a trivially copyable class type.
+month_weekday is a standard-layout class type.
+month_weekday is a literal class type.
+

+ +
+constexpr month_weekday::month_weekday(const date::month& m, const date::weekday_indexed& wdi) noexcept;
+
+ +
+

+Effects: Constructs an object of type month_weekday by constructing +m_ with m, and wdi_ with wdi. +

+
+ +
+constexpr month month_weekday::month() const noexcept;
+
+ +
+

+Returns: m_. +

+
+ +
+constexpr weekday_indexed month_weekday::weekday_indexed() const noexcept;
+
+ +
+

+Returns: wdi_. +

+
+ +
+constexpr bool month_weekday::ok() const noexcept;
+
+ +
+

+Returns: m_.ok() && wdi_.ok(). +

+
+ +
+constexpr bool operator==(const month_weekday& x, const month_weekday& y) noexcept;
+
+ +
+

+Returns: x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed(). +

+
+ +
+constexpr bool operator!=(const month_weekday& x, const month_weekday& y) noexcept;
+
+ +
+

+Returns: !(x == y). +

+
+ +
+std::ostream& operator<<(std::ostream& os, const month_weekday& mwd);
+
+ +
+

+Effects: Inserts +os << mwd.month() << '/' << mwd.weekday_indexed(). +

+

+Returns: os. +

+
+ +
+ +

month_weekday_last

+ +
+

Synopsis

+ +
+class month_weekday_last
+{
+    date::month        m_;     // exposition only
+    date::weekday_last wdl_;   // exposition only
+public:
+    constexpr month_weekday_last(const date::month& m,
+                                 const date::weekday_last& wdl) noexcept;
+
+    constexpr date::month        month()        const noexcept;
+    constexpr date::weekday_last weekday_last() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const month_weekday_last& x, const month_weekday_last& y) noexcept;
+constexpr bool operator!=(const month_weekday_last& x, const month_weekday_last& y) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const month_weekday_last& mwdl);
+
+ +

Overview

+ +

+month_weekday_last represents the last weekday of a +month, of an as yet unspecified year. To do this the +month_weekday_last stores a month and a +weekday_last. +

+ +

Specification

+ +

+month_weekday_last is a trivially copyable class type.
+month_weekday_last is a standard-layout class type.
+month_weekday_last is a literal class type.
+

+ +
+constexpr month_weekday_last::month_weekday_last(const date::month& m,
+                                                 const date::weekday_last& wdl) noexcept;
+
+ +
+

+Effects: Constructs an object of type month_weekday_last by constructing +m_ with m, and wdl_ with wdl. +

+
+ +
+constexpr month month_weekday_last::month() const noexcept;
+
+ +
+

+Returns: m_. +

+
+ +
+constexpr weekday_last month_weekday_last::weekday_last() const noexcept;
+
+ +
+

+Returns: wdl_. +

+
+ +
+constexpr bool month_weekday_last::ok() const noexcept;
+
+ +
+

+Returns: m_.ok() && wdl_.ok(). +

+
+ +
+constexpr bool operator==(const month_weekday_last& x, const month_weekday_last& y) noexcept;
+
+ +
+

+Returns: x.month() == y.month() && x.weekday_last() == y.weekday_last(). +

+
+ +
+constexpr bool operator!=(const month_weekday_last& x, const month_weekday_last& y) noexcept;
+
+ +
+

+Returns: !(x == y). +

+
+ +
+std::ostream& operator<<(std::ostream& os, const month_weekday_last& mwdl);
+
+ +
+

+Effects: Inserts +os << mwdl.month() << '/' << mwdl.weekday_last(). +

+

+Returns: os. +

+
+ +
+ +

year_month

+ +
+

Synopsis

+ +
+class year_month
+{
+    date::year  y_;  // exposition only
+    date::month m_;  // exposition only
+
+public:
+    constexpr year_month(const date::year& y, const date::month& m) noexcept;
+
+    constexpr date::year year() const noexcept;
+    constexpr date::month month() const noexcept;
+
+    year_month& operator+=(const months& dm) noexcept;
+    year_month& operator-=(const months& dm) noexcept;
+    year_month& operator+=(const years& dy) noexcept;
+    year_month& operator-=(const years& dy) noexcept;
+
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const year_month& x, const year_month& y) noexcept;
+constexpr bool operator!=(const year_month& x, const year_month& y) noexcept;
+constexpr bool operator< (const year_month& x, const year_month& y) noexcept;
+constexpr bool operator> (const year_month& x, const year_month& y) noexcept;
+constexpr bool operator<=(const year_month& x, const year_month& y) noexcept;
+constexpr bool operator>=(const year_month& x, const year_month& y) noexcept;
+
+constexpr year_month operator+(const year_month& ym, const months& dm) noexcept;
+constexpr year_month operator+(const months& dm, const year_month& ym) noexcept;
+constexpr year_month operator-(const year_month& ym, const months& dm) noexcept;
+constexpr months operator-(const year_month& x, const year_month& y) noexcept;
+constexpr year_month operator+(const year_month& ym, const years& dy) noexcept;
+constexpr year_month operator+(const years& dy, const year_month& ym) noexcept;
+constexpr year_month operator-(const year_month& ym, const years& dy) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const year_month& ym);
+
+ +

Overview

+ +

+year_month represents a specific month of a specific +year, but with an unspecified day. year_month is a +field-based time point with a resolution of months. One can observe the +different components. One can assign a new value. year_month is equality +comparable and less-than comparable. One can stream out a year_month for +debugging purposes. +

+ +

Specification

+ +

+year_month is a trivially copyable class type.
+year_month is a standard-layout class type.
+year_month is a literal class type.
+

+ +
+constexpr year_month::year_month(const date::year& y, const date::month& m) noexcept;
+
+ +
+

+Effects: Constructs an object of type year_month by constructing +y_ with y, and m_ with m. +

+
+ +
+constexpr year year_month::year() const noexcept;
+
+ +
+

+Returns: y_. +

+
+ +
+constexpr month year_month::month() const noexcept;
+
+ +
+

+Returns: m_. +

+
+ +
+year_month& operator+=(const months& dm) noexcept;
+
+ +
+

+Effects: *this = *this + dm. +

+

+Returns: *this. +

+
+ +
+year_month& operator-=(const months& dm) noexcept;
+
+ +
+

+Effects: *this = *this - dm. +

+

+Returns: *this. +

+
+ +
+year_month& operator+=(const years& dy) noexcept;
+
+ +
+

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

+

+Returns: *this. +

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

+Effects: *this = *this - dy. +

+

+Returns: *this. +

+
+ +
+constexpr bool year_month::ok() const noexcept;
+
+ +
+

+Returns: y_.ok() && m_.ok(). +

+
+ +
+constexpr bool operator==(const year_month& x, const year_month& y) noexcept;
+
+ +
+

+Returns: x.year() == y.year() && x.month() == y.month() +

+
+ +
+constexpr bool operator!=(const year_month& x, const year_month& y) noexcept;
+
+ +
+

+Returns: !(x == y) +

+
+ +
+constexpr bool operator< (const year_month& x, const year_month& y) noexcept;
+
+ +
+

+Returns: If x.year() < y.year() returns true. Else +if x.year() > y.year() returns false. Else returns +x.month() < y.month(). +

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

+Returns: y < x. +

+
+ +
+constexpr bool operator<=(const year_month& x, const year_month& y) noexcept;
+
+ +
+

+Returns: !(y < x). +

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

+Returns: !(x < y). +

+
+ +
+constexpr year_month operator+(const year_month& ym, const months& dm) noexcept;
+
+ +
+

+Returns: A year_month value z such that +z - ym == dm. +

+

+Complexity: O(1) with respect to the value of dm. +

+
+ +
+constexpr year_month operator+(const months& dm, const year_month& ym) noexcept;
+
+ +
+

+Returns: ym + dm. +

+
+ +
+constexpr year_month operator-(const year_month& ym, const months& dm) noexcept;
+
+ +
+

+Returns: ym + -dm. +

+
+ +
+constexpr months operator-(const year_month& x, const year_month& y) noexcept;
+
+ +
+

+Returns: The number of months one must add to y to get +x. +

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

+Returns: (ym.year() + dy) / ym.month(). +

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

+Returns: ym + dy. +

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

+Returns: ym + -dy. +

+
+ +
+std::ostream& operator<<(std::ostream& os, const year_month& ym);
+
+ +
+

+Effects: Inserts +os << ym.year() << '/' << ym.month(). +

+

+Returns: os. +

+
+ +
+ +

year_month_day

+ +
+

Synopsis

+ +
+class year_month_day
+{
+    date::year  y_;  // exposition only
+    date::month m_;  // exposition only
+    date::day   d_;  // exposition only
+
+public:
+    constexpr year_month_day(const date::year& y, const date::month& m, const date::day& d) noexcept;
+    constexpr year_month_day(const year_month_day_last& ymdl) noexcept;
+    constexpr year_month_day(const day_point& dp) noexcept;
+
+    year_month_day& operator+=(const months& m) noexcept;
+    year_month_day& operator-=(const months& m) noexcept;
+    year_month_day& operator+=(const years& y) noexcept;
+    year_month_day& operator-=(const years& y) noexcept;
+
+    constexpr date::year year()   const noexcept;
+    constexpr date::month month() const noexcept;
+    constexpr date::day day()     const noexcept;
+
+    constexpr operator day_point() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const year_month_day& x, const year_month_day& y) noexcept;
+constexpr bool operator!=(const year_month_day& x, const year_month_day& y) noexcept;
+constexpr bool operator< (const year_month_day& x, const year_month_day& y) noexcept;
+constexpr bool operator> (const year_month_day& x, const year_month_day& y) noexcept;
+constexpr bool operator<=(const year_month_day& x, const year_month_day& y) noexcept;
+constexpr bool operator>=(const year_month_day& x, const year_month_day& y) noexcept;
+
+constexpr year_month_day operator+(const year_month_day& ymd, const months& dm) noexcept;
+constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept;
+constexpr year_month_day operator+(const year_month_day& ymd, const years& dy) noexcept;
+constexpr year_month_day operator+(const years& dy, const year_month_day& ymd) noexcept;
+constexpr year_month_day operator-(const year_month_day& ymd, const months& dm) noexcept;
+constexpr year_month_day operator-(const year_month_day& ymd, const years& dy) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const year_month_day& ymd);
+
+ +

Overview

+ +

+year_month_day represents a specific year, month, +and day. year_month_day is a field-based time point with a +resolution of days. One can observe each field. year_month_day +supports years and months oriented arithmetic, but not +days oriented arithmetic. For the latter, there is a conversion to +day_point which efficiently supports days oriented arithmetic. +There is also a conversion from day_point. +year_month_day is equality and less-than comparable. +

+ +

Specification

+ +

+year_month_day is a trivially copyable class type.
+year_month_day is a standard-layout class type.
+year_month_day is a literal class type.
+

+ +
+constexpr year_month_day::year_month_day(const date::year& y, const date::month& m, const date::day& d) noexcept;
+
+ +
+

+Effects: Constructs an object of type year_month_day by constructing +y_ with y, m_ with m, and, +d_ with d. +

+
+ +
+constexpr year_month_day::year_month_day(const year_month_day_last& ymdl) noexcept;
+
+ +
+

+Effects: Constructs an object of type year_month_day by constructing +y_ with ymdl.year(), m_ with +ymdl.month(), and, d_ with ymdl.day(). +

+

+Note: This conversion from year_month_day_last to +year_month_day is more efficient than converting a +year_month_day_last to a day_point, and then converting that +day_point to a year_month_day. +

+
+ +
+constexpr year_month_day::year_month_day(const day_point& dp) noexcept;
+
+ +
+

+Effects: Constructs an object of type year_month_day which corresponds +to the date represented by dp. +

+

+Remarks: For any value of year_month_day, ymd, for which +ymd.ok() is true, this equality will also be true: +ymd == year_month_day{day_point{ymd}}. +

+
+ +
+year_month_day& year_month_day::operator+=(const months& m) noexcept;
+
+ +
+

+Effects: *this = *this + m;. +

+

+Returns: *this. +

+
+ +
+year_month_day& year_month_day::operator-=(const months& m) noexcept;
+
+ +
+

+Effects: *this = *this - m;. +

+

+Returns: *this. +

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

+Effects: *this = *this + y;. +

+

+Returns: *this. +

+
+ +
+year_month_day& year_month_day::operator-=(const years& y) noexcept;
+
+ +
+

+Effects: *this = *this - y;. +

+

+Returns: *this. +

+
+ +
+constexpr year year_month_day::year() const noexcept;
+
+ +
+

+Returns: y_. +

+
+ +
+constexpr month year_month_day::month() const noexcept;
+
+ +
+

+Returns: m_. +

+
+ +
+constexpr day year_month_day::day() const noexcept;
+
+ +
+

+Returns: d_. +

+
+ +
+constexpr year_month_day::operator day_point() const noexcept;
+
+ +
+

+Requires: ok() == true. +

+

+Returns: A day_point which represents the date represented by +*this. +

+
+ +
+constexpr bool year_month_day::ok() const noexcept;
+
+ +
+

+Returns: If y_.ok() is true, and m_.ok() is +true, and d_ is in the range +[1_d, (y_/m_/last).day()], then returns true, else returns +false. +

+
+ +
+constexpr bool operator==(const year_month_day& x, const year_month_day& y) noexcept;
+
+ +
+

+Returns: x.year() == y.year() && x.month() == y.month() && x.day() == y.day(). +

+
+ +
+constexpr bool operator!=(const year_month_day& x, const year_month_day& y) noexcept;
+
+ +
+

+Returns: !(x == y). +

+
+ +
+constexpr bool operator< (const year_month_day& x, const year_month_day& y) noexcept;
+
+ +
+

+Returns: If x.year() < y.year(), returns true. Else +if x.year() > y.year() returns false. +Else if x.month() < y.month(), returns true. +Else if x.month() > y.month(), returns false. +Else returns x.day() < y.day(). +

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

+Returns: y < x. +

+
+ +
+constexpr bool operator<=(const year_month_day& x, const year_month_day& y) noexcept;
+
+ +
+

+Returns: !(y < x). +

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

+Returns: !(x < y). +

+
+ +
+constexpr year_month_day operator+(const year_month_day& ymd, const months& dm) noexcept;
+
+ +
+

+Requires: ymd.month().ok() is true. +

+

+Returns: (ymd.year() / ymd.month() + dm) / ymd.day(). +

+

+Remarks: If ymd.day() is in the range [1_d, 28_d], +the resultant year_month_day is guaranteed to return true from +ok(). +

+
+ +
+constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept;
+
+ +
+

+Returns: ymd + dm. +

+
+ +
+constexpr year_month_day operator-(const year_month_day& ymd, const months& dm) noexcept;
+
+ +
+

+Returns: ymd + (-dm). +

+
+ +
+constexpr year_month_day operator+(const year_month_day& ymd, const years& dy) noexcept;
+
+ +
+

+Returns: (ymd.year() + dy) / ymd.month() / ymd.day(). +

+

+Remarks: If ymd.month() is feb and ymd.day() +is not in the range [1_d, 28_d], the resultant year_month_day is +not guaranteed to return true from ok(). +

+
+ +
+constexpr year_month_day operator+(const years& dy, const year_month_day& ymd) noexcept;
+
+ +
+

+Returns: ymd + dy. +

+
+ +
+constexpr year_month_day operator-(const year_month_day& ymd, const years& dy) noexcept;
+
+ +
+

+Returns: ymd + (-dy). +

+
+ +
+std::ostream& operator<<(std::ostream& os, const year_month_day& ymd);
+
+ +
+

+Effects: Inserts yyyy-mm-dd where the number of indicated digits +are prefixed with '0' if necessary.. +

+

+Returns: os. +

+
+ +
+ +

year_month_day_last

+ +
+

Synopsis

+ +
+class year_month_day_last
+{
+    date::year           y_;    // exposition only
+    date::month_day_last mdl_;  // exposition only
+
+public:
+    constexpr year_month_day_last(const date::year& y,
+                                  const date::month_day_last& mdl) noexcept;
+
+    year_month_day_last& operator+=(const months& m) noexcept;
+    year_month_day_last& operator-=(const months& m) noexcept;
+    year_month_day_last& operator+=(const years& y) noexcept;
+    year_month_day_last& operator-=(const years& y) noexcept;
+
+    constexpr date::year           year()           const noexcept;
+    constexpr date::month          month()          const noexcept;
+    constexpr date::month_day_last month_day_last() const noexcept;
+    constexpr date::day            day()            const noexcept;
+
+    constexpr operator day_point() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const year_month_day_last& x, const year_month_day_last& y) noexcept;
+constexpr bool operator!=(const year_month_day_last& x, const year_month_day_last& y) noexcept;
+constexpr bool operator< (const year_month_day_last& x, const year_month_day_last& y) noexcept;
+constexpr bool operator> (const year_month_day_last& x, const year_month_day_last& y) noexcept;
+constexpr bool operator<=(const year_month_day_last& x, const year_month_day_last& y) noexcept;
+constexpr bool operator>=(const year_month_day_last& x, const year_month_day_last& y) noexcept;
+
+constexpr year_month_day_last operator+(const year_month_day_last& ymdl, const months& dm) noexcept;
+constexpr year_month_day_last operator+(const months& dm, const year_month_day_last& ymdl) noexcept;
+constexpr year_month_day_last operator+(const year_month_day_last& ymdl, const years& dy) noexcept;
+constexpr year_month_day_last operator+(const years& dy, const year_month_day_last& ymdl) noexcept;
+constexpr year_month_day_last operator-(const year_month_day_last& ymdl, const months& dm) noexcept;
+constexpr year_month_day_last operator-(const year_month_day_last& ymdl, const years& dy) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const year_month_day_last& ymdl);
+
+ +

Overview

+ +

+year_month_day_last represents a specific year, +month, and the last day of the month. +year_month_day_last is a field-based time point with a resolution of +days, except that it is restricted to pointing to the last day of a year and +month. One can observe each field. The day field is computed on demand. +year_month_day_last supports years and months +oriented arithmetic, but not days oriented arithmetic. For the latter, there +is a conversion to day_point which efficiently supports days +oriented arithmetic. year_month_day_last is equality and less-than +comparable. +

+ +

Specification

+ +

+year_month_day_last is a trivially copyable class type.
+year_month_day_last is a standard-layout class type.
+year_month_day_last is a literal class type.
+

+ +
+constexpr year_month_day_last::year_month_day_last(const date::year& y,
+                                                   const date::month_day_last& mdl) noexcept;
+
+ +
+

+Effects: Constructs an object of type year_month_day_last by +constructing y_ with y and mdl_ with mdl. +

+
+ +
+year_month_day_last& year_month_day_last::operator+=(const months& m) noexcept;
+
+ +
+

+Effects: *this = *this + m;. +

+

+Returns: *this. +

+
+ +
+year_month_day_last& year_month_day_last::operator-=(const months& m) noexcept;
+
+ +
+

+Effects: *this = *this - m;. +

+

+Returns: *this. +

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

+Effects: *this = *this + y;. +

+

+Returns: *this. +

+
+ +
+year_month_day_last& year_month_day_last::operator-=(const years& y) noexcept;
+
+ +
+

+Effects: *this = *this - y;. +

+

+Returns: *this. +

+
+ +
+constexpr year year_month_day_last::year() const noexcept;
+
+ +
+

+Returns: y_. +

+
+ +
+constexpr month year_month_day_last::month() const noexcept;
+
+ +
+

+Returns: mdl_.month(). +

+
+ +
+constexpr month_day_last year_month_day_last::month_day_last() const noexcept;
+
+ +
+

+Returns: mdl_. +

+
+ +
+constexpr day year_month_day_last::day() const noexcept;
+
+ +
+

+Returns: A day representing the last day of the year, +month pair represented by *this. +

+
+ +
+constexpr year_month_day_last::operator day_point() const noexcept;
+
+ +
+

+Requires: ok() == true. +

+

+Returns: A day_point which represents the date represented by +*this. +

+
+ +
+constexpr bool year_month_day_last::ok() const noexcept;
+
+ +
+

+Returns: y_.ok() && mdl_.ok(). +

+
+ +
+constexpr bool operator==(const year_month_day_last& x, const year_month_day_last& y) noexcept;
+
+ +
+

+Returns: x.year() == y.year() && x.month_day_last() == y.month_day_last(). +

+
+ +
+constexpr bool operator!=(const year_month_day_last& x, const year_month_day_last& y) noexcept;
+
+ +
+

+Returns: !(x == y). +

+
+ +
+constexpr bool operator< (const year_month_day_last& x, const year_month_day_last& y) noexcept;
+
+ +
+

+Returns: If x.year() < y.year(), returns true. Else +if x.year() > y.year() returns false. +Else returns x.month_day_last() < y.month_day_last(). +

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

+Returns: y < x. +

+
+ +
+constexpr bool operator<=(const year_month_day_last& x, const year_month_day_last& y) noexcept;
+
+ +
+

+Returns: !(y < x). +

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

+Returns: !(x < y). +

+
+ +
+constexpr year_month_day_last operator+(const year_month_day_last& ymdl, const months& dm) noexcept;
+
+ +
+

+Requires: ymdl.ok() is true. +

+

+Returns: (ymdl.year() / ymdl.month() + dm) / last. +

+

+Postconditions: The resultant year_month_day_last will return +true from ok(). +

+

+Complexity: O(1) with respect to the value of dm. +

+
+ +
+constexpr year_month_day_last operator+(const months& dm, const year_month_day_last& ymdl) noexcept;
+
+ +
+

+Returns: ymdl + dm. +

+
+ +
+constexpr year_month_day_last operator-(const year_month_day_last& ymdl, const months& dm) noexcept;
+
+ +
+

+Returns: ymdl + (-dm). +

+
+ +
+constexpr year_month_day_last operator+(const year_month_day_last& ymdl, const years& dy) noexcept;
+
+ +
+

+Returns: {ymdl.year()+dy, ymdl.month_day_last()}. +

+
+ +
+constexpr year_month_day_last operator+(const years& dy, const year_month_day_last& ymdl) noexcept;
+
+ +
+

+Returns: ymdl + dy. +

+
+ +
+constexpr year_month_day_last operator-(const year_month_day_last& ymdl, const years& dy) noexcept;
+
+ +
+

+Returns: ymdl + (-dy). +

+
+ +
+std::ostream& operator<<(std::ostream& os, const year_month_day_last& ymdl);
+
+ +
+

+Effects: Inserts +os << ymdl.year() << '/' << ymdl.month_day_last(). +

+

+Returns: os. +

+
+ +
+ +

year_month_weekday

+ +
+

Synopsis

+ +
+class year_month_weekday
+{
+    date::year            y_;    // exposition only
+    date::month           m_;    // exposition only
+    date::weekday_indexed wdi_;  // exposition only
+
+public:
+    constexpr year_month_weekday(const date::year& y, const date::month& m,
+                                 const date::weekday_indexed& wdi) noexcept;
+    constexpr year_month_weekday(const day_point& dp) noexcept;
+
+    year_month_weekday& operator+=(const months& m) noexcept;
+    year_month_weekday& operator-=(const months& m) noexcept;
+    year_month_weekday& operator+=(const years& y) noexcept;
+    year_month_weekday& operator-=(const years& y) noexcept;
+
+    constexpr date::year year() const noexcept;
+    constexpr date::month month() const noexcept;
+    constexpr date::weekday weekday() const noexcept;
+    constexpr unsigned index() const noexcept;
+    constexpr date::weekday_indexed weekday_indexed() const noexcept;
+
+    constexpr operator day_point() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr bool operator==(const year_month_weekday& x, const year_month_weekday& y) noexcept;
+constexpr bool operator!=(const year_month_weekday& x, const year_month_weekday& y) noexcept;
+
+constexpr year_month_weekday operator+(const year_month_weekday& ymwd, const months& dm) noexcept;
+constexpr year_month_weekday operator+(const months& dm, const year_month_weekday& ymwd) noexcept;
+constexpr year_month_weekday operator+(const year_month_weekday& ymwd, const years& dy) noexcept;
+constexpr year_month_weekday operator+(const years& dy, const year_month_weekday& ymwd) noexcept;
+constexpr year_month_weekday operator-(const year_month_weekday& ymwd, const months& dm) noexcept;
+constexpr year_month_weekday operator-(const year_month_weekday& ymwd, const years& dy) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const year_month_weekday& ymwdi);
+
+ +

Overview

+ +

+year_month_weekday represents a specific year, +month, and nth weekday of the month. +year_month_weekday is a field-based time point with a resolution of +days. One can observe each field. year_month_weekday supports +years and months oriented arithmetic, but not days +oriented arithmetic. For the latter, there is a conversion to day_point which +efficiently supports days oriented arithmetic. +year_month_weekday is equality comparable. +

+ +

Specification

+ +

+year_month_weekday is a trivially copyable class type.
+year_month_weekday is a standard-layout class type.
+year_month_weekday is a literal class type.
+

+ +
+constexpr year_month_weekday::year_month_weekday(const date::year& y, const date::month& m,
+                                                 const date::weekday_indexed& wdi) noexcept;
+
+ +
+

+Effects: Constructs an object of type year_month_weekday by +constructing y_ with y, m_ with m, +and wdi_ with wdi. +

+
+ +
+constexpr year_month_weekday(const day_point& dp) noexcept;
+
+ +
+

+Effects: Constructs an object of type year_month_weekday which +corresponds to the date represented by dp. +

+

+Remarks: For any value of year_month_weekday, ymdl, for +which ymdl.ok() is true, this equality will also be +true: ymdl == year_month_weekday{day_point{ymdl}}. +

+
+ +
+year_month_weekday& year_month_weekday::operator+=(const months& m) noexcept;
+
+ +
+

+Effects: *this = *this + m;. +

+

+Returns: *this. +

+
+ +
+year_month_weekday& year_month_weekday::operator-=(const months& m) noexcept;
+
+ +
+

+Effects: *this = *this - m;. +

+

+Returns: *this. +

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

+Effects: *this = *this + y;. +

+

+Returns: *this. +

+
+ +
+year_month_weekday& year_month_weekday::operator-=(const years& y) noexcept;
+
+ +
+

+Effects: *this = *this - y;. +

+

+Returns: *this. +

+
+ +
+constexpr year year_month_weekday::year() const noexcept;
+
+ +
+

+Returns: y_. +

+
+ +
+constexpr month year_month_weekday::month() const noexcept;
+
+ +
+

+Returns: m_. +

+
+ +
+constexpr weekday year_month_weekday::weekday() const noexcept;
+
+ +
+

+Returns: wdi_.weekday(). +

+
+ +
+constexpr unsigned year_month_weekday::index() const noexcept;
+
+ +
+

+Returns: wdi_.index(). +

+
+ +
+constexpr weekday_indexed year_month_weekday::weekday_indexed() const noexcept;
+
+ +
+

+Returns: wdi_. +

+
+ +
+constexpr year_month_weekday::operator day_point() const noexcept;
+
+ +
+

+Requires: ok() == true. +

+

+Returns: A day_point which represents the date represented by +*this. +

+
+ +
+constexpr bool year_month_weekday::ok() const noexcept;
+
+ +
+

+Returns: If y_.ok() or m_.ok() or wdi_.ok() +returns false, returns false. Else if *this +represents a valid date, returns true, else returns false. +

+
+ +
+constexpr bool operator==(const year_month_weekday& x, const year_month_weekday& y) noexcept;
+
+ +
+

+Returns: x.year() == y.year() && x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed(). +

+
+ +
+constexpr bool operator!=(const year_month_weekday& x, const year_month_weekday& y) noexcept;
+
+ +
+

+Returns: !(x == y). +

+
+ +
+constexpr year_month_weekday operator+(const year_month_weekday& ymwd, const months& dm) noexcept;
+
+ +
+

+Requires: ymwd.ok() is true. +

+

+Returns: (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed(). +

+

+Postconditions: The resultant year_month_weekday will return +true from ok(). +

+

+Complexity: O(1) with respect to the value of dm. +

+
+ +
+constexpr year_month_weekday operator+(const months& dm, const year_month_weekday& ymwd) noexcept;
+
+ +
+

+Returns: ymwd + dm. +

+
+ +
+constexpr year_month_weekday operator-(const year_month_weekday& ymwd, const months& dm) noexcept;
+
+ +
+

+Returns: ymwd + (-dm). +

+
+ +
+constexpr year_month_weekday operator+(const year_month_weekday& ymwd, const years& dy) noexcept;
+
+ +
+

+Returns: {ymwd.year()+dy, ymwd.month(), ymwd.weekday_indexed()}. +

+
+ +
+constexpr year_month_weekday operator+(const years& dy, const year_month_weekday& ymwd) noexcept;
+
+ +
+

+Returns: ymwd + dm. +

+
+ +
+constexpr year_month_weekday operator-(const year_month_weekday& ymwd, const years& dy) noexcept;
+
+ +
+

+Returns: ymwd + (-dm). +

+
+ +
+std::ostream& operator<<(std::ostream& os, const year_month_weekday& ymwd);
+
+ +
+

+Effects: Inserts +os << ymwdi.year() << '/' << ymwdi.month() << '/' << ymwdi.weekday_indexed(). +

+

+Returns: os. +

+
+ +
+ +

year_month_weekday_last

+ +
+

Synopsis

+ +
+class year_month_weekday_last
+{
+    date::year         y_;    // exposition only
+    date::month        m_;    // exposition only
+    date::weekday_last wdl_;  // exposition only
+
+public:
+    constexpr year_month_weekday_last(const date::year& y, const date::month& m,
+                                      const date::weekday_last& wdl) noexcept;
+
+    year_month_weekday_last& operator+=(const months& m) noexcept;
+    year_month_weekday_last& operator-=(const months& m) noexcept;
+    year_month_weekday_last& operator+=(const years& y) noexcept;
+    year_month_weekday_last& operator-=(const years& y) noexcept;
+
+    constexpr date::year year() const noexcept;
+    constexpr date::month month() const noexcept;
+    constexpr date::weekday weekday() const noexcept;
+    constexpr date::weekday_last weekday_last() const noexcept;
+
+    constexpr operator day_point() const noexcept;
+    constexpr bool ok() const noexcept;
+};
+
+constexpr
+bool
+operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept;
+
+constexpr
+bool
+operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept;
+
+constexpr
+year_month_weekday_last
+operator+(const year_month_weekday_last& ymwdl, const months& dm) noexcept;
+
+constexpr
+year_month_weekday_last
+operator+(const months& dm, const year_month_weekday_last& ymwdl) noexcept;
+
+constexpr
+year_month_weekday_last
+operator+(const year_month_weekday_last& ymwdl, const years& dy) noexcept;
+
+constexpr
+year_month_weekday_last
+operator+(const years& dy, const year_month_weekday_last& ymwdl) noexcept;
+
+constexpr
+year_month_weekday_last
+operator-(const year_month_weekday_last& ymwdl, const months& dm) noexcept;
+
+constexpr
+year_month_weekday_last
+operator-(const year_month_weekday_last& ymwdl, const years& dy) noexcept;
+
+std::ostream& operator<<(std::ostream& os, const year_month_weekday_last& ymwdl);
+
+ +

Overview

+ +

+year_month_weekday_last represents a specific year, +month, and last weekday of the month. +year_month_weekday_last is a field-based time point with a resolution of +days, except that it is restricted to pointing to the last weekday of a year +and month. One can observe each field. year_month_weekday_last supports +years and months oriented arithmetic, but not days +oriented arithmetic. For the latter, there is a conversion to day_point which +efficiently supports days oriented arithmetic. +year_month_weekday_last is equality comparable. +

+ +

Specification

+ +

+year_month_weekday_last is a trivially copyable class type.
+year_month_weekday_last is a standard-layout class type.
+year_month_weekday_last is a literal class type.
+

+ +
+constexpr year_month_weekday_last::year_month_weekday_last(const date::year& y, const date::month& m,
+                                                           const date::weekday_last& wdl) noexcept;
+
+ +
+

+Effects: Constructs an object of type year_month_weekday_last by +constructing y_ with y, m_ with m, +and wdl_ with wdl. +

+
+ +
+year_month_weekday_last& year_month_weekday_last::operator+=(const months& m) noexcept;
+
+ +
+

+Effects: *this = *this + m;. +

+

+Returns: *this. +

+
+ +
+year_month_weekday_last& year_month_weekday_last::operator-=(const months& m) noexcept;
+
+ +
+

+Effects: *this = *this - m;. +

+

+Returns: *this. +

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

+Effects: *this = *this + y;. +

+

+Returns: *this. +

+
+ +
+year_month_weekday_last& year_month_weekday_last::operator-=(const years& y) noexcept;
+
+ +
+

+Effects: *this = *this - y;. +

+

+Returns: *this. +

+
+ +
+constexpr year year_month_weekday_last::year() const noexcept;
+
+ +
+

+Returns: y_. +

+
+ +
+constexpr month year_month_weekday_last::month() const noexcept;
+
+ +
+

+Returns: m_. +

+
+ +
+constexpr weekday year_month_weekday_last::weekday() const noexcept;
+
+ +
+

+Returns: wdl_.weekday(). +

+
+ +
+constexpr weekday_last year_month_weekday_last::weekday_last() const noexcept;
+
+ +
+

+Returns: wdl_. +

+
+ +
+constexpr year_month_weekday_last::operator day_point() const noexcept;
+
+ +
+

+Requires: ok() == true. +

+

+Returns: A day_point which represents the date represented by +*this. +

+
+ +
+constexpr bool year_month_weekday_last::ok() const noexcept;
+
+ +
+

+Returns: If y_.ok() && m_.ok() && wdl_.ok(). +

+
+ +
+constexpr bool operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept;
+
+ +
+

+Returns: x.year() == y.year() && x.month() == y.month() && x.weekday_last() == y.weekday_last(). +

+
+ +
+constexpr bool operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept;
+
+ +
+

+Returns: !(x == y). +

+
+ +
+constexpr year_month_weekday_last operator+(const year_month_weekday_last& ymwdl, const months& dm) noexcept;
+
+ +
+

+Requires: ymwdl.ok() is true. +

+

+Returns: (ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last(). +

+

+Postconditions: The resultant year_month_weekday_last will return +true from ok(). +

+

+Complexity: O(1) with respect to the value of dm. +

+
+ +
+constexpr year_month_weekday_last operator+(const months& dm, const year_month_weekday_last& ymwdl) noexcept;
+
+ +
+

+Returns: ymwdl + dm. +

+
+ +
+constexpr year_month_weekday_last operator-(const year_month_weekday_last& ymwdl, const months& dm) noexcept;
+
+ +
+

+Returns: ymwdl + (-dm). +

+
+ +
+constexpr year_month_weekday_last operator+(const year_month_weekday_last& ymwdl, const years& dy) noexcept;
+
+ +
+

+Returns: {ymwdl.year()+dy, ymwdl.month(), ymwdl.weekday_last()}. +

+
+ +
+constexpr year_month_weekday_last operator+(const years& dy, const year_month_weekday_last& ymwdl) noexcept;
+
+ +
+

+Returns: ymwdl + dy. +

+
+ +
+constexpr year_month_weekday_last operator-(const year_month_weekday_last& ymwdl, const years& dy) noexcept;
+
+ +
+

+Returns: ymwdl + (-dy). +

+
+ +
+std::ostream& operator<<(std::ostream& os, const year_month_weekday_last& ymwdl);
+
+ +
+

+Effects: Inserts +os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last(). +

+

+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. y/m/d
  2. +
  3. m/d/y
  4. +
  5. d/m/y
  6. +
+ +

+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 "day" is required one can also specify one of: +

+ + + +

+Sub-field-types such as year_month and month_day can be created +by simply not applying the second division operator for any of the three orders. For +example: +

+ +
+year_month ym = 2015_y/apr;
+month_day md1 = apr/4;
+month_day md2 = 4_d/apr;
+
+ +

+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_month_day{year(2015), month(4), day(4)}
+auto c = 2015_y/4_d/apr; // error: invalid operands to binary expression ('date::year' and 'date::day')
+auto d = 2015/apr/4;     // error: invalid operands to binary expression ('int' and 'const date::month')
+
+ +

+The last example may be clear to a human reader. But the compiler doesn't know if +2015 refers to a year or a day. 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_month:

+ +
+constexpr year_month operator/(const year& y, const month& m) noexcept;
+
+ +
+Returns: {y, m}. +
+ +
+constexpr year_month operator/(const year& y, int   m) noexcept;
+
+ +
+Returns: y / month(m). +
+ +

 

+ +

month_day:

+ +
+constexpr month_day operator/(const month& m, const day& d) noexcept;
+
+ +
+Returns: {m, d}. +
+ +
+constexpr month_day operator/(const month& m, int d) noexcept;
+
+ +
+Returns: m / day(d). +
+ +
+constexpr month_day operator/(int m, const day& d) noexcept;
+
+ +
+Returns: month(m) / d. +
+ +
+constexpr month_day operator/(const day& d, const month& m) noexcept;
+
+ +
+Returns: m / d. +
+ +
+constexpr month_day operator/(const day& d, int m) noexcept;
+
+ +
+Returns: month(m) / d. +
+ +

 

+ +

month_day_last:

+ +
+constexpr month_day_last operator/(const month& m, last_spec) noexcept;
+
+ +
+Returns: month_day_last{m}. +
+ +
+constexpr month_day_last operator/(int m, last_spec) noexcept;
+
+ +
+Returns: month(m) / last. +
+ +
+constexpr month_day_last operator/(last_spec, const month& m) noexcept;
+
+ +
+Returns: m / last. +
+ +
+constexpr month_day_last operator/(last_spec, int m) noexcept;
+
+ +
+Returns: month(m) / last. +
+ +

 

+ +

month_weekday:

+ +
+constexpr month_weekday operator/(const month& m, const weekday_indexed& wdi) noexcept;
+
+ +
+Returns: {m, wdi}. +
+ +
+constexpr month_weekday operator/(int m, const weekday_indexed& wdi) noexcept;
+
+ +
+Returns: month(m) / wdi. +
+ +
+constexpr month_weekday operator/(const weekday_indexed& wdi, const month& m) noexcept;
+
+ +
+Returns: m / wdi. +
+ +
+constexpr month_weekday operator/(const weekday_indexed& wdi, int m) noexcept;
+
+ +
+Returns: month(m) / wdi. +
+ +

 

+ +

month_weekday_last:

+ +
+constexpr month_weekday_last operator/(const month& m, const weekday_last& wdl) noexcept;
+
+ +
+Returns: {m, wdl}. +
+ +
+constexpr month_weekday_last operator/(int m, const weekday_last& wdl) noexcept;
+
+ +
+Returns: month(m) / wdl. +
+ +
+constexpr month_weekday_last operator/(const weekday_last& wdl, const month& m) noexcept;
+
+ +
+Returns: m / wdl. +
+ +
+constexpr month_weekday_last operator/(const weekday_last& wdl, int m) noexcept;
+
+ +
+Returns: month(m) / wdl. +
+ +

 

+ +

year_month_day:

+ +
+constexpr year_month_day operator/(const year_month& ym, const day& d) noexcept;
+
+ +
+Returns: {ym.year(), ym.month(), d}. +
+ +
+constexpr year_month_day operator/(const year_month& ym, int d) noexcept;
+
+ +
+Returns: ym / day(d). +
+ +
+constexpr year_month_day operator/(const year& y, const month_day& md) noexcept;
+
+ +
+Returns: y / md.month() / md.day(). +
+ +
+constexpr year_month_day operator/(int y, const month_day& md) noexcept;
+
+ +
+Returns: year(y) / md. +
+ +
+constexpr year_month_day operator/(const month_day& md, const year& y) noexcept;
+
+ +
+Returns: y / md. +
+ +
+constexpr year_month_day operator/(const month_day& md, int y) noexcept;
+
+ +
+Returns: year(y) / md. +
+ +

 

+ +

year_month_day_last:

+ +
+constexpr year_month_day_last operator/(const year_month& ym, last_spec) noexcept;
+
+ +
+Returns: {ym.year(), month_day_last{ym.month()}}. +
+ +
+constexpr year_month_day_last operator/(const year& y, const month_day_last& mdl) noexcept;
+
+ +
+Returns: {y, mdl}. +
+ +
+constexpr year_month_day_last operator/(int y, const month_day_last& mdl) noexcept;
+
+ +
+Returns: year(y) / mdl. +
+ +
+constexpr year_month_day_last operator/(const month_day_last& mdl, const year& y) noexcept;
+
+ +
+Returns: y / mdl. +
+ +
+constexpr year_month_day_last operator/(const month_day_last& mdl, int y) noexcept;
+
+ +
+Returns: year(y) / mdl. +
+ +

 

+ +

year_month_weekday:

+ +
+constexpr year_month_weekday operator/(const year_month& ym, const weekday_indexed& wdi) noexcept;
+
+ +
+Returns: {ym.year(), ym.month(), wdi}. +
+ +
+constexpr year_month_weekday operator/(const year& y, const month_weekday& mwd) noexcept;
+
+ +
+Returns: {y, mwd.month(), mwd.weekday_indexed()}. +
+ +
+constexpr year_month_weekday operator/(int y, const month_weekday& mwd) noexcept;
+
+ +
+Returns: year(y) / mwd. +
+ +
+constexpr year_month_weekday operator/(const month_weekday& mwd, const year& y) noexcept;
+
+ +
+Returns: y / mwd. +
+ +
+constexpr year_month_weekday operator/(const month_weekday& mwd, int y) noexcept;
+
+ +
+Returns: year(y) / mwd. +
+ +

 

+ +

year_month_weekday_last:

+ +
+constexpr year_month_weekday_last operator/(const year_month& ym, const weekday_last& wdl) noexcept;
+
+ +
+Returns: {ym.year(), ym.month(), wdl}. +
+ +
+constexpr year_month_weekday_last operator/(const year& y, const month_weekday_last& mwdl) noexcept;
+
+ +
+Returns: {y, mwdl.month(), mwdl.weekday_last()}. +
+ +
+constexpr year_month_weekday_last operator/(int y, const month_weekday_last& mwdl) noexcept;
+
+ +
+Returns: year(y) / mwdl. +
+ +
+constexpr year_month_weekday_last operator/(const month_weekday_last& mwdl, const year& y) noexcept;
+
+ +
+Returns: y / mwdl. +
+ +
+constexpr year_month_weekday_last operator/(const month_weekday_last& mwdl, int y) noexcept;
+
+ +
+Returns: year(y) / mwdl. +
+ +
+ +

time_of_day

+ +
+

Overview

+ +
+template <class Duration> class time_of_day;
+
+ +

+The time_of_day class breaks a std::chrono::duration which +represents the time elapsed since midnight, into a "broken" down time such as +hours:minutes:seconds. The Duration template parameter dictates the +precision to which the time is broken down. This can vary from a course precision of +hours to a very fine precision of nanoseconds. +

+ +

+There are 4 specializations of time_of_day to handle four precisions: +

+ +
    + +
  1. +
    +time_of_day<std::chrono::hours>
    +
    +

    +This specialization handles hours since midnight. +

    +
  2. + +
  3. +
    +time_of_day<std::chrono::minutes>
    +
    +

    +This specialization handles hours:minutes since midnight. +

    +
  4. + +
  5. +
    +time_of_day<std::chrono::seconds>
    +
    +

    +This specialization handles hours:minutes:seconds since midnight. +

    +
  6. + +
  7. +
    +time_of_day<std::chrono::duration<Rep, Period>>
    +
    +

    +This specialization is restricted to Periods that are shorter than 1 +second. Typical uses are with milliseconds, microseconds and nanoseconds. This +specialization handles hours:minute:seconds.fractional_seconds since midnight. +

    +
  8. + +
+ +

Specification

+ +
+enum {am = 1, pm};
+
+ +

+Each specialization of time_of_day is a trivially copyable class type.
+Each specialization of time_of_day is a standard-layout class type.
+Each specialization of time_of_day is a literal class type.
+

+ +
+time_of_day<std::chrono::hours>
+{
+public:
+    using precision = std::chrono::hours;
+
+    constexpr explicit time_of_day(std::chrono::hours since_midnight) noexcept;
+    constexpr time_of_day(std::chrono::hours h, unsigned md) noexcept;
+
+    constexpr std::chrono::hours hours() const noexcept;
+    constexpr unsigned mode() const noexcept;
+
+    constexpr explicit operator precision() const noexcept;
+    constexpr precision to_duration() const noexcept;
+
+    void make24() noexcept;
+    void make12() noexcept;
+};
+
+ +
+constexpr explicit time_of_day<std::chrono::hours>::time_of_day(std::chrono::hours since_midnight) noexcept;
+
+ +
+

+Effects: Constructs an object of type time_of_day in 24-hour format +corresponding to since_midnight hours after 00:00:00. +

+

+Postconditions: hours() returns the integral number of hours +since_midnight is after 00:00:00. mode() returns 0. +

+
+ +
+constexpr time_of_day<std::chrono::hours>::time_of_day(std::chrono::hours h, unsigned md) noexcept;
+
+ +
+

+Preconditions: md == am or md == pm. +

+

+Effects: Constructs an object of type time_of_day in 12-hour format +corresponding to h hours after 00:00:00. +

+

+Postconditions: hours() returns h, and mode() +returns md. +

+
+ +
+constexpr std::chrono::hours time_of_day<std::chrono::hours>::hours() const noexcept;
+
+ +
+

+Returns: The stored hour of *this. +

+
+ +
+constexpr unsigned time_of_day<std::chrono::hours>::mode() const noexcept;
+
+ +
+

+Returns: 0 if *this is in 24-hour format. Otherwise returns +am or pm corresponding to whether this represents a before-noon +time or afternoon time. +

+
+ +
+constexpr explicit time_of_day<std::chrono::hours>::operator precision() const noexcept;
+
+ +
+

+Returns: The number of hours since midnight. +

+
+ +
+constexpr precision to_duration() const noexcept;
+
+ +
+

+Returns: precision{*this}. +

+
+ +
+void time_of_day<std::chrono::hours>::make24() noexcept;
+
+ +
+

+Effects: If *this is a 12-hour time, converts to a 24-hour time. +Otherwise, no effects. +

+
+ +
+void time_of_day<std::chrono::hours>::make12() noexcept;
+
+ +
+

+Effects: If *this is a 24-hour time, converts to a 12-hour time. +Otherwise, no effects. +

+
+ +
+std::ostream& operator<<(std::ostream& os, const time_of_day<std::chrono::hours>& t);
+
+ +
+

+Effects: If t is a 24-hour time, outputs to os +according to the strftime format: "%H00". "%H" will emit a leading 0 for +hours less than 10. +Else t is a 12-hour time, outputs to os +according to the strftime format: "%I%p" according to the C locale, except +that no leading zero is output for hours less than 10. +

+

+Returns: os. +

+

+Example: +

+
+0100  // 1 in the morning in 24-hour format
+1800  // 6 in the evening in 24-hour format
+1am   // 1 in the morning in 12-hour format
+6pm   // 6 in the evening in 12-hour format
+
+
+ +
+time_of_day<std::chrono::minutes>
+{
+public:
+    using precision = std::chrono::minutes;
+
+    constexpr explicit time_of_day(std::chrono::minutes since_midnight) noexcept;
+    constexpr time_of_day(std::chrono::hours h, std::chrono::minutes m,
+                          unsigned md) noexcept;
+
+    constexpr std::chrono::hours   hours() const noexcept;
+    constexpr std::chrono::minutes minutes() const noexcept;
+    constexpr unsigned mode() const noexcept;
+
+    constexpr explicit operator precision() const noexcept;
+    constexpr precision to_duration() const noexcept;
+
+    void make24() noexcept;
+    void make12() noexcept;
+};
+
+ +
+constexpr explicit time_of_day<std::chrono::minutes>::time_of_day(std::chrono::minutes since_midnight) noexcept;
+
+ +
+

+Effects: Constructs an object of type time_of_day in 24-hour format +corresponding to since_midnight minutes after 00:00:00. +

+

+Postconditions: hours() returns the integral number of hours +since_midnight is after 00:00:00. minutes() returns the +integral number of minutes since_midnight is after (00:00:00 + +hours()). mode() returns 0. +

+
+ +
+constexpr time_of_day<std::chrono::minutes>::time_of_day(std::chrono::hours h, std::chrono::minutes m,
+                                                               unsigned md) noexcept;
+
+ +
+

+Preconditions: md == am or md == pm. +

+

+Effects: Constructs an object of type time_of_day in 12-hour format +corresponding to h hours and m minutes after 00:00:00. +

+

+Postconditions: hours() returns h, minutes() +returns m, and mode() returns md. +

+
+ +
+constexpr std::chrono::hours time_of_day<std::chrono::minutes>::hours() const noexcept;
+
+ +
+

+Returns: The stored hour of *this. +

+
+ +
+constexpr std::chrono::minutes time_of_day<std::chrono::minutes>::minutes() const noexcept;
+
+ +
+

+Returns: The stored minute of *this. +

+
+ +
+constexpr unsigned time_of_day<std::chrono::minutes>::mode() const noexcept;
+
+ +
+

+Returns: 0 if *this is in 24-hour format. Otherwise returns +am or pm corresponding to whether this represents a before-noon +time or afternoon time. +

+
+ +
+constexpr explicit time_of_day<std::chrono::minutes>::operator precision() const noexcept;
+
+ +
+

+Returns: The number of minutes since midnight. +

+
+ +
+constexpr precision to_duration() const noexcept;
+
+ +
+

+Returns: precision{*this}. +

+
+ +
+void time_of_day<std::chrono::minutes>::make24() noexcept;
+
+ +
+

+Effects: If *this is a 12-hour time, converts to a 24-hour time. +Otherwise, no effects. +

+
+ +
+void time_of_day<std::chrono::minutes>::make12() noexcept;
+
+ +
+

+Effects: If *this is a 24-hour time, converts to a 12-hour time. +Otherwise, no effects. +

+
+ +
+std::ostream& operator<<(std::ostream& os, const time_of_day<std::chrono::minutes>& t);
+
+ +
+

+Effects: If t is a 24-hour time, outputs to os +according to the strftime format: "%H:%M". "%H" will emit a leading 0 for +hours less than 10. +Else t is a 12-hour time, outputs to os +according to the strftime format: "%I:%M%p" according to the C locale, except +that no leading zero is output for hours less than 10. +

+

+Returns: os. +

+

+Example: +

+
+01:08   // 1:08 in the morning in 24-hour format
+18:15   // 6:15 in the evening in 24-hour format
+1:08am  // 1:08 in the morning in 12-hour format
+6:15pm  // 6:15 in the evening in 12-hour format
+
+
+ +
+time_of_day<std::chrono::seconds>
+{
+public:
+    using precision = std::chrono::seconds;
+
+    constexpr explicit time_of_day(std::chrono::seconds since_midnight) noexcept;
+    constexpr time_of_day(std::chrono::hours h, std::chrono::minutes m,
+                          std::chrono::seconds s, unsigned md) noexcept;
+
+    constexpr std::chrono::hours   hours() const noexcept;
+    constexpr std::chrono::minutes minutes() const noexcept;
+    constexpr std::chrono::seconds seconds() const noexcept;
+    constexpr unsigned mode() const noexcept;
+
+    constexpr explicit operator precision() const noexcept;
+    constexpr precision to_duration() const noexcept;
+
+    void make24() noexcept;
+    void make12() noexcept;
+};
+
+ +
+constexpr explicit time_of_day<std::chrono::seconds>::time_of_day(std::chrono::seconds since_midnight) noexcept;
+
+ +
+

+Effects: Constructs an object of type time_of_day in 24-hour format +corresponding to since_midnight seconds after 00:00:00. +

+

+Postconditions: hours() returns the integral number of hours +since_midnight is after 00:00:00. minutes() returns the +integral number of minutes since_midnight is after (00:00:00 + +hours()). seconds() returns the integral number of seconds +since_midnight is after (00:00:00 + hours() + +minutes()). mode() returns 0. +

+
+ +
+constexpr time_of_day<std::chrono::seconds>::time_of_day(std::chrono::hours h, std::chrono::minutes m,
+                                                               std::chrono::seconds s, unsigned md) noexcept;
+
+ +
+

+Preconditions: md == am or md == pm. +

+

+Effects: Constructs an object of type time_of_day in 12-hour format +corresponding to h hours, m minutes, and s seconds +after 00:00:00. +

+

+Postconditions: hours() returns h. minutes() +returns m. seconds() returns s. +mode() returns md. +

+
+ +
+constexpr std::chrono::hours time_of_day<std::chrono::seconds>::hours() const noexcept;
+
+ +
+

+Returns: The stored hour of *this. +

+
+ +
+constexpr std::chrono::minutes time_of_day<std::chrono::seconds>::minutes() const noexcept;
+
+ +
+

+Returns: The stored minute of *this. +

+
+ +
+constexpr std::chrono::seconds time_of_day<std::chrono::seconds>::seconds() const noexcept;
+
+ +
+

+Returns: The stored second of *this. +

+
+ +
+constexpr unsigned time_of_day<std::chrono::seconds>::mode() const noexcept;
+
+ +
+

+Returns: 0 if *this is in 24-hour format. Otherwise returns +am or pm corresponding to whether this represents a before-noon +time or afternoon time. +

+
+ +
+constexpr explicit time_of_day<std::chrono::seconds>::operator precision() const noexcept;
+
+ +
+

+Returns: The number of seconds since midnight. +

+
+ +
+constexpr precision to_duration() const noexcept;
+
+ +
+

+Returns: precision{*this}. +

+
+ +
+void time_of_day<std::chrono::seconds>::make24() noexcept;
+
+ +
+

+Effects: If *this is a 12-hour time, converts to a 24-hour time. +Otherwise, no effects. +

+
+ +
+void time_of_day<std::chrono::seconds>::make12() noexcept;
+
+ +
+

+Effects: If *this is a 24-hour time, converts to a 12-hour time. +Otherwise, no effects. +

+
+ +
+std::ostream& operator<<(std::ostream& os, const time_of_day<std::chrono::seconds>& t);
+
+ +
+

+Effects: If t is a 24-hour time, outputs to os +according to the strftime format: "%H:%M%S". "%H" will emit a leading 0 for +hours less than 10. +Else t is a 12-hour time, outputs to os +according to the strftime format: "%I:%M%S%p" according to the C locale, except +that no leading zero is output for hours less than 10. +

+

+Returns: os. +

+

+Example: +

+
+01:08:03   // 1:08:03 in the morning in 24-hour format
+18:15:45   // 6:15:45 in the evening in 24-hour format
+1:08:03am  // 1:08:03 in the morning in 12-hour format
+6:15:45pm  // 6:15:45 in the evening in 12-hour format
+
+
+ +
+time_of_day<std::chrono::duration<Rep, Period>>
+{
+public:
+    using precision = std::chrono::duration<Rep, Period>;
+
+    constexpr explicit time_of_day(precision since_midnight) noexcept;
+    constexpr time_of_day(std::chrono::hours h, std::chrono::minutes m,
+                          std::chrono::seconds s, precision sub_s, unsigned md) noexcept;
+
+    constexpr std::chrono::hours   hours() const noexcept;
+    constexpr std::chrono::minutes minutes() const noexcept;
+    constexpr std::chrono::seconds seconds() const noexcept;
+    constexpr precision subseconds() const noexcept;
+    constexpr unsigned mode() const noexcept;
+
+    constexpr explicit operator precision() const noexcept;
+    constexpr precision to_duration() const noexcept;
+
+    void make24() noexcept;
+    void make12() noexcept;
+};
+
+ +

+This specialization shall not exist unless Period < 1s. +

+ +
+constexpr explicit time_of_day<std::chrono::duration<Rep, Period>>::time_of_day(precision since_midnight) noexcept;
+
+ +
+

+Effects: Constructs an object of type time_of_day in 24-hour format +corresponding to since_midnight precision fractional seconds after 00:00:00. +

+

+Postconditions: hours() returns the integral number of hours +since_midnight is after 00:00:00. minutes() returns the +integral number of minutes since_midnight is after (00:00:00 + +hours()). seconds() returns the integral number of seconds +since_midnight is after (00:00:00 + hours() + +minutes()). subseconds() returns the integral number of +fractional precision seconds since_midnight is after (00:00:00 + +hours() + minutes() + seconds). mode() +returns 0. +

+
+ +
+constexpr time_of_day<std::chrono::duration<Rep, Period>>::time_of_day(std::chrono::hours h, std::chrono::minutes m,
+                                                                       std::chrono::seconds s, precision sub_s,
+                                                                       unsigned md) noexcept;
+
+ +
+

+Preconditions: md == am or md == pm. +

+

+Effects: Constructs an object of type time_of_day in 12-hour format +corresponding to h hours, m minutes, and s + sub_s +seconds after 00:00:00. +

+

+Postconditions: hours() returns h. minutes() +returns m. seconds() returns s. +subseconds() returns sub_s. mode() returns +md. +

+
+ +
+constexpr std::chrono::hours time_of_day<std::chrono::duration<Rep, Period>>::hours() const noexcept;
+
+ +
+

+Returns: The stored hour of *this. +

+
+ +
+constexpr std::chrono::minutes time_of_day<std::chrono::duration<Rep, Period>>::minutes() const noexcept;
+
+ +
+

+Returns: The stored minute of *this. +

+
+ +
+constexpr std::chrono::seconds time_of_day<std::chrono::duration<Rep, Period>>::seconds() const noexcept;
+
+ +
+

+Returns: The stored second of *this. +

+
+ +
+constexpr
+std::chrono::duration<Rep, Period>
+time_of_day<std::chrono::duration<Rep, Period>>::subseconds() const noexcept;
+
+ +
+

+Returns: The stored subsecond of *this. +

+
+ +
+constexpr unsigned time_of_day<std::chrono::duration<Rep, Period>>::mode() const noexcept;
+
+ +
+

+Returns: 0 if *this is in 24-hour format. Otherwise returns +am or pm corresponding to whether this represents a before-noon +time or afternoon time. +

+
+ +
+constexpr explicit time_of_day<std::chrono::duration<Rep, Period>>::operator precision() const noexcept;
+
+ +
+

+Returns: The number of subseconds since midnight. +

+
+ +
+constexpr precision to_duration() const noexcept;
+
+ +
+

+Returns: precision{*this}. +

+
+ +
+void time_of_day<std::chrono::duration<Rep, Period>>::make24() noexcept;
+
+ +
+

+Effects: If *this is a 12-hour time, converts to a 24-hour time. +Otherwise, no effects. +

+
+ +
+void time_of_day<std::chrono::duration<Rep, Period>>::make12() noexcept;
+
+ +
+

+Effects: If *this is a 24-hour time, converts to a 12-hour time. +Otherwise, no effects. +

+
+ +
+std::ostream& operator<<(std::ostream& os, const time_of_day<std::chrono::duration<Rep, Period>>& t);
+
+ +
+

+Effects: If t is a 24-hour time, outputs to os +according to the strftime format: "%H:%M%S.%s". "%H" will emit a leading 0 for +hours less than 10. "%s" is not a strftime code and represents the fractional +seconds. +Else t is a 12-hour time, outputs to os +according to the strftime format: "%I:%M%S.%s%p" according to the C locale, except +that no leading zero is output for hours less than 10. +

+

+Returns: os. +

+

+Example: +

+
+01:08:03.007   // 1:08:03.007 in the morning in 24-hour format (assuming millisecond precision)
+18:15:45.123   // 6:15:45.123 in the evening in 24-hour format (assuming millisecond precision)
+1:08:03.007am  // 1:08:03.007 in the morning in 12-hour format (assuming millisecond precision)
+6:15:45.123pm  // 6:15:45.123 in the evening in 12-hour format (assuming millisecond precision)
+
+
+ +
+ +

make_time

+ +
+ +
+template <class Rep, class Period>
+constexpr
+time_of_day<std::chrono::duration<Rep, Period>>
+make_time(std::chrono::duration<Rep, Period> d) noexcept;
+
+ +
+

+Returns: time_of_day<std::chrono::duration<Rep, Period>>(d). +

+
+ +
+constexpr
+time_of_day<std::chrono::hours>
+make_time(std::chrono::hours h, unsigned md) noexcept;
+
+ +
+

+Returns: time_of_day<std::chrono::hours>(h, md). +

+
+ +
+constexpr
+time_of_day<std::chrono::minutes>
+make_time(std::chrono::hours h, std::chrono::minutes m, unsigned md) noexcept;
+
+ +
+

+Returns: time_of_day<std::chrono::minutes>(h, m, md). +

+
+ +
+constexpr
+time_of_day<std::chrono::seconds>
+make_time(std::chrono::hours h, std::chrono::minutes m, std::chrono::seconds s,
+          unsigned md) noexcept;
+
+ +
+

+Returns: time_of_day<std::chrono::seconds>(h, m, s, md). +

+
+ +
+template <class Rep, class Period,
+          class = std::enable_if_t<std::ratio_less<Period, std::ratio<1>>::value>>
+constexpr
+time_of_day<std::chrono::duration<Rep, Period>>
+make_time(std::chrono::hours h, std::chrono::minutes m, std::chrono::seconds s,
+          std::chrono::duration<Rep, Period> sub_s, unsigned md) noexcept
+
+ +
+

+Returns: time_of_day<std::chrono::duration<Rep, Period>>(h, m, s, sub_s, md). +

+
+ +
+ +
+template <class Duration>
+inline
+std::ostream&
+operator<<(std::ostream& os,
+           const std::chrono::time_point<std::chrono::system_clock, Duration>& tp);
+
+ +
+

+Remarks: This operator shall not participate in overload resolution if +std::chrono::treat_as_floating_point<typename Duration::rep>::value is +true. +

+

+Effects: If Duration{1} < days{1}: +

+
+auto const dp = floor<days>(tp);
+os << year_month_day(dp) << ' ' << make_time(tp-dp);
+
+

+Otherwise: +

+
+os << year_month_day(floor<days>(tp));
+
+ +

+Returns: os. +

+
+ + + diff --git a/iso_week.html b/iso_week.html new file mode 100644 index 0000000..4e5a812 --- /dev/null +++ b/iso_week.html @@ -0,0 +1,2924 @@ + + + + iso_week + + + + + +
+
+
+Howard E. Hinnant
+2015-12-23
+ Creative
+Commons License
This work is licensed +under a Creative +Commons Attribution 4.0 International License. +
+
+

iso_week

+ +

Contents

+ + + +

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 day_point. And + day_point is just a type alias for: +

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

+This is the exact same day_point used by the +date and time zone +libraries. And so by simply having conversions to and from day_point, +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 day_point. 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 
 day_point
  
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 +day_points. +

+
+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>>;
+
+ +

day_point

+ +
+

+day_point is a std::chrono::time_point using +std::chrono::system_clock and days. This makes +day_point 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. day_point is a serial-based time point with a resolution of +days. +

+
+using day_point = 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 day_point& 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 day_point. 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 day_point& dp) noexcept;
+
+ +
+

+Effects: Constructs an object of type weekday by computing what day +of the week corresponds to the day_point 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 +day_point{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 +day_point{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 day_point& 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 day_point() 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 day_point. 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 day_point& 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{day_point{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 day_point() const noexcept;
+
+ +
+

+Returns: A day_point 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 day_point() 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 day_point. +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 day_point() const noexcept;
+
+ +
+

+Returns: A day_point 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. +
  3. weeknum/weekday/year
  4. +
  5. weekday/weeknum/year
  6. +
+ +

+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}. +
+ +
+ + + diff --git a/tz.html b/tz.html new file mode 100644 index 0000000..a633e72 --- /dev/null +++ b/tz.html @@ -0,0 +1,2106 @@ + + + + Time Zone Database Parser + + + + + +
+
+
+Howard E. Hinnant
+2016-04-09
+ Creative
+Commons License
This work is licensed +under a Creative +Commons Attribution 4.0 International License. +
+
+

Time Zone Database Parser

+ +

Contents

+ + + +

Introduction

+ +

+I had just completed writing date, which is a +library for extending <chrono> into the realm of calendars, and I was +looking around for the most challenging date time problem I could find with which I could +demonstrate the power of this new library. "I know," I said to myself, "I'll handle all +the world's time zones, and maybe even leap seconds!" Thus began my journey into a +rabbit hole which I knew existed, but had never truly appreciated the intricacies of. +

+ +

+This library adds timezone and leap second support to this date + library. This is a separate library from date +because many clients of date do not need timezone +nor leap second support, and this support does not come for free (though the cost is quite +reasonable). +

+ +

+This library is a complete parser of the IANA Time Zone Database. This database contains +timezone information that represents the history of local time for many representative +locations around the globe. It is updated periodically to reflect changes made by +political bodies to time zone boundaries, UTC offsets, and daylight-saving rules. The +database also maintains a list of leap seconds from 1972 through the present. +

+ +

+The IANA Time Zone Database contains four +specific types of data: +

+ +
    +
  1. +Zone: A geographic location with a human-readable name (e.g. "America/New_York") which +specifies the offset from UTC and an abbreviation for the zone. This data includes +daylight saving rules, if applicable, for the zone. This data is not only the rules +currently in effect for the region, but also includes specifications dating back to at +least 1970, and in most cases dating back to the mid 1800's (when uniform time was +first introduced across regions larger than individual towns and cities). +

  2. +
  3. +Rule: A specification for a single daylight-saving rule. This helps implement and +consolidate the specifications of Zones. +

  4. +
  5. +Link: This is an alternative name for a Zone. +

  6. +
  7. +Leap: The date of the insertion of a leap second. +

  8. +
+ +

+The library documented herein provides access to all of this data, and offers +efficient and convenient ways to compute with it. And this is all done based on the date library, which in turn is based on the C++11/14 +<chrono> library. So once you've learned those fundamental libraries, +the learning curve for this library is greatly eased. +

+ +

Overview

+ +

+Like date, this library revolves around +std::chrono::system_clock. Thus it is important to understand the properties +of this foundation. std::chrono::system_clock has nested types including +time_point and duration, and a static function called +now which returns a time_point. This time_point +measures time against some unspecified epoch using the units of duration. +

+ +
+namespace std { namespace chrono {
+
+class system_clock
+{
+public:
+    using duration   = microseconds;
+    using time_point = chrono::time_point<system_clock>;
+    // other types ...
+
+    static time_point now() noexcept;
+    // other member functions ...
+};
+
+}} // namespace std::chrono
+
+ +

+The use of microseconds above for the duration type is just +an example. This is what is used for libc++ on +OS X. Other implementations may use +other units such as nanoseconds. But one unspecified property that all +implementations of std::chrono::system_clock have in common is that they +all model Unix time. +

+ +

+Unix time counts the number of +seconds since 1970-01-01 00:00:00 UTC, except that leap seconds are ignored in the count. +An interesting and useful property of +Unix time is that it treats leap +seconds as nothing more than a typical clock correction. That is, no clock keeps perfect +time, not even the one in your computer. And several times a day your computer will ask +another computer what time it is, and typically correct itself by a small fraction of a +second. +

+ +

+When a leap second occurs, instead of counting an extra second, +Unix time reacts by saying, oh, I'm +off by a second, I'll slow down or speed up to correct. Companies such as Google will +"smear" the application of a leap second over a period of hours, letting their +Unix time counters adjust by +milliseconds, or even microseconds at a time, so that the insertion of a leap second is +virtually undetectable to applications running on the computer. +

+ +

+It is this de-facto standard based on +Unix time that allows +date to portably convert a count of microseconds +(for example) into field-based structures containing year/month/day and +hours::minutes::seconds.microseconds. And when you need to further convert +the system_clock::time_point into a local time, and/or take leap seconds into +account, the library documented herein handles it by accessing your local copy of the +IANA Time Zone Database. +

+ +

Synopsis

+ +

+This synopsis provides nothing but a quick overview of the documented API of this library. +If you don't see it in the synopsis below, it is not a documented part of this library. +

+ +
+namespace date
+{
+
+using second_point = std::chrono::time_point<std::chrono::system_clock,
+                                             std::chrono::seconds>;
+
+struct Info
+{
+    second_point         begin;
+    second_point         end;
+    std::chrono::seconds offset;
+    std::chrono::minutes save;
+    std::string          abbrev;
+};
+
+std::ostream&
+operator<<(std::ostream& os, const Info& r);
+
+enum class tz {utc, local};
+enum class choose {earliest, latest};
+
+class nonexistent_local_time
+    : public std::runtime_error
+{
+public:
+};
+
+class ambiguous_local_time
+    : public std::runtime_error
+{
+public:
+};
+
+class Zone
+{
+public:
+    const std::string& name() const;
+
+    template <class Rep, class Period>
+    std::pair
+    <
+        std::chrono::time_point<std::chrono::system_clock,
+            typename std::common_type<std::chrono::duration<Rep, Period>,
+                                      std::chrono::seconds>::type>,
+        std::string
+    >
+    to_local(std::chrono::time_point<std::chrono::system_clock,
+                                     std::chrono::duration<Rep, Period>> tp) const;
+
+    template <class Rep, class Period>
+    std::chrono::time_point<std::chrono::system_clock,
+        typename std::common_type<std::chrono::duration<Rep, Period>,
+                                  std::chrono::seconds>::type>
+    to_sys(std::chrono::time_point<std::chrono::system_clock,
+                                   std::chrono::duration<Rep, Period>> tp) const;
+
+    template <class Rep, class Period>
+    std::chrono::time_point<std::chrono::system_clock,
+        typename std::common_type<std::chrono::duration<Rep, Period>,
+                                  std::chrono::seconds>::type>
+    to_sys(std::chrono::time_point<std::chrono::system_clock,
+                                   std::chrono::duration<Rep, Period>> tp,
+           choose z) const;
+
+    template <class Rep, class Period>
+    Info
+    get_info(std::chrono::time_point<std::chrono::system_clock,
+                                     std::chrono::duration<Rep, Period>> tp,
+             tz timezone) const;
+};
+
+const Zone* locate_zone(const std::string& tz_name);
+const Zone* current_zone();
+
+bool operator==(const Zone& x, const Zone& y);
+bool operator!=(const Zone& x, const Zone& y);
+bool operator< (const Zone& x, const Zone& y);
+bool operator> (const Zone& x, const Zone& y);
+bool operator<=(const Zone& x, const Zone& y);
+bool operator>=(const Zone& x, const Zone& y);
+
+std::ostream& operator<<(std::ostream& os, const Zone& z);
+
+class Link
+{
+public:
+    const std::string& name() const;
+    const std::string& target() const;
+};
+
+bool operator==(const Link& x, const Link& y);
+bool operator!=(const Link& x, const Link& y);
+bool operator< (const Link& x, const Link& y);
+bool operator> (const Link& x, const Link& y);
+bool operator<=(const Link& x, const Link& y);
+bool operator>=(const Link& x, const Link& y);
+
+std::ostream& operator<<(std::ostream& os, const Link& x);
+
+class Leap
+{
+public:
+    second_point date() const;
+};
+
+bool operator==(const Leap& x, const Leap& y);
+bool operator!=(const Leap& x, const Leap& y);
+bool operator< (const Leap& x, const Leap& y);
+bool operator> (const Leap& x, const Leap& y);
+bool operator<=(const Leap& x, const Leap& y);
+bool operator>=(const Leap& x, const Leap& y);
+
+std::ostream& operator<<(std::ostream& os, const Leap& x);
+
+template <class Duration>
+bool
+operator==(const Leap& x,
+           const std::chrono::time_point<std::chrono::system_clock, Duration>& y);
+
+template <class Duration>
+bool
+operator==(const std::chrono::time_point<std::chrono::system_clock, Duration>& x,
+           const Leap& y);
+
+template <class Duration>
+bool
+operator!=(const Leap& x,
+           const std::chrono::time_point<std::chrono::system_clock, Duration>& y);
+
+template <class Duration>
+bool
+operator!=(const std::chrono::time_point<std::chrono::system_clock, Duration>& x,
+           const Leap& y);
+
+template <class Duration>
+bool
+operator< (const Leap& x,
+           const std::chrono::time_point<std::chrono::system_clock, Duration>& y);
+
+template <class Duration>
+bool
+operator< (const std::chrono::time_point<std::chrono::system_clock, Duration>& x,
+           const Leap& y);
+
+template <class Duration>
+bool
+operator> (const Leap& x,
+           const std::chrono::time_point<std::chrono::system_clock, Duration>& y);
+
+template <class Duration>
+bool
+operator> (const std::chrono::time_point<std::chrono::system_clock, Duration>& x,
+           const Leap& y);
+
+template <class Duration>
+bool
+operator<=(const Leap& x,
+           const std::chrono::time_point<std::chrono::system_clock, Duration>& y);
+
+template <class Duration>
+bool
+operator<=(const std::chrono::time_point<std::chrono::system_clock, Duration>& x,
+           const Leap& y);
+
+template <class Duration>
+bool
+operator>=(const Leap& x,
+           const std::chrono::time_point<std::chrono::system_clock, Duration>& y);
+
+template <class Duration>
+bool
+operator>=(const std::chrono::time_point<std::chrono::system_clock, Duration>& x,
+           const Leap& y);
+
+class Rule;
+
+struct TZ_DB
+{
+    std::string       version;
+    std::vector<Zone> zones;
+    std::vector<Link> links;
+    std::vector<Leap> leaps;
+    std::vector<Rule> rules;
+};
+
+std::ostream& operator<<(std::ostream& os, const TZ_DB& db);
+
+const TZ_DB& get_tzdb();
+const TZ_DB& reload_tzdb();
+
+#if HAS_REMOTE_API
+std::string remote_version();
+bool        remote_download(const std::string& version);
+bool        remote_install(const std::string& version);
+#endif
+
+class utc_clock
+{
+public:
+    using duration                  = std::chrono::system_clock::duration;
+    using rep                       = duration::rep;
+    using period                    = duration::period;
+    using time_point                = std::chrono::time_point<utc_clock>;
+    static constexpr bool is_steady = true;
+
+    static time_point now() noexcept;
+
+    template <class Duration>
+        static
+        std::chrono::time_point<utc_clock,
+            typename std::common_type<Duration, std::chrono::seconds>::type>
+        sys_to_utc(std::chrono::time_point<std::chrono::system_clock, Duration> t);
+
+    template <class Duration>
+        static
+        std::chrono::time_point<std::chrono::system_clock,
+            typename std::common_type<Duration, std::chrono::seconds>::type>
+        utc_to_sys(std::chrono::time_point<utc_clock, Duration> t);
+};
+
+template <class Duration>
+std::string
+format(const std::locale& loc, std::string format,
+       std::chrono::time_point<std::chrono::system_clock, Duration> tp,
+       const Zone* zone = nullptr);
+
+std::string
+format(const std::locale& loc, std::string format, day_point tp,
+       const Zone* zone = nullptr);
+
+template <class Duration>
+std::string
+format(std::string format,
+       std::chrono::time_point<std::chrono::system_clock, Duration> tp,
+       const Zone* zone = nullptr);
+
+std::string
+format(std::string format, day_point tp, const Zone* zone = nullptr);
+
+template <class Duration>
+void
+parse(std::istream& is, const std::string& format,
+      std::chrono::time_point<std::chrono::system_clock, Duration>& tp);
+
+template <class Duration>
+void
+parse(std::istream& is, const std::string& format,
+      std::chrono::time_point<std::chrono::system_clock, Duration>& tp,
+      std::string& abbrev);
+
+}  // namespace date
+
+ +

Description

+ +

+Everything documented below is in namespace date. Explicit references to +this namespace in example code below is intentionally omitted in the hopes of reducing +verbosity. +

+ +

The Database

+ +

+The database is represented with the type TZ_DB: +

+ +
+struct TZ_DB
+{
+    std::string       version;
+    std::vector<Zone> zones;
+    std::vector<Link> links;
+    std::vector<Leap> leaps;
+    std::vector<Rule> rules;
+};
+
+ +

+This is a singleton class. You can get a const TZ_DB& to the singleton +using this function: +

+ +
+const TZ_DB& get_tzdb();
+
+ +

+The first call to get_tzdb() will initialize the database from your local +copy of the IANA Time Zone Database located +at install (a file-scope variable of type std::string in +tz.cpp). +You will need to catch the return of this function by const& as the +TZ_DB is not constructible from a const TZ_DB. This can be done +with the following example code: +

+ +
+auto& db = get_tzdb();
+
+ +

+With a reference to the database in hand, you have read-only access to the entire +database, which is nothing more than sorted vectors for the four types of +data contained in the database. With such a reference you could (for example) print the +names of all the Zones in the database: +

+ +
+for (auto& z : db.zones)
+    std::cout << z.name() << '\n';
+
+ +

+There are currently 377 zones in the database. +

+ +

+Or you could output the 89 Links, including their name() and +target(): +

+ +
+for (auto& link : db.links)
+    std::cout << link << '\n';
+
+ +

+If you aren't happy with the format this outputs in, Link has public member +functions name() and target() so that you can achieve whatever +format you desire. +

+ +

+If needed, db.version is a std::string containing the +IANA Time Zone Database version of the +database you are reading. For example the current version when this sentence +was written was "2016a". +

+ +

+You can even print the entire database out in a semi-human-readable format if desired: +

+ +
+std::cout << db << '\n';
+
+ +

+If you constrain the geography or history of the database during installation, those +constraints will be reflected in these examples. +

+ +

+If you decide you need to reload the database say, because you want to install a new +version of the IANA Time Zone Database +without stopping your program, you can use this function: +

+ +
+const TZ_DB& reload_tzdb();
+
+ +

+This re-initializes the database by reading from the install location you +customized on installation. The use of the reload_tzdb function is not +pain-free, and not for every application (not for most of them I'm guessing). For example +see the Thread Safety section for issues related to the use of these functions. +

+ +

The remote API

+ +

+The remote API is enabled only if HAS_REMOTE_API is set to 1 during +compilation. See Installation for more details. +

+ +
+std::string remote_version();
+
+ +

+This function will query the +IANA Time Zone Database website for the +latest version number of the IANA database, and return it as a std::string. +If an internet connection can not be made, an empty string is returned. +This string can be compared against the version of your local copy of the database: +get_tzdb().version. +

+ +
+bool remote_download(const std::string& version);
+
+ +

+This function will attempt to download the database with the version version +from the IANA Time Zone Database website. +If successful, true is returned and a file named +version + ".tar.gz" will be stored at the location install. +If not successful, false is returned. +

+ +
+bool remote_install(const std::string& version);
+
+ +

+This function will attempt to uncompress the tar file downloaded by +remote_download(version) and replace any existing database with +the result. It will then delete the tar file. If the tar file doesn't exist, +remote_install will do nothing. Returns true on +success, else returns false. +

+ +

Zone

+ +

+The Zone class is the most important type in this library. It provides the +main access to the functionality provided by this library. Each Zone is +named, represents a geographic area, and provides a mapping between UTC and the local +time, in both directions. This mapping from local time to UTC is in general not one to +one. The mapping, and even the specific rule, depends upon the input +time_point, which can represent either UTC or local time. +

+ +

+The detailed API of the Zone class depends upon a small amount of +infrastructure which is introduced first. +

+ +

Infrastructure

+ +
+using second_point = std::chrono::time_point<std::chrono::system_clock,
+                                             std::chrono::seconds>;
+
+ +

+second_point is a std::chrono::time_point based on +system_clock but with the precision of seconds. This library +will interoperate with system_clock::time_points of any precision. +However the data in the database is largely based on second_point, and +some of the data which is presented, such as that in the Info class, uses +this type alias as a convenience, and to reduce verbosity. second_point +will implicitly convert to system_clock::time_point. And coarser +time_points such as the day_point from the +date library will implicitly convert to +second_point. +

+ +
+struct Info
+{
+    second_point         begin;
+    second_point         end;
+    std::chrono::seconds offset;
+    std::chrono::minutes save;
+    std::string          abbrev;
+};
+
+ +

+The Info struct is the return type of the get_info member +function of the Zone class. It contains very detailed information about the +Zone at the time_point (UTC or local) input into this member +function. Info contains no pointers or references into the database. +Therefore clients do not need to be concerned about holding on to Infos +during a call to reload_tzdb(). Though a call to reload_tzdb() +could potentially make the data in an outstanding Info obsolete. See +Zone::get_info for more details. +

+ +
+enum class tz {utc, local};
+enum class choose {earliest, latest};
+
+ +

+These enums are used as input to some of the Zone member +functions. tz::utc indicates that a time_point represents a +time in the UTC time zone. tz::local indicates that a +time_point represents a time in the Zone's local time zone. +The choose enum allows a client to specify how a mapping from local to UTC +should behave when the mapping is not one to one. Alternatively one can not specify +a policy in the mapping, and if the mapping is not unique, an exception will be thrown. +

+ +
+class nonexistent_local_time
+    : public std::runtime_error
+{
+public:
+    const char* what() const override;
+};
+
+class ambiguous_local_time
+    : public std::runtime_error
+{
+public:
+    const char* what() const override;
+};
+
+ +

+These are the exception classes thrown by the local to UTC mapping. In addition to their +type indicating the nature of the exceptional circumstance, they also sport a +what() member function that will contain a very detailed explanation +including specific times for the specific time_points involved in the +attempted mapping. +

+ +

+If in a call to Zone::to_sys the local time_point falls into a +"gap" for which no local time exists, a nonexistent_local_time exception is +thrown. +

+ +

+If in a call to Zone::to_sys the local time_point has an +ambiguous mapping to UTC, a ambiguous_local_time exception is thrown. +

+ +

+Either exceptional situation can be circumvented with the use of +choose::earliest or choose::latest in the call to +to_sys. +

+ +

Zone continued

+ +
+class Zone
+{
+public:
+    const std::string& name() const;
+
+    template <class Rep, class Period>
+    std::pair
+    <
+        std::chrono::time_point<std::chrono::system_clock,
+            typename std::common_type<std::chrono::duration<Rep, Period>,
+                                      std::chrono::seconds>::type>,
+        std::string
+    >
+    to_local(std::chrono::time_point<std::chrono::system_clock,
+                                     std::chrono::duration<Rep, Period>> tp) const;
+
+    template <class Rep, class Period>
+    std::chrono::time_point<std::chrono::system_clock,
+        typename std::common_type<std::chrono::duration<Rep, Period>,
+                                  std::chrono::seconds>::type>
+    to_sys(std::chrono::time_point<std::chrono::system_clock,
+                                   std::chrono::duration<Rep, Period>> tp) const;
+
+    template <class Rep, class Period>
+    std::chrono::time_point<std::chrono::system_clock,
+        typename std::common_type<std::chrono::duration<Rep, Period>,
+                                  std::chrono::seconds>::type>
+    to_sys(std::chrono::time_point<std::chrono::system_clock,
+                                   std::chrono::duration<Rep, Period>> tp,
+           choose z) const;
+
+    template <class Rep, class Period>
+    Info
+    get_info(std::chrono::time_point<std::chrono::system_clock,
+                                     std::chrono::duration<Rep, Period>> tp,
+             tz timezone) const;
+};
+
+const Zone* locate_zone(const std::string& tz_name);
+const Zone* current_zone();
+
+bool operator==(const Zone& x, const Zone& y);
+bool operator!=(const Zone& x, const Zone& y);
+bool operator< (const Zone& x, const Zone& y);
+bool operator> (const Zone& x, const Zone& y);
+bool operator<=(const Zone& x, const Zone& y);
+bool operator>=(const Zone& x, const Zone& y);
+
+std::ostream& operator<<(std::ostream& os, const Zone& z);
+
+ +

+The entire public API of the Zone is const. Once the database +is initialized (or reloaded), Zones are set in concrete. +

+ +
+ +

+The current time zone associated with your computer can be retrieved with the namespace +scope function current_zone(). For example: +

+ +
+std::cout << current_zone()->name() << '\n';
+
+ +

+For me the above currently outputs America/New_York. +

+ +
+ +
+const Zone* locate_zone(const std::string& tz_name);
+
+ +

+locate_zone returns a pointer to a Zone in the database +associated with tz_name. If it can't find a Zone named +tz_name, the implementation will search for a Link named +tz_name, and then return the Zone associated with the +Link's target(). If tz_name can not be found in the +database, a std::runtime_error is thrown. +

+ +

+Example: +

+ +
+try
+{
+    cout << locate_zone("Europe/London")->name() << '\n';     // A Zone
+    cout << locate_zone("Europe/Jersey")->name() << '\n';     // A Link to a Zone
+    cout << locate_zone("Europe/New_Jersey")->name() << '\n'; // Doesn't exist
+}
+catch (const exception& e)
+{
+    cout << e.what() << '\n';
+}
+
+ +

+Which outputs: +

+ +
+Europe/London
+Europe/London
+Europe/New_Jersey not found in timezone database
+
+ +

+Note that locate_zone never returns nullptr. Also note that +the first call to locate_zone may implicitly initialize the database. +

+ +
+ +
+template <class Rep, class Period>
+std::pair
+<
+    std::chrono::time_point<std::chrono::system_clock,
+        typename std::common_type<std::chrono::duration<Rep, Period>,
+                                  std::chrono::seconds>::type>,
+    std::string
+>
+to_local(std::chrono::time_point<std::chrono::system_clock,
+                                 std::chrono::duration<Rep, Period>> tp) const;
+
+ +

+to_local maps a system_clock-associated time_point +from UTC to local time, returning both the mapped time_point and an +abbreviation for the local time zone. This member function accepts any precision +time_point, but returns a time_point with a precision of +seconds or finer. This is done because it is possible that some of the +mappings returned by the database need the precision of a second. +

+ +

+There are only two ways this function can fail: +

+ +
    +
  1. +Out of memory error. Not bloody likely. The only memory that possibly could be +allocated is for the abbreviation stored in a std::string and all known +implementations will fit all known abbreviations into their short string buffer. +

  2. +
  3. +If you curtailed history during installation, a runtime_error will be thrown +if tp refers to a time_point outside of the range +min_year/jan/1 00:00:00 to max_year/dec/31 23:59:59. This can +not happen with the default settings of min_year and max_year. +

  4. +
+ +

+Example: +

+ +
+auto local = current_zone()->to_local(system_clock::now());
+cout << local.first << ' ' << local.second << '\n';
+
+ +

+Which just output for me: +

+ +
+2015-07-12 16:57:14.430467 EDT
+
+ +

+Not quite 5pm in the US Eastern timezone during daylight saving time. +

+ +

+And for a historical example: +

+ +
+auto distant_past = locate_zone("America/New_York")->to_local(day_point(feb/9/1942) + 7h);
+cout << distant_past.first << ' ' << distant_past.second << '\n';
+
+ +

+Which outputs: +

+ +
+1942-02-09 03:00:00 EWT
+
+ +

+The US shifted to "War Time." +

+ +
+ +

+If you want to go the other direction (from local time to UTC) use: +

+ +
+template <class Rep, class Period>
+std::chrono::time_point<std::chrono::system_clock,
+    typename std::common_type<std::chrono::duration<Rep, Period>,
+                              std::chrono::seconds>::type>
+to_sys(std::chrono::time_point<std::chrono::system_clock,
+                               std::chrono::duration<Rep, Period>> tp) const;
+
+ +

+For example: +

+ +
+auto distant_past = locate_zone("America/New_York")->to_sys(day_point(feb/9/1942) + 3h);
+cout << distant_past << ' ' << " UTC\n";
+
+ +

+Which outputs: +

+ +
+1942-02-09 07:00:00 UTC
+
+ +

+This function will throw an exception of type nonexistent_local_time if the +local time does not exist. This can happen when the local clock is discontinuously set +forward, such as when moving from standard time to daylight savings time. +

+ +

+For example: +

+ +
+try
+{
+    auto distant_past = locate_zone("America/New_York")->to_sys(day_point(feb/9/1942) + 3h - 1ms);
+    cout << distant_past << ' ' << " UTC\n";
+}
+catch (const exception& e)
+{
+    cout << e.what() << '\n';
+}
+
+ +

+Which outputs: +

+ +
+1942-02-09 02:59:59.999 is in a gap between
+1942-02-09 02:00:00 EST and
+1942-02-09 03:00:00 EWT which are both equivalent to
+1942-02-09 07:00:00 UTC
+
+ +

+And sometimes a local time can be ambiguous, mapping to more than one UTC time: +

+ +
+try
+{
+    auto distant_past = locate_zone("America/New_York")->to_sys(day_point(sep/30/1945) + 2h - 1ns);
+    cout << distant_past << " UTC\n";
+}
+catch (const exception& e)
+{
+    cout << e.what() << '\n';
+}
+
+ +
+1945-09-30 01:59:59.999999999 is ambiguous.  It could be
+1945-09-30 01:59:59.999999999 EPT == 1945-09-30 05:59:59.999999999 UTC or
+1945-09-30 01:59:59.999999999 EST == 1945-09-30 06:59:59.999999999 UTC
+
+ +
+ +

+If you would rather not deal with these rare exceptions, you can choose ahead of time +to select the earliest time or latest time when a local time falls into a gap: +

+ +
+auto z = locate_zone("America/New_York");
+auto distant_past = z->to_sys(day_point(sep/30/1945) + 2h - 1ns, choose::earliest);
+cout << distant_past << " UTC\n";
+distant_past =      z->to_sys(day_point(sep/30/1945) + 2h - 1ns, choose::latest);
+cout << distant_past << " UTC\n";
+
+ +

+Which outputs: +

+ +
+1945-09-30 05:59:59.999999999 UTC
+1945-09-30 06:59:59.999999999 UTC
+
+ +

+When using this form of to_sys and the local time is non-existent, both +choices will map to the single UTC time on either side of the gap: +

+ +
+auto z = locate_zone("America/New_York");
+auto distant_past = z->to_sys(day_point(feb/9/1942) + 3h - 1ms, choose::earliest);
+cout << distant_past << " UTC\n";
+distant_past =      z->to_sys(day_point(feb/9/1942) + 3h - 1ms, choose::latest);
+cout << distant_past << " UTC\n";
+
+ +

+Which outputs: +

+ +
+1942-02-09 07:00:00.000 UTC
+1942-02-09 07:00:00.000 UTC
+
+ +
+ +

+So far I've shown how given a Zone and a system_clock::time_point +of arbitrary precision, you can use to_local to map UTC to local time, and +to_sys to map local time to UTC, with your choice of either detecting any +errors, or choosing how to resolve errors. But what if that is not enough? You may be +thinking: Do I have to call these mapping functions every second? How often does the +offset change? +

+ +

+This library offers a partial solution to this dilemma. If the location you are concerned +about doesn't change, and if the database isn't reloaded, then get_info can +tell you how far into the past, and far into the future a given offset and abbreviation +are guaranteed to stay valid: +

+ +
+template <class Rep, class Period>
+Info
+get_info(std::chrono::time_point<std::chrono::system_clock,
+                                 std::chrono::duration<Rep, Period>> tp,
+         tz timezone) const;
+
+ +

+Input a time_point tp, and indicate whether tp represents a UTC +time_point (tz::utc) or a local time_point +(tz::local), and a struct Info for that time_point +is returned: +

+ +
+auto info = locate_zone("America/New_York")->get_info(system_clock::now(), tz::utc);
+
+ +

+Upon return info will contain the following information: +

+ + + +

+The Info also has a streaming operator which is mainly useful for debugging +purposes. Here is sample code and output: +

+ +
+cout << current_zone()->get_info(system_clock::now(), tz::utc);
+
+2015-03-08 07:00:00
+2015-11-01 06:00:00
+-04:00:00
+01:00
+EDT
+
+ +

+This is considered to be a low-level function, and as such there is no error detection +if you input a local time that either does not exist, or is ambiguous. Enough information +is returned for you to compute those conditions. Indeed, this is exactly how error +detection is computed in to_sys: by calling get_info and +analyzing how the input time relates to begin and end. +

+ +

+Additionally the Zone is equality and less-than comparable (using the +name()). And you can stream the Zone out to a stream, though +the output may not be crystal clear. The streaming output is mainly used as an aid in +debugging this library, not your code. +

+ +

Flight Example

+ +

+There's nothing like a real-world example to help demonstrate things. Imagine a +plane flying from New York, New York, USA to Tehran, Iran. To make it more realistic, +lets say this flight occurred before the hostage crisis, right at the end of 1978. Flight +time for a non-stop one way trip is 14 hours and 44 minutes. +

+ +

+Given that the departure is one minute past noon on Dec. 30, 1978, local time, what is +the local arrival time? +

+ +
+#include "tz.h"
+#include <iostream>
+
+int
+main()
+{
+    using namespace std::chrono;
+    using namespace date;
+    auto nyc_tz = locate_zone("America/New_York");
+    auto teh_tz = locate_zone("Asia/Tehran");
+    auto nyc_departure_sys = nyc_tz->to_sys(day_point(dec/30/1978) + 12h + 1min);
+    auto nyc_departure = nyc_tz->to_local(nyc_departure_sys);
+    auto flight_length = 14h + 44min;
+    auto teh_arrival_sys = nyc_departure_sys + flight_length;
+    auto teh_arrival = teh_tz->to_local(teh_arrival_sys);
+    std::cout << "departure NYC time:  " << nyc_departure.first << ' '
+                                         << nyc_departure.second << '\n';
+    std::cout << "flight time is " << make_time(flight_length) << '\n';
+    std::cout << "arrival Tehran time: " << teh_arrival.first << ' '
+                                         << teh_arrival.second << '\n';
+}
+
+ +

+There are several points to be made about the above code: +

+ + + +

+The output of the above program is: +

+ +
+departure NYC time:  1978-12-30 12:01:00 EST
+flight time is 14:44
+arrival Tehran time: 1978-12-31 11:45:00 IRST
+
+ +

+And this program is exactly correct. But what happens with the same flight on +the following day? +

+ +
+auto nyc_departure_sys = nyc_tz->to_sys(day_point(dec/31/1978) + 12h + 1min);
+
+departure NYC time:  1978-12-31 12:01:00 EST
+flight time is 14:44
+arrival Tehran time: 1979-01-01 11:15:00 IRST
+
+ +

+Now we have the flight arriving 30min earlier. This is because the time zone +"Asia/Tehran" undergoes an offset change while the plane is in the air, shifting its UTC +offset to 30min earlier. Is this the final word on this example? Almost. If accuracy +down to the second is required (it is not for a flight arrival), then additional effort +needs to be expended. See Flight Example with leap seconds. +

+ +

utc_clock

+ +

+One of the first questions everyone asks when a new date-time library comes out is: +

+ +

+Does it handle leap seconds? +

+ +

+The answer here is yes, this library can handle leap seconds. But be careful what you ask +for. Correctly handling leap seconds is error prone. Therefore this library handles leap +seconds in a completely different type-safe way, which can't be accidentally mixed with +everything else presented so far. The motivation for this separation is born from several +issues: +

+ + + +

+utc_clock is a std::chrono-conforming clock with the same +duration as your system_clock, and a now() +function that returns the actual number of physical seconds since 1970-01-01 00:00:00 UTC +(counting leap seconds): +

+ +
+class utc_clock
+{
+public:
+    using duration                  = std::chrono::system_clock::duration;
+    using rep                       = duration::rep;
+    using period                    = duration::period;
+    using time_point                = std::chrono::time_point<utc_clock>;
+    static constexpr bool is_steady = true;
+
+    static time_point now() noexcept;
+
+    template <class Duration>
+        static
+        std::chrono::time_point<utc_clock,
+            typename std::common_type<Duration, std::chrono::seconds>::type>
+        sys_to_utc(std::chrono::time_point<std::chrono::system_clock, Duration> t);
+
+    template <class Duration>
+        static
+        std::chrono::time_point<std::chrono::system_clock,
+            typename std::common_type<Duration, std::chrono::seconds>::type>
+        utc_to_sys(std::chrono::time_point<utc_clock, Duration> t);
+};
+
+ +

+Additionally utc_clock has static member functions for converting between +utc_clock-based time_points to and from +system_clock-based time_points of any precision. But it is +important to remember that utc_clock isn't connected to a super accurate +atomic clock. All it does is look its time_point up in the database to +see how many leap seconds have passed since 1972, and adds or subtracts that number of +seconds to do the conversion. The utc_clock::now() function simply calls +system_clock::now() and adds the current total of leaps seconds (currently +26) to the result. This is useful behavior but it is important to understand that +utc_clock is not a highly accurate scientific instrument. It is precisely +as accurate as your existing std::chrono::system_clock. +

+ +

Flight Example with leap seconds

+ +

+In the preceding section a flight from New York City to Tehran was offered, demonstrating +how local political changes in the rules governing UTC offsets can affect time +computations. As it turns out, while that flight departing on dec/31/1978 +was in the air, we also underwent a leap second addition. How does that impact the +computation, and how can this library be used to account for that (should it actually be +important)? +

+ +
+#include "tz.h"
+#include <iostream>
+
+int
+main()
+{
+    using namespace std::chrono;
+    using namespace date;
+    auto nyc_tz = locate_zone("America/New_York");
+    auto teh_tz = locate_zone("Asia/Tehran");
+    auto nyc_departure_sys = nyc_tz->to_sys(day_point(dec/31/1978) + 12h + 1min);
+    auto nyc_departure = nyc_tz->to_local(nyc_departure_sys);
+    auto nyc_departure_utc = utc_clock::sys_to_utc(nyc_departure_sys);
+    auto flight_length = 14h + 44min;
+    auto teh_arrival_utc = nyc_departure_utc + flight_length;
+    auto teh_arrival_sys = utc_clock::utc_to_sys(teh_arrival_utc);
+    auto teh_arrival = teh_tz->to_local(teh_arrival_sys);
+    std::cout << "departure NYC time:  " << nyc_departure.first << ' '
+                                         << nyc_departure.second << '\n';
+    std::cout << "flight time is " << make_time(flight_length) << '\n';
+    std::cout << "arrival Tehran time: " << teh_arrival.first << ' '
+                                         << teh_arrival.second << '\n';
+}
+
+departure NYC time:  1978-12-31 12:01:00 EST
+flight time is 14:44
+arrival Tehran time: 1979-01-01 11:14:59 IRST
+
+ +

+As can be seen, we now report an arrival time 1s before the arrival time we computed +without taking leap seconds into account. The key to working with leap seconds is to make +sure that all your time arithmetic takes place using utc_clock-based +time_points, instead of system_clock-based +time_points. Just convert to system_clock when you're ready to +break the date and time up into field-based structures, or are ready to further convert it +into a local time_point. In this example, the only time arithmetic is: +

+ +
+auto teh_arrival_utc = nyc_departure_utc + flight_length;
+
+ +

+The reset of the code is simply about converting from local, to system_clock +to utc_clock and back. +

+ +

+Digression: Doing computations with leap seconds is cool. But perhaps the true +power of this library is revealed in the ease with which I created this example. I sat +back and said to myself: +

+

+I want to find a time and location where a timezone offset changed within 12 hours +of a leap second insertion. And then build my flight time example around that event. +

+

+Subsequently I wrote the following code to search the entire planet, and the last 45 +years, to find these rare chronological events: +

+
+const auto& db = get_tzdb();
+for (auto const& leap : db.leaps)
+{
+    for (auto const& zone : db.zones)
+    {
+        auto info = zone.get_info(leap.date(), tz::utc);
+        if (leap.date() - info.begin <= 12h)
+        {
+            auto prev = zone.get_info(info.begin - 1s, tz::utc);
+            if (prev.offset != info.offset)
+                std::cout << zone.name() << "  " << info.begin << " : "
+                          <<  leap << ' '
+                          << make_time(info.offset-prev.offset) << '\n';
+        }
+        if (info.end - leap.date() <= 12h)
+        {
+            auto next = zone.get_info(info.end, tz::utc);
+            if (next.offset != info.offset)
+                std::cout << zone.name() << " " << info.end <<  " : "
+                          <<  leap << ' '
+                          << make_time(next.offset - info.offset) << '\n';
+        }
+    }
+}
+
+

+The flight time example wasn't really about Iran, the US, and politics after all. It was +about finding this needle in a haystack of time and space, which turned out to be +relatively easy and incredibly efficient. +

+

+You too can analyze the IANA Time Zone +Database in creative and interesting ways no one else has thought of. There is a lot +of history here. +

+ +

Formatting

+ +

+All of the types in this library, as well as in +date.h are streamable when you need quick and +simple output. However in addition to this simplistic streaming there is more +sophisticated formatting built on top of the C++11 time_put<char> +facet. time_put<char> itself is built on C's strftime +function. But time_put<char> is sensitive to C++ locales. +

+ +

+The basic way to use formatting is to call the format function like this: +

+ +
+cout << format("%A %F %T", floor<seconds>(system_clock::now())) << '\n';
+
+ +

+Which just output for me: +

+ +
+Sunday 2016-04-03 22:02:19
+
+ +

+Note the cast to seconds precision in the call. This is how you control +the precision of the seconds output (if any). The modifiers %S +and %T will output seconds to whatever the precision is of the +time_point. For example: +

+ +
+cout << format("%A %F %T", floor<milliseconds>(system_clock::now())) << '\n';
+
+ +

+would instead output: +

+ +
+Sunday 2016-04-03 22:02:19.656
+
+ +

+Note that there is an implicit time zone being used here: UTC. The %z and +%Z modifiers can be used to show this: +

+ +
+cout << format("%A %F %T %z %Z", floor<milliseconds>(system_clock::now())) << '\n';
+
+ +

+would instead output: +

+ +
+Sunday 2016-04-03 22:02:19.656 +0000 UTC
+
+ +

+A Zone can also be passed in and then the %z and +%Z modifiers will reflect that passed-in zone. It is important to +remember however that format never shifts the +time_point for you. Instead you pass in a Zone that you know +to be associated with your time_point. For example: +

+ +
+auto zone = locate_zone("Europe/Berlin");
+auto local = zone->to_local(floor<milliseconds>(system_clock::now())).first;
+cout << format("%A %F %T %z %Z", local, zone) << '\n';
+
+ +
+Monday 2016-04-04 00:02:19.656 +0200 CEST
+
+ +

+The only thing format ever does with a Zone is extract +the offset and/or the abbreviation for use with the %z and %Z +modifiers. +

+ +

+You can also pass in a locale to format: +

+ +
+cout << format(locale("de_DE"), "%A %F %T %z %Z", local, zone) << '\n';
+
+ +
+Montag 2016-04-04 00:02:19,656 +0200 CEST
+
+ +

+The set of named locales that your OS supports is defined by your OS, not this library. +

+ +

+Instead of a time_point you can also pass in anything that is implicitly +convertible to day_point: +

+ +
+cout << format(locale("de_DE"), "%A %B %e, %Y", 2016_y/jul/mon[1]) << '\n';
+
+ +
+Montag Juli  4, 2016
+
+ +

+In summary, use format by passing in a format string and a +time_point, or something implicitly convertible to a day_point. +You can optionally pass in a locale as the first parameter, and a +Zone as the last parameter. format will never alter the value +of your time_point. The precision of the time_point controls +the precision of seconds with the %S and %T modifiers. If you +pass in a Zone, this will only impact the output of %z and +%Z (which default to +0000 and UTC respectively). +The output of format is a std::string. +

+ +

Parsing

+ +

+Since all parts of all date-types in this library can be constructed with integral types, +you can parse any format you wish as integrals, and create dates from any format you +wish that way. +

+ +

+However this section introduces a parse function which is built on top +of the C++11 time_get facet which can also be used: +

+ +
+template <class Duration>
+void
+parse(std::istream& is, const std::string& format,
+      std::chrono::time_point<std::chrono::system_clock, Duration>& tp);
+
+ +

+You can input any istream, and a format string much like that used for +format and strftime, and a time_point of any +precision, and this function will attempt to extract the time_point from +the istream by using the format string. If not successful, +the time_point will not be altered. +

+ +

+Example use: +

+ +
+istringstream is("Montag 2016-04-04 00:02:19,656 +0200");
+is.imbue(locale("de_DE"));
+system_clock::time_point tp;
+parse(is, "%A %F %T %z", tp);
+cout << tp << '\n';
+
+ +

+Which outputs: +

+ +
+2016-04-03 22:02:19.656000
+
+ +

+Note that the locale associated with the istream is respected. +If the format string contains a %z which matches the input stream, this is +used to convert the value to UTC. If there is no %z, then no conversion +happens (you can assume whatever timezone you want). Note that fractional seconds are +accepted as long as one uses %T or %S, and the precision of the +time_point is fine enough to accept fractional seconds. +

+ +

+%Z is not accepted as the mapping from a timezone abbreviation to UTC is +in general, ambiguous. If you have a %Z in the format string, this will +result in is.fail() returning true after the call to +parse. +

+ +

+However, if you absolutely must parse a timestamp with a timezone abbreviation in it, +an extra parse overload is provided: +

+ +
+template <class Duration>
+void
+parse(std::istream& is, const std::string& format,
+      std::chrono::time_point<std::chrono::system_clock, Duration>& tp,
+      std::string& abbrev);
+
+ +

+Now if %Z matches a word in is and if the rest of +is correctly parses according to format, then +abbrev will be assigned the word which matched %Z. This +will not have any impact on the value of tp (no timezone offset +applied). However perhaps there is enough a-priori knowledge in your application to +make use of the value of abbrev to correctly interpret the meaning of +the timestamp and the resulting value of tp. +

+ +

+As an example of how this option can be both useful and dangerous, consider +an example where we need to parse the timestamp "Thu Apr 07 11:45:28 AEST 2016", and +we want to discover what the corresponding time is in UTC, and what timezone this +timestamp represents. +

+ +

+The following program parses this, and then searches +the entire timezone database looking for timezones which have "AEST" as an abbreviation +at a local time of Apr 07 11:45:28 2016. The program finds the first one, notes its UTC +offset, and then searches for more. If it finds more, and the UTC offset is the same, +it simply outputs the name of each additional timezone found. If the additional timezones +have a different UTC offset, that is noted too by outputting the UTC timestamp associated +with the additional timezone. +

+ +
+#include "tz.h"
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <cassert>
+
+int
+main()
+{
+    using namespace std::chrono;
+    using namespace date;
+    auto& db = get_tzdb();
+    std::istringstream in("Thu Apr 07 11:45:28 AEST 2016");
+    time_point<system_clock, seconds> tp_local;
+    std::string abbrev;
+    parse(in, "%a %b %d %T %Z %Y", tp_local, abbrev);
+    assert(!in.fail());
+    auto i = std::find_if(db.zones.begin(), db.zones.end(),
+                          [&tp_local, &abbrev](auto const& z)
+                          {
+                              return z.get_info(tp_local, tz::local).abbrev == abbrev;
+                          });
+    if (i != db.zones.end())
+    {
+        auto tp_utc = i->to_sys(tp_local);
+        std::cout << tp_utc << " UTC " << i->name() << '\n';
+        for (++i; i != db.zones.end(); ++i)
+        {
+            if (i->get_info(tp_local, tz::local).abbrev != abbrev)
+                continue;
+            auto tp = i->to_sys(tp_local);
+            if (tp != tp_utc)
+                std::cout << tp << " UTC ";
+            std::cout << i->name() << '\n';
+        }
+    }
+}
+
+ +

+This program outputs: +

+ +
+2016-04-07 01:45:28 UTC Australia/Brisbane
+Australia/Currie
+Australia/Hobart
+Australia/Lindeman
+Australia/Melbourne
+Australia/Sydney
+
+ +

+This indicates that "Thu Apr 07 11:45:28 AEST 2016" unambiguously refers to +2016-04-07 01:45:28 UTC (a UTC offset of +1000). However which IANA timezone is referred +to is ambiguous. This means that past or future timepoints using any of these timezones +may or may not have the same UTC offsets (or abbreviations) among this set of timezones. +

+ +

+And this is a good case. Consider just altering the abbreviation in the above example +from AEST to BST. Now the output is: +

+ +
+2016-04-07 10:45:28 UTC Europe/London
+2016-04-07 00:45:28 UTC Pacific/Bougainville
+
+ +

+Meaning: Not only do we not know what timezone this refers to, it could mean one of +two different UTC timepoints! +

+ +

+So in summary, it is dangerous to parse timezone abbreviations. You should avoid it if at +all possible. However, if you are forced to, this library has the power to find out every +thing that is knowable about that timestamp. +

+ +

Thread Safety

+ +

+The implementation of the database is as a singleton. An application can have only a +single database. However the initial construction of that database is thread safe, and +subsequent access is always const (unless you need to update to a new version of the +database at run time). The initial construction thread safety is implemented with C++11 +function local statics. If your compiler does not implement threadsafe function local +statics, then you will need to arrange for your own thread safety during the +initialization stage. +

+ +

+If you need to update the database at runtime via the reload_tzdb function, +you will need to provide your own thread safety if you are in a multithreaded application. +This could be done (for example) by ensuring that all of your calls into the database +occur with the permission of a C++14 +std::shared_lock<std::shared_timed_mutex>, except for the calls to +reload_tzdb, which must be done with a +std::unique_lock<std::shared_timed_mutex>. Such facilities are not +provided by default with this library so that you don't pay for them if you don't need +them. +

+ +

+In case you do need to protect calls into the database with a mutex, here is a +comprehensive list of the public API that accesses the database: +

+ +
+// Read/write access
+const TZ_DB& reload_tzdb();
+
+// Read-only access
+
+const TZ_DB& get_tzdb();
+
+// Zone functions
+const Zone* locate_zone(const std::string& tz_name);
+const Zone* current_zone();
+Info Zone::get_info(std::chrono::system_clock::time_point tp, tz timezone) const;
+
+template <class Rep, class Period>
+auto
+Zone::to_local(std::chrono::time_point<std::chrono::system_clock,
+               std::chrono::duration<Rep, Period>> tp) const
+    -> std::pair<decltype(tp + get_info(tp, tz::utc).offset), std::string>;
+
+template <class Rep, class Period>
+auto
+Zone::to_sys(std::chrono::time_point<std::chrono::system_clock,
+             std::chrono::duration<Rep, Period>> tp) const
+    -> decltype(tp - get_info(tp, tz::local).offset);
+
+template <class Rep, class Period>
+auto
+Zone::to_sys(std::chrono::time_point<std::chrono::system_clock,
+             std::chrono::duration<Rep, Period>> tp, choose z) const
+    -> decltype(tp - get_info(tp, tz::local).offset);
+
+// leap second functions
+utc_clock::time_point utc_clock::now() noexcept;
+
+template <class Duration>
+std::chrono::time_point<utc_clock,
+    typename std::common_type<Duration, std::chrono::seconds>::type>
+utc_clock::sys_to_utc(std::chrono::time_point<std::chrono::system_clock, Duration> t);
+
+template <class Duration>
+std::chrono::time_point<std::chrono::system_clock,
+    typename std::common_type<Duration, std::chrono::seconds>::type>
+utc_clock::utc_to_sys(std::chrono::time_point<utc_clock, Duration> t);
+
+ +

+Those functions that explicitly return const references or const pointers (the first five) +continue to have read access into the database after the call until the client drops that +reference or pointer. +

+ +

+Emphasis: If you don't use the reload_tzdb function, then all access +is read-only and there is no need for synchronization with an external mutex. +

+ +

Installation

+ +

+There are only three files in the timezone library: +tz.h, +tz_private.h and +tz.cpp. +These are sources located at the github repository +https://github.com/HowardHinnant/date. +The source +tz.cpp +contains the following string near the top: +

+ +
+static std::string install{"~/Downloads/tzdata"};  //  "c:\\tzdata" on Windows
+
+ +

+You should set this such that install points to the directory +where your library or application can find the downloaded and uncompressed +IANA Time Zone Database. +

+ +

+There are three configuration macros that can be defined on the command line during +compilation, or you can ignore them and they will take on default values. +

+ +
+ + + + + + + + + + + + + +
HAS_REMOTE_APIDefaults to 1 on Linux and OS X, and to 0 on Windows
AUTO_DOWNLOADDefaults to HAS_REMOTE_API
LAZY_INITDefaults to 1
+
+ +

+If HAS_REMOTE_API is 1 then the remote API exists, +else it doesn't: +

+ +
+std::string remote_version();
+bool        remote_download(const std::string& version);
+bool        remote_install(const std::string& version);
+
+ +

+The remote API requires linking against libcurl +(https://curl.haxx.se/libcurl). +On OS X and Linux this is done with -lcurl. +libcurl comes pre-installed on OS X and Linux, but not on Windows. +However one can download it for Windows. +

+ +

+If AUTO_DOWNLOAD is 1 then first access to the timezone database will install +it if it hasn't been installed, and if it has, will use the remote API to install the +latest version if not already installed. +

+ +

+If AUTO_DOWNLOAD is 1 then reload_tzdb() will automatically +check remote_version() against the local version, and if unchanged, will do +nothing. If remote_version() can't access the IANA website, +reload_tzdb() will re-initialize the database anyway (perhaps you changed it +manually because the net is down). If the remote_version() is confirmed to +have changed (and AUTO_DOWNLOAD is on), then reload_tzdb() will +download and install the latest version. +

+ +

+If AUTO_DOWNLOAD is off, reload_tzdb() re-initializes the +database without using the remote API (presumably because it has been manually updated). +

+ +

+If HAS_REMOTE_API is off and AUTO_DOWNLOAD is on, there will be +a compile-time error as AUTO_DOWNLOAD needs the remote API. +

+ +

+If LAZY_INIT is on, the Zones are not fully compiled upon first +access to the database. As each Zone is accessed individaully by the +programmer (when they are used), they are fully compiled at that point. However, this +further Zone compilation does not involve any access to the local copy of the +tz database files. +

+ +

+If LAZY_INIT is off, every Zone is fully compiled upon first +access to the database. +

+ +

+LAZY_INIT speeds up the initialization of the database, but slows down the +first use of any individual Zone. If you are only using a few +Zones then LAZY_INIT is a clear win. If you are immediately +using all of the Zones (say for some database analysis) then +LAZY_INIT is not a win. +

+ +

+If LAZY_INIT is off, and you are on multi-core hardware, and your application +has other unrelated initialization it has to take care of, spinning off timezone +initialization into a detached thread can be an attractive option: +

+ +
+int
+main()
+{
+    std::thread(date::get_tzdb).detach();
+    // other initialization ...
+}
+
+ +

+By the time your application actually needs to use the timezone database, it is likely to +be fully initialized and ready to go. And if it is not, C++11 threadsafe function local +statics ensure there is no race condition on the initialization. +

+ +

+If you would like to trade off functionality for size, you can reduce the size of the +database in two ways: +

+ + + +

+You can limit geography by removing one or more of the files in this list: +

+ +
+const std::vector<const std::string> files =
+{
+    "africa", "antarctica", "asia", "australasia", "backward", "etcetera", "europe",
+    "pacificnew", "northamerica", "southamerica", "systemv", "leapseconds"
+};
+
+ +

+You can limit history by setting min_year to something more recent such as: +

+ +
+CONSTDATA auto min_year = 2015_y;
+
+ +

+When you do so, if you ask to convert a date prior to min_year, an exception +will be thrown. +

+ +

+The entire database consumes about 859Kb. +

+ +

+Compile +tz.cpp +in with the rest of your library or application. +

+ +

+If AUTO_DOWNLOAD is not enabled, you are responsible for keeping your +IANA Time Zone Database up to date. New +versions of it are released several times a year. This library is not bundled with a +specific version of the database already installed, nor is any specific version of the +database blessed. +

+ +

+There is no preprocessing of the +IANA Time Zone Database required. This +library efficiently initializes itself directly from the files of the +IANA Time Zone Database. If your application +is long running, and you anticipate the need to update the +IANA Time Zone Database to a new version +without recompiling, or even restarting your application, there is API to accomplish +that. +

+ +

+If you constrain geography during installation, this can significantly reduce the time +it takes to initialize the database. However constraining history has little (if any) +impact on the performance of the initialization. +

+ +

Acknowledgements

+ +

+A database parser is nothing without its database. I would like to thank the founding +contributor of the IANA Time Zone Database +Arthur David Olson. I would also like to thank the entire group of people who continually +maintain it, and especially the IESG-designated TZ Coordinator, Paul Eggert. Without the +work of these people, this software would have no data to parse. +

+ + +