diff --git a/date.html b/date.html
index 096939c..c8c60a2 100644
--- a/date.html
+++ b/date.html
@@ -26,7 +26,7 @@
Howard E. Hinnant
-2016-05-07
+2016-05-15
This work is licensed
@@ -42,6 +42,7 @@ Commons Attribution 4.0 International License.
iso_week
.
+
+As with all numerical representations with a fixed storage size, duration
s,
+time_point
s, and year_month_day
s have a fixed range, outside
+of which they overflow. With this library, and with <chrono>
, the
+range varies with precision.
+
+On one side nanoseconds
is represented by a int64_t
+which has a range of about +/- 292 years. And on the other side year
+is represented by a int16_t
which has a range of about +/- 32 thousand
+years. It is informative and educational to write software which explores the
+intersection of these two constraints for various precisions, and outputs the result
+in terms of a sys_time
.
+
+Here is a function which will discover the limits for a single durration D
:
+
+ ++#include "date.h" +#include <iomanip> +#include <iostream> +#include <limits> +#include <cstdint> + +template <class D> +void +limit(const std::string& msg) +{ + using namespace date; + using namespace std; + using namespace std::chrono; + using dsecs = sys_time<duration<double>>; + constexpr auto ymin = sys_days{year{numeric_limits<int16_t>::min()}/jan/1}; + constexpr auto ymax = sys_days{year{numeric_limits<int16_t>::max()}/12/last}; + constexpr auto dmin = sys_time<D>::min(); + constexpr auto dmax = sys_time<D>::max(); + cout << left << setw(24) << msg << " : ["; + if (ymin > dsecs{dmin}) + cout << ymin; + else + cout << dmin; + cout << ", "; + if (ymax < dsecs{dmax}) + cout << ymax; + else + cout << dmax; + cout << "]\n"; +} +
+The best way to explore limits without risking overflow during the comparison operation
+itself is to use double
-based seconds
for the comparison. By
+using seconds
you guarantee that the conversion to the comparison type
+won't overflow the compile-time machinery of finding the common_type
of the
+duration
s, and by using double
you make overflow or underflow
+nearly impossible. The use of double
sacrifices precision, but this is
+rarely needed for limits comparisons as the two operands of the comparison are typically
+orders of magnitude apart.
+
+So the code above creates a sys_time<double>
time_point
+with which to perform the comparisons. Then it finds the min and max of both the
+year_month_day
object, and the duration D
. It then prints
+out the intersection of these two ranges.
+
+This code can be exercised like so: +
+ ++ ++void +limits() +{ + using namespace std::chrono; + using namespace std; + using picoseconds = duration<int64_t, pico>; + using fs = duration<int64_t, ratio_multiply<ratio<100>, nano>>; + limit<picoseconds>("picoseconds range is"); + limit<nanoseconds>("nanoseconds range is"); + limit<fs>("VS system_clock range is"); + limit<microseconds>("microseconds range is"); + limit<milliseconds>("milliseconds range is"); + limit<seconds>("seconds range is"); + limit<minutes>("minutes range is"); + limit<hours>("hours range is"); +} +
+I've included two extra units: picoseconds
, and the units used by Visual
+Studio's system_clock::time_point
. Units finer than picoseconds
+do not work with this date library because the conversion factors needed to convert to
+units such as days
overflow the compile-time machinery. As a practical
+matter this is not important as the range of a 64 bit femtosecond is only about +/- 2.5
+hours. On the other side, units coarser than hours
, if represented by at
+least 32 bits, will always have a range far greater than a 16 bit year
.
+
+The output of this function on Visual Studio, and on clang using libc++ with
+-arch i386
is:
+
+ ++picoseconds range is : [1969-09-16 05:57:07.963145224192, 1970-04-17 18:02:52.036854775807] +nanoseconds range is : [1677-09-21 00:12:43.145224192, 2262-04-11 23:47:16.854775807] +VS system_clock range is : [-27258-04-19 21:11:54.5224192, 31197-09-14 02:48:05.4775807] +microseconds range is : [-32768-01-01, 32767-12-31] +milliseconds range is : [-32768-01-01, 32767-12-31] +seconds range is : [-32768-01-01, 32767-12-31] +minutes range is : [-2114-12-08 21:52, 6053-01-23 02:07] +hours range is : [-32768-01-01, 32767-12-31] +
+Using gcc or clang/libc++ with -arch x86_64
the output is:
+
+ ++picoseconds range is : [1969-09-16 05:57:07.963145224192, 1970-04-17 18:02:52.036854775807] +nanoseconds range is : [1677-09-21 00:12:43.145224192, 2262-04-11 23:47:16.854775807] +VS system_clock range is : [-27258-04-19 21:11:54.5224192, 31197-09-14 02:48:05.4775807] +microseconds range is : [-32768-01-01, 32767-12-31] +milliseconds range is : [-32768-01-01, 32767-12-31] +seconds range is : [-32768-01-01, 32767-12-31] +minutes range is : [-32768-01-01, 32767-12-31] +hours range is : [-32768-01-01, 32767-12-31] +
+The only difference between these two outputs is that associated with
+minutes
. When minutes
is represented with 32 bits the range is
+only about +/- 4000 years from 1970. When minutes
is represented with 64
+bits, the limits of the 16 bit year takes precedence.
+
+The take-away point here is two-fold: +
+ +
+If you need to check range, do the check using duration<double>
to
+ensure your comparison is not itself vulnerable to overflow.
+
+If you are dealing units finer than microseconds
, you may well
+accidentally experience overflow in surprisingly mundane-looking code. When
+dealing with dates that may be hundreds of years away from 1970, keep an eye on
+the precision. And in a surprise move, 32 bit minutes
can bite if
+you are several thousand years away from 1970.
+
+Finally note that the civil calendar itself models the rotation and orbit of the
+earth with an accuracy of only one day in several thousand years. So dates more
+than several thousand years in the past or future (with a precision of a single
+day) are of limited practical use with or without numerical overflow. The chief
+motivation for having large ranges of date computation before overflow happens
+is to make range checking superflous for most reasonable computations. If you
+need to handle ranges dealing with geological or astrophysical phenomenon,
+<chrono>
can handle it (attoseconds
to
+exaseconds
), but year_month_day
is the wrong tool for
+such extremes.
+
diff --git a/tz.html b/tz.html
index 6c19929..44ad845 100644
--- a/tz.html
+++ b/tz.html
@@ -26,7 +26,7 @@
Howard E. Hinnant
-2016-05-08
+2016-05-15
This work is licensed
@@ -39,9 +39,8 @@ Commons Attribution 4.0 International License.
choose
nonexistent_local_time
ambiguous_local_time
sys_info
local_info
time_zone
zoned_time
make_zoned
format
parse
utc_clock
Leap
Link
-I had just completed writing date
, which is a
+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
+of 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
+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).
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
+href="date.html">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.
-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.
-
-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 sys_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 sys_info& r); - -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> - sys_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 -
@@ -464,6 +150,229 @@ this namespace in example code below is intentionally omitted in the hopes of re verbosity.
++One of the first things people want to is find out what current local time it is. +Here is a complete program to print out the local time in human readable format: +
+ ++ ++#include "tz.h" +#include <iostream> + +int +main() +{ + using namespace date; + using namespace std::chrono; + auto local_time = make_zoned(current_zone(), system_clock::now()); + std::cout << local_time << '\n'; +} +
+This just output for me: +
+ ++ ++2016-05-14 18:33:24.205124 EDT +
+There are some noteworthy points about this program: +
+ +
+This is a <chrono>
-based system. The current time is
+found with std::chrono::system_clock::now()
.
+
+The computer's current local time zone is not assumed. If anything is assumed that
+would be UTC, since this is the time zone that system_clock
tracks
+(unspecified but de facto standard).
+
+Specifying you want to convert system_clock::time_point
s to the
+current local time zone is as easy as calling date::current_zone()
+and pairing that with a system_clock::time_point
using
+date::make_zoned
. This creates a zoned_time
.
+
+This zoned_time
maintains whatever precision it was given. On my
+platform system_clock::now()
has microseconds precision, so in this
+example, local_time
has microseconds precision as well.
+
+The local_time
is then simply streamed out. By default the output
+represents all of the precision it is given.
+
+Everything about the above program can be customized: the precision, the formatting, +and the time zone. But by default, things just work, and don't throw away information. +
+ +
+For example let's say we wanted to limit the precision to milliseconds. This can
+be done by inserting floor<milliseconds>
in one place. This
+makes local_time
have just a precision of milliseconds
+and that is reflected in the streaming operator with no further effort:
+
+ ++auto local_time = make_zoned(current_zone(), floor<milliseconds>(system_clock::now())); +std::cout << local_time << '\n'; // 2016-05-14 18:33:24.205 EDT +
+Seconds precision is just as easy: +
+ ++ ++auto local_time = make_zoned(current_zone(), floor<seconds>(system_clock::now())); +std::cout << local_time << '\n'; // 2016-05-14 18:33:24 EDT +
+The entire strftime
/ time_put
formatting capability is
+also at your fingertips (and at any precision):
+
+ ++auto local_time = make_zoned(current_zone(), system_clock::now()); +std::cout << format("%a, %b %d, %Y at %I:%M %p %Z", local_time) << '\n'; +// Sat, May 14, 2016 at 06:33 PM EDT +
+Using any std::locale
your OS supports:
+
+ ++auto local_time = make_zoned(current_zone(), floor<seconds>(system_clock::now())); +std::cout << format(locale("de_DE"), "%a, %b %d, %Y at %T %Z", local_time) << '\n'; +// Sa, Mai 14, 2016 at 18:33:24 EDT +
+From the previous section: +
+ +++ ++Hmm... German locale in an American time zone. +
+
+We can fix that easily too: +
+ ++ ++auto zone = locate_zone("Europe/Berlin"); +auto local_time = make_zoned(zone, floor<seconds>(system_clock::now())); +std::cout << format(locale("de_DE"), "%a, %b %d, %Y at %T %Z", local_time) << '\n'; +// So, Mai 15, 2016 at 00:33:24 CEST +
+The date::locate_zone()
function looks up the IANA time zone with the name
+"Europe/Berlin" and returns a const time_zone*
which has no ownership
+issues and can be freely and cheaply copied around. It is not possible for
+locate_zone()
to return nullptr
, though it might throw
+an exception if pushed far enough (e.g. locate_zone("Disney/Mickey_Mouse")
).
+
+You can also call make_zoned
with the time zone name right in the call:
+
+ ++auto local_time = make_zoned("Europe/Berlin", floor<seconds>(system_clock::now())); +
+The first way is very slightly more efficient if you plan on using zone
+multiple times since it then only has to be looked up once.
+
time_zone
from one time zone to another?
+So far we've only looked at converting from system_clock::now()
to
+a local, or specific time zone. We've used make_zoned
with the
+first argument being either current_zone()
or a specification for
+some other time zone, and the second argument being a
+system_clock::time_point
. So far so good.
+
+But now I have a video-conference meeting on the first Monday of May, 2016 at +9am New York time. I need to communicate that meeting with partners in London +and Sydney. And the computation is taking place on a computer in New Zealand (or some other +unrelated time zone). What does that look like? +
+ ++ ++#include "tz.h" +#include <iostream> + +int +main() +{ + using namespace date::literals; + using namespace std::chrono_literals; + auto meet_nyc = make_zoned("America/New_York", date::local_days{mon[1]/may/2016} + 9h); + auto meet_lon = make_zoned("Europe/London", meet_nyc); + auto meet_syd = make_zoned("Australia/Sydney", meet_nyc); + std::cout << "The New York meeting is " << meet_nyc << '\n'; + std::cout << "The London meeting is " << meet_lon << '\n'; + std::cout << "The Sydney meeting is " << meet_syd << '\n'; +} +
+The output is the following. But before you forward it, send a generous bonus +to the guys in Australia. +
+ ++ ++The New York meeting is 2016-05-02 09:00:00 EDT +The London meeting is 2016-05-02 14:00:00 BST +The Sydney meeting is 2016-05-02 23:00:00 AEST +
+Summary: zoned_time
is a pairing of local or UTC time with a time_zone
.
+The result is a well-specified point in time. And it carries with it the ability to
+serve as a translator to any other time_point
which carries time zone
+information (to any precision).
+
@@ -649,7 +558,7 @@ some of the data which is presented, such as that in the sys_info
c
this type alias as a convenience, and to reduce verbosity. second_point
will implicitly convert to system_clock::time_point
. And coarser
time_point
s such as the day_point
from the
-date
library will implicitly convert to
+date
library will implicitly convert to
second_point
.
All of the types in this library, as well as in
-date.h
are streamable when you need quick and
+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
@@ -1804,93 +1713,13 @@ all possible. However, if you are forced to, this library has the power to find
thing that is knowable about that timestamp.
-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.
-
+Everything specified below is in namespace date
, and accessed via the
+header "tz.h"
.
+
@@ -3120,37 +2949,405 @@ make_zoned(const std::string& name, const sys_time<Duration>& st)
format
-needs documentation
++template <class Duration> +std::string +format(const std::locale& loc, std::string format, local_time<Duration> tp); + +template <class Duration> +std::string +format(std::string format, local_time<Duration> tp); + +template <class Duration> +std::string +format(const std::locale& loc, std::string format, const zoned_time<Duration>& tp); + +template <class Duration> +std::string +format(std::string format, const zoned_time<Duration>& tp); + +template <class Duration> +std::string +format(const std::locale& loc, std::string format, sys_time<Duration> tp); + +template <class Duration> +std::string +format(std::string format, sys_time<Duration> tp); ++++Effects: These functions create a formatted time stamp using the +arguments, returning the result in a
+std::string
. +++ ++If a
+locale
is passed in, then thatlocale
is used for +any formatting that requires alocale
. If nolocale
+is passed in, then if alocale
is required for formatting, a +default constructedlocale
will be used (which makes a copy of the +globallocale
). ++The
+format
string follows the rules as specified for +std::time_put
with the following exceptions: ++
+ +- + +
+If
%S
or%T
appears in theformat
string +and the argumenttp
has precision finer than seconds, then seconds +are formatted as a decimal floating point number with a fixed format and a +precision matching that of the precision oftp
. The character for +the decimal point is localized according to thelocale
. +- + +
+If
+%z
appears in the format, the behavior depends on the type of +tp
: ++
+- +
+local_time
: An exception of typestd::runtime_error
is thrown. +- +
+zoned_time
: The offset associated withtp.get_time_zone()
is +used. +- +
+sys_time
:"+0000"
is used. +- + +
+If
+%Z
appears in the format, the behavior depends on the type of +tp
: ++
+- +
+local_time
: An exception of typestd::runtime_error
is thrown. +- +
+zoned_time
: The abbreviation associated with +tp.get_time_zone()
is used. +- +
+sys_time
:"UTC"
is used. ++For the overloads taking a
+zoned_time
it is the value returned by +tz.get_local_time()
that is formatted. ++Returns: The formatted string. +
+ +
parse
-+needs documentation
-+template <class Duration> +void +parse(std::istream& is, const std::string& format, sys_time<Duration>& tp); -+template <class Duration> +void +parse(std::istream& is, const std::string& format, local_time<Duration>& tp); + +template <class Duration> +void +parse(std::istream& is, const std::string& format, local_time<Duration>& tp, + std::string& abbrev); +
Leap
-needs documentation
++Effects: These functions attempt to parse a
+time_point
out of +is
according toformat
. If the parse is unsuccessful, +callsis.setstate(std::ios::failbit)
which may throw an exception. +tp
is altered only in the event of a successful parse. ++++The
+format
string follows the rules as specified forstd::time_get
+with the following exceptions: ++
+- + +
+If
%S
or%T
appears in theformat
string +and the argumenttp
has precision finer than seconds, then the +seconds are parsed as adouble
, and if that parse is successful +contributes to the time stamp as if +round<Duration>(duration<double>{s})
where +s
is a local variable holding the parseddouble
. +- + +
+If
%z
appears in theformat
string and an offset is +successfully parsed, the first overload (sys_time
) interprets the +parsed time as a local time and subtracts the offset prior to assigning the +value totp
, resulting in a value oftp
representing a +UTC timestamp. The second and third overloads require a valid parse of the +offset, but then ignore the offset in assigning a value to the +local_time<Duration>& tp
. +- +
+If
%Z
appears in theformat
string then an abbreviation +is required in that position for a successful parse. However the parsed abbreviation +does not have to be a valid time zone abbreviation, and has no impact on the value +parsed intotp
. Using the third overload one can discover what that +parsed abbreviation is. If the third overload is used, but%Z
does +not appear in the format, thenabbrev
is not altered. ++Note: There is no unique mapping from a time zone abbreviation to a +
+time_zone
. +
utc_clock
-+ +needs documentation
++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 + utc_time<std::common_type_t<Duration, std::chrono::seconds>> + sys_to_utc(sys_time<Duration> t); + + template <class Duration> + static + sys_time<std::common_type_t<Duration, std::chrono::seconds>> + utc_to_sys(utc_time<Duration> u); +}; + +template <class Duration> + using utc_time = std::chrono::time_point<utc_clock, Duration>; + +using utc_seconds = utc_time<std::chrono::seconds>; ++ ++In contrast to
+ +sys_time
which does not take leap seconds into +account,utc_clock
and its associatedtime_point
, +utc_time
, counts time, including leap seconds, since +1970-01-01 00:00:00 UTC. It also provides functions for converting between +utc_time
andsys_time
. These functions consult +get_tzdb().leaps
to decide how many seconds to add/subtract +in performing those conversions. ++static utc_clock::time_point utc_clock::now() noexcept; ++++ ++Returns:
+sys_to_utc(system_clock::now())
. ++template <class Duration> +static +utc_time<std::common_type_t<Duration, std::chrono::seconds>> +utc_clock::sys_to_utc(sys_time<Duration> t); ++++ ++Returns: A
+utc_time
u
, such that +u.time_since_epoch() - t.time_since_epoch()
is equal to the number +of leap seconds that were inserted betweent
and 1970-01-01. If +t
is ambiguous on this issue (i.e. corresponds to the date of leap +second insertion), then the conversion counts that leap second as inserted. ++template <class Duration> +static +sys_time<std::common_type_t<Duration, std::chrono::seconds>> +utc_clock::utc_to_sys(utc_time<Duration> u); ++++ ++Returns: A
+sys_time
t
, such that +utc_clock::sys_to_utc(t) == u
. ++template <class Duration> +utc_time<std::common_type_t<Duration, std::chrono::seconds>> +to_utc_time(sys_time<Duration> t) ++++ ++Returns:
+utc_clock::sys_to_utc(t)
. ++template <class Duration> +sys_time<std::common_type_t<Duration, std::chrono::seconds>> +to_sys_time(utc_time<Duration> u) ++++ ++Returns:
+utc_clock::utc_to_sys(u)
. ++[Example: +
+ ++ ++#include "tz.h" +#include <iostream> + +int +main() +{ + using namespace date; + using namespace std::chrono_literals; + auto t0 = sys_days{1972_y/jul/1} - 1ms; + auto u0 = to_utc_time(t0); + auto t1 = to_sys_time(u0); + std::cout << t0 << ":\n"; + std::cout << (u0.time_since_epoch() - t0.time_since_epoch()).count() << "ms\n"; + std::cout << (t1 - t0).count() << "ms\n\n"; + + t0 += 1ms; + u0 = to_utc_time(t0); + t1 = to_sys_time(u0); + std::cout << t0 << ":\n"; + std::cout << (u0.time_since_epoch() - t0.time_since_epoch()).count() << "ms\n"; + std::cout << (t1 - t0).count() << "ms\n"; +} +++Output: +
++1972-06-30 23:59:59.999: +0ms +0ms + +1972-07-01 00:00:00.000: +1000ms +0ms +++— end example] +
+ +
Leap
++class Leap +{ +public: + Leap(const Leap&) = default; + Leap& operator=(const Leap&) = default; + + // Undocumented constructors + + sys_seconds 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); + +template <class Duration> bool operator==(const const Leap& x, const sys_time<Duration>& y); +template <class Duration> bool operator==(const sys_time<Duration>& x, const Leap& y); +template <class Duration> bool operator!=(const Leap& x, const sys_time<Duration>& y); +template <class Duration> bool operator!=(const sys_time<Duration>& x, const Leap& y); +template <class Duration> bool operator< (const Leap& x, const sys_time<Duration>& y); +template <class Duration> bool operator< (const sys_time<Duration>& x, const Leap& y); +template <class Duration> bool operator> (const Leap& x, const sys_time<Duration>& y); +template <class Duration> bool operator> (const sys_time<Duration>& x, const Leap& y); +template <class Duration> bool operator<=(const Leap& x, const sys_time<Duration>& y); +template <class Duration> bool operator<=(const sys_time<Duration>& x, const Leap& y); +template <class Duration> bool operator>=(const Leap& x, const sys_time<Duration>& y); +template <class Duration> bool operator>=(const sys_time<Duration>& x, const Leap& y); ++ ++
Leap
is a copyable class that is constructed and stored in the time zone +database when initialized. You can explicitly convert it to asys_seconds
+with the member functiondate()
and that will be the date of the leap second +insertion.Leap
is equality and less-than comparable, both with itself, and +withsys_time<Duration>
. +
Link
-needs documentation
++class Link +{ +public: + Link(const Link&) = default; + Link& operator=(const Link&) = default; + + // Undocumented constructors + + 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); +++A
Link
is an alternative name for atime_zone
. The alternative +name isname()
. The name of thetime_zone
for which this is +an alternative name istarget()
.Link
s will be constructed +for you when the time zone database is initialized. +
-There are only three files in the timezone library:
+You will need the following four source files:
+date.h
,
tz.h
,
tz_private.h
and
tz.cpp
.
-These are sources located at the github repository
+These sources are located at the github repository
https://github.com/HowardHinnant/date.
The source
tz.cpp
@@ -3164,7 +3361,9 @@ 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.
+IANA Time Zone Database (or where
+you want the software to install it for you if you compile with
+AUTO_DOWNLOAD == 1
).
@@ -3190,7 +3389,7 @@ compilation, or you can ignore them and they will take on default values.
-If HAS_REMOTE_API
is 1 then the remote API exists,
+If HAS_REMOTE_API
is 1 then the remote API exists,
else it doesn't:
-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 Zone
s are not fully compiled upon first
@@ -3333,17 +3514,7 @@ 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. +IANA Time Zone Database.
-I would also like to thank Jiangang Zhuang and Bjarne Stroustrup for invaluable feedback -for the timezone portion of this library, which ended up influencing the date.h library. +I would also like to thank Jiangang Zhuang and Bjarne Stroustrup for invaluable +feedback for the timezone portion of this library, which ended up also +influencing the date.h library.
And I would also especially like to thank contributors to this library: gmcode,