mirror of
https://github.com/HowardHinnant/date.git
synced 2025-01-16 20:41:20 +08:00
3015 lines
102 KiB
HTML
3015 lines
102 KiB
HTML
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
|
"http://www.w3.org/TR/html4/loose.dtd">
|
|
<html>
|
|
<head>
|
|
<title>Time Zone Database Parser</title>
|
|
|
|
<style>
|
|
p {text-align:justify}
|
|
li {text-align:justify}
|
|
blockquote.note
|
|
{
|
|
background-color:#E0E0E0;
|
|
padding-left: 15px;
|
|
padding-right: 15px;
|
|
padding-top: 1px;
|
|
padding-bottom: 1px;
|
|
}
|
|
ins {color:#00A000}
|
|
del {color:#A00000}
|
|
code {white-space:pre;}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<address align=right>
|
|
<br/>
|
|
<br/>
|
|
<a href="mailto:howard.hinnant@gmail.com">Howard E. Hinnant</a><br/>
|
|
2016-10-08<br/>
|
|
</address>
|
|
<hr/>
|
|
<h1 align=center>Time Zone Database Parser</h1>
|
|
|
|
<h2>Contents</h2>
|
|
|
|
<ul>
|
|
<li><a href="https://github.com/HowardHinnant/date">github link</a></li>
|
|
<li><a href="#Introduction">Introduction</a></li>
|
|
<li><a href="#Description">Description</a>
|
|
<ul>
|
|
<li><a href="#current_local">What is the current local time?</a></li>
|
|
<li><a href="#somewhere_else">What time is it somewhere <i>else</i> in the world?</a></li>
|
|
<li><a href="#convert">How do I convert a <code>time_zone</code> from one time zone to another?</a></li>
|
|
<li><a href="#loc_vs_sys"><code>local_time</code> vs <code>sys_time</code></a></li>
|
|
<li><a href="#Summary">Summary</a></li>
|
|
<li><a href="#Examples">Examples</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#Reference">Reference</a>
|
|
<ul>
|
|
<li><a href="#database">The database</a></li>
|
|
<li><a href="#choose"><code>choose</code></a></li>
|
|
<li><a href="#nonexistent_local_time"><code>nonexistent_local_time</code></a></li>
|
|
<li><a href="#ambiguous_local_time"><code>ambiguous_local_time</code></a></li>
|
|
<li><a href="#sys_info"><code>sys_info</code></a></li>
|
|
<li><a href="#local_info"><code>local_info</code></a></li>
|
|
<li><a href="#time_zone"><code>time_zone</code></a></li>
|
|
<li><a href="#zoned_time"><code>zoned_time</code></a></li>
|
|
<li><a href="#make_zoned"><code>make_zoned</code></a></li>
|
|
<li><a href="#format"><code>format</code></a></li>
|
|
<li><a href="#parse"><code>parse</code></a></li>
|
|
<li><a href="#utc_clock"><code>utc_clock</code></a></li>
|
|
<li><a href="#tai_clock"><code>tai_clock</code></a></li>
|
|
<li><a href="#gps_clock"><code>gps_clock</code></a></li>
|
|
<li><a href="#leap"><code>leap</code></a></li>
|
|
<li><a href="#link"><code>link</code></a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#Installation">Installation</a></li>
|
|
<li><a href="#Acknowledgements">Acknowledgements</a></li>
|
|
</ul>
|
|
|
|
<a name="Introduction"></a><h2>Introduction</h2>
|
|
|
|
<p>
|
|
I had just completed writing <a href="date.html"><code>date</code></a>, which is a
|
|
library for extending <code><chrono></code> 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
|
|
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.
|
|
</p>
|
|
|
|
<p>
|
|
This library adds timezone and leap second support to this <a href="date.html">date</a>
|
|
library. This is a separate library from <a href="date.html"><code>date</code></a>
|
|
because many clients of <a href="date.html"><code>date</code></a> do not need timezone
|
|
nor leap second support, and this support does not come for free (though the cost is quite
|
|
reasonable).
|
|
</p>
|
|
|
|
<p>
|
|
This library is a <b>complete</b> parser of the <a
|
|
href="http://www.iana.org/time-zones">IANA Time Zone Database</a>. This database contains
|
|
timezone information that represents the history of local time for many representative
|
|
locations around the globe. It is updated every few months 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.
|
|
</p>
|
|
|
|
<p>
|
|
The <a href="http://www.iana.org/time-zones">IANA Time Zone Database</a> contains four
|
|
specific types of data:
|
|
</p>
|
|
|
|
<ol>
|
|
<li><p>
|
|
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).
|
|
</p></li>
|
|
<li><p>
|
|
Rule: A specification for a single daylight-saving rule. This helps implement and
|
|
consolidate the specifications of Zones.
|
|
</p></li>
|
|
<li><p>
|
|
link: This is an alternative name for a Zone.
|
|
</p></li>
|
|
<li><p>
|
|
leap: The date of the insertion of a leap second.
|
|
</p></li>
|
|
</ol>
|
|
|
|
<p>
|
|
The library documented herein provides access to <i>all</i> of this data, and offers
|
|
efficient and convenient ways to compute with it. And this is all done based on the <a
|
|
href="date.html"><code>date</code></a> library, which in turn is based on the C++11/14
|
|
<code><chrono></code> library. So once you've learned those fundamental libraries,
|
|
the learning curve for this library is greatly eased.
|
|
</p>
|
|
|
|
<a name="Description"></a><h2>Description</h2>
|
|
|
|
|
|
<p>
|
|
Here is an overview of all the types we are going to talk about at some point. They are
|
|
all fully covered in the reference section. This link is just there to give you a view
|
|
of everything on one quick page so that you don't get lost or overwhelmed. Many of these
|
|
types will never need to be explicitly named in typical use cases.
|
|
</p>
|
|
|
|
<blockquote>
|
|
<a href="tz_types.jpeg">tz_types.jpeg</a>
|
|
</blockquote>
|
|
|
|
<p>
|
|
Everything documented below is in <code>namespace date</code>. Explicit references to
|
|
this namespace in example code below is intentionally omitted in the hopes of reducing
|
|
verbosity.
|
|
</p>
|
|
|
|
<a name="current_local"></a><h3>What is the current local time?</h3>
|
|
|
|
<p>
|
|
One of the first things people want to do is find out what the current local time
|
|
it is. Here is a complete program to print out the local time in human readable
|
|
format:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
#include "tz.h"
|
|
#include <iostream>
|
|
|
|
int
|
|
main()
|
|
{
|
|
using namespace date;
|
|
using namespace std::chrono;
|
|
auto t = make_zoned(current_zone(), system_clock::now());
|
|
std::cout << t << '\n';
|
|
}
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
This just output for me:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
2016-05-14 18:33:24.205124 EDT
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
There are some noteworthy points about this program:
|
|
</p>
|
|
|
|
<ul>
|
|
<li><p>
|
|
This is a <code><chrono></code>-based system. The current time is
|
|
found with <code>std::chrono::system_clock::now()</code>.
|
|
</p></li>
|
|
<li><p>
|
|
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 <code>system_clock</code> tracks
|
|
(unspecified but de facto standard).
|
|
</p></li>
|
|
<li><p>
|
|
Specifying you want to convert <code>system_clock::time_point</code>s to the
|
|
current local time zone is as easy as calling <code>date::current_zone()</code>
|
|
and <i>pairing</i> that with a <code>system_clock::time_point</code> using
|
|
<code>date::make_zoned</code>. This creates a <code>zoned_time</code>.
|
|
</p></li>
|
|
<li><p>
|
|
This <code>zoned_time</code> maintains whatever precision it was given. On my
|
|
platform <code>system_clock::now()</code> has microseconds precision, so in this
|
|
example, <code>t</code> has microseconds precision as well.
|
|
</p></li>
|
|
<li><p>
|
|
Then <code>t</code> is simply streamed out. By default the output
|
|
represents all of the precision it is given.
|
|
</p></li>
|
|
</ul>
|
|
|
|
<p>
|
|
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.
|
|
</p>
|
|
|
|
<p>
|
|
For example let's say we wanted to limit the precision to milliseconds. This can
|
|
be done by inserting <code>floor<milliseconds></code> in one place. This
|
|
makes <code>t</code> have just a precision of <code>milliseconds</code>
|
|
and that is reflected in the streaming operator with no further effort:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
auto t = make_zoned(current_zone(), <b>floor<milliseconds></b>(system_clock::now()));
|
|
std::cout << t << '\n'; // 2016-05-14 18:33:24.205 EDT
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Seconds precision is just as easy:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
auto t = make_zoned(current_zone(), <b>floor<seconds></b>(system_clock::now()));
|
|
std::cout << t << '\n'; // 2016-05-14 18:33:24 EDT
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The entire <code>time_get</code> / <code>time_put</code> formatting capability is
|
|
also at your fingertips (and at any precision):
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
auto t = make_zoned(current_zone(), system_clock::now());
|
|
std::cout << <b>format("%a, %b %d, %Y at %I:%M %p %Z", t)</b> << '\n';
|
|
// Sat, May 14, 2016 at 06:33 PM EDT
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Using any <code>std::locale</code> your OS supports:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
auto t = make_zoned(current_zone(), floor<seconds>(system_clock::now()));
|
|
std::cout << format(<b>locale("de_DE")</b>, "%a, %b %d, %Y at %T %Z", t) << '\n';
|
|
// Sa, Mai 14, 2016 at 18:33:24 EDT
|
|
</pre></blockquote>
|
|
|
|
<a name="somewhere_else"></a><h3>What time is it somewhere <i>else</i> in the world?</h3>
|
|
|
|
<p>
|
|
From the previous section:
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>
|
|
Hmm... German locale in an American time zone.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<p>
|
|
We can fix that easily too:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
<b>auto zone = locate_zone("Europe/Berlin");</b>
|
|
auto t = make_zoned(<b>zone</b>, floor<seconds>(system_clock::now()));
|
|
std::cout << format(locale("de_DE"), "%a, %b %d, %Y at %T %Z", t) << '\n';
|
|
// So, Mai 15, 2016 at 00:33:24 CEST
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The <code>date::locate_zone()</code> function looks up the IANA time zone with the name
|
|
"Europe/Berlin" and returns a <code>const time_zone*</code> which has no ownership
|
|
issues and can be freely and cheaply copied around. It is not possible for
|
|
<code>locate_zone()</code> to return <code>nullptr</code>, though it might throw
|
|
an exception if pushed far enough (e.g. <code>locate_zone("Disney/Mickey_Mouse")</code>).
|
|
</p>
|
|
|
|
<p>
|
|
You can also call <code>make_zoned</code> with the time zone name right in the call:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
auto t = make_zoned(<b>"Europe/Berlin"</b>, floor<seconds>(system_clock::now()));
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The first way is very slightly more efficient if you plan on using <code>zone</code>
|
|
multiple times since it then only has to be looked up once.
|
|
</p>
|
|
|
|
<a name="convert"></a><h3>How do I convert a <code>time_zone</code> from one time zone to another?</h3>
|
|
|
|
<p>
|
|
So far we've only looked at converting from <code>system_clock::now()</code> to
|
|
a local, or specific time zone. We've used <code>make_zoned</code> with the
|
|
first argument being either <code>current_zone()</code> or a specification for
|
|
some other time zone, and the second argument being a
|
|
<code>system_clock::time_point</code>. So far so good.
|
|
</p>
|
|
|
|
<p>
|
|
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?
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
#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';
|
|
}
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The output is the following. But before you forward it, send a generous bonus
|
|
to the guys in Australia.
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
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
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The first time, <code>meet_nyc</code> is a pairing of a time zone ("America/New_York")
|
|
with a <i>local time</i> (<code>mon[1]/may/2016</code> at 09:00). Note that this
|
|
input is exactly reflected in the output:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
The New York meeting is 2016-05-02 09:00:00 EDT
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The next line creates <code>meet_lon</code> with the <code>zoned_time</code>
|
|
<code>meet_nyc</code> and a new time zone: "Europe/London". The effect of this pairing
|
|
is to create a <code>time_point</code> with the exact same UTC time point, but
|
|
associated with a different <code>time_zone</code> for localization purposes. That is,
|
|
after this "converting construction", an invariant is that
|
|
<code>meet_lon.get_sys_time() == meet_nyc.get_sys_time()</code>, even though these
|
|
two objects refer to different time zones.
|
|
</p>
|
|
|
|
<p>
|
|
The same recipe is followed for creating <code>meet_syd</code>. The default formatting
|
|
for these <code>zoned_time</code>s is to output the <i>local</i> date and time followed
|
|
by the current time zone abbreviation.
|
|
</p>
|
|
|
|
<p>
|
|
Summary: <code>zoned_time</code> is a pairing of local or UTC time with a <code>time_zone</code>.
|
|
The result is a well-specified point in time. And it carries with it the ability to
|
|
serve as a translator to any other <code>time_point</code> which carries time zone
|
|
information (to any precision).
|
|
</p>
|
|
|
|
<a name="loc_vs_sys"></a><h3><code>local_time</code> vs <code>sys_time</code></h3>
|
|
|
|
<p>
|
|
Let's say I want to refer to the New Years Day party at 2017-01-01 00:00:00. I don't
|
|
want to refer to a specific party at some geographical location. I want to refer to
|
|
the fact that this moment is celebrated in different parts of the world according to
|
|
local times. This is called a <code>local_time</code>.
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
auto new_years = local_time<days>{2017_y/jan/1} + 0h + 0m + 0s;
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
A <code>local_time<D></code> can be created with any duration <code>D</code> and
|
|
is a <code>std::chrono::time_point</code> except that
|
|
<code>local_time<D>::clock</code> has no <code>now()</code> function. There is
|
|
no time zone associated with <code>local_time</code>.
|
|
</p>
|
|
|
|
<blockquote>
|
|
<p>
|
|
<code>local_time</code> <b>is not</b> the time associated with the current local time
|
|
the computer is set to.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<p>
|
|
<code>local_time</code> <i>is</i> a time associated with an <i>as yet</i>
|
|
unspecified time zone. Only when you pair a <code>local_time</code> with a
|
|
<code>time_zone</code> do you get a concrete point in time that can be converted
|
|
to UTC and other time zones: a <code>zoned_time</code>.
|
|
</p>
|
|
|
|
<p>
|
|
There also exist convenience type aliases:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
using local_seconds = local_time<std::chrono::seconds>;
|
|
using local_days = local_time<days>;
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
In summary: When is 1min after New Years 2017?
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
auto t = local_days{jan/1/2017} + 1min;
|
|
cout << t << '\n'; // 2017-01-01 00:01
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
When is 1min after New Years 2017 UTC?
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
auto t = sys_days{jan/1/2017} + 1min;
|
|
cout << t << '\n'; // 2017-01-01 00:01
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
This effectively means that <code>year_month_day</code> is also ambiguous as to
|
|
whether it refers to a local (timezone-less) time or to UTC. You have to
|
|
specify which when you use it. But that is the nature of how people use dates
|
|
(points in time with days precision). "There will be a celebration on New Years."
|
|
In many contexts the time zone is intentionally left unspecified.
|
|
</p>
|
|
|
|
<p>
|
|
When is 1min after New Years 2017 in New York?
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
zoned_seconds t{"America/New_York", local_days{jan/1/2017} + 1min};
|
|
cout << t << '\n'; // 2017-01-01 00:01:00 EST
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
What time will it be in New York when it is 1min after New Years 2017 UTC?
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
zoned_seconds t{"America/New_York", sys_days{jan/1/2017} + 1min};
|
|
cout << t << '\n'; // 2016-12-31 19:01:00 EST
|
|
</pre></blockquote>
|
|
|
|
<a name="Summary"></a><h3>Summary</h3>
|
|
|
|
<p>
|
|
We now have 5 concepts and their associated types:
|
|
</p>
|
|
|
|
<ol>
|
|
<li><p>
|
|
Calendars: These are day-precision time points that are typically field structures
|
|
(multiple fields that create a unique "name" for a day).
|
|
</p>
|
|
<p>
|
|
Example calendars include <code>year_month_day</code> and
|
|
<code>year_month_weekday</code>. Other examples could include the ISO
|
|
week-based calendar, the Julian calendar, the Islamic calendar, the Hebrew
|
|
calendar, the Chinese calendar, the Mayan calendar, etc.
|
|
</p>
|
|
<p>
|
|
Calendars can convert to and from both <code>sys_days</code> and
|
|
<code>local_days</code>. These two conversions involve identical arithmetic, but
|
|
have semantic differences.
|
|
</p>
|
|
<p>
|
|
Once these conversions are implemented, the calendars are not only interoperable
|
|
with <code>zoned_time</code>, but are also interoperable with each other. That
|
|
is dates in the Chinese calendar can easily be converted to or from dates in the
|
|
Mayan calendar even though these two calendars have no knowledge of the other.
|
|
</p>
|
|
<p>
|
|
Disclaimer: "date.h" provides only the <code>year_month_day</code> and
|
|
<code>year_month_weekday</code> calendars.
|
|
</p></li>
|
|
|
|
<li><p>
|
|
<code>sys_time</code>: This is a serial time point and a
|
|
<code>std::chrono::time_point</code> of arbitrary precision. It has
|
|
<code>sys_seconds</code> and <code>sys_days</code> convenience precisions.
|
|
</p>
|
|
<p>
|
|
<code>sys_time</code> is a <code>time_point</code> associated with the return of
|
|
<code>system_clock::now()</code> and represents
|
|
<a href="https://en.wikipedia.org/wiki/Unix_time">Unix Time</a> which very
|
|
closely approximates UTC.
|
|
</p></li>
|
|
|
|
<li><p>
|
|
<code>local_time</code>: This is a serial time point and a
|
|
<code>std::chrono::time_point</code> of arbitrary precision. It has
|
|
<code>local_seconds</code> and <code>local_days</code> convenience precisions.
|
|
</p>
|
|
<p>
|
|
<code>local_time</code> is a <code>time_point</code> associated with no time
|
|
zone, and no <code>clock::now()</code>. It is the <code>void*</code> of
|
|
<code>time_point</code>s.
|
|
</p></li>
|
|
|
|
<li><p>
|
|
<code>time_zone</code>: This represents a specific geographical area, and all
|
|
time zone related information for this area over all time. This includes a
|
|
name for the area, and for any specific point in time, the UTC offset, the
|
|
abbreviation, and additional information.
|
|
</p></li>
|
|
|
|
|
|
<li><p>
|
|
<code>zoned_time</code>: This is a pairing of a <code>time_zone</code> and a
|
|
<code>sys_time</code> (of precision seconds or finer). It can also be
|
|
equivalently viewed as a pairing of a <code>time_zone</code> and a
|
|
<code>local_time</code>. Once constructed it represents a valid point in time,
|
|
and the <code>time_zone</code>, <code>sys_time</code> and
|
|
<code>local_time</code> can all be extracted. There exists a
|
|
<code>zoned_seconds</code> convenience precision.
|
|
</p></li>
|
|
</ol>
|
|
|
|
<p>
|
|
<code>time_zone</code>s are retrieved from a time zone database. The database
|
|
also holds information about leap seconds. To make computing with leap
|
|
seconds easier, there is a clock that takes leap seconds into account:
|
|
<code>utc_clock</code>. This clock has an associated family of time points
|
|
called <code>utc_time</code>.
|
|
</p>
|
|
|
|
<p>
|
|
Full formatting and parsing facilities are available with <code>time_put</code>-like
|
|
formatting strings.
|
|
</p>
|
|
|
|
<a name="Examples"><h3>Examples</h3>
|
|
|
|
<p>
|
|
Interesting things can happen to the apparent time when you travel across the globe
|
|
at high speeds. So departure and arrival times of airplane flights make for good
|
|
examples involving time zone arithmetic.
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
#include "tz.h"
|
|
#include <iostream>
|
|
|
|
int
|
|
main()
|
|
{
|
|
using namespace std::chrono_literals;
|
|
using namespace date;
|
|
|
|
auto departure = make_zoned("America/New_York", local_days{dec/30/1978} + 12h + 1min);
|
|
auto flight_length = 14h + 44min;
|
|
auto arrival = make_zoned("Asia/Tehran", departure.get_sys_time() + flight_length);
|
|
|
|
std::cout << "departure NYC time: " << departure << '\n';
|
|
std::cout << "flight time is " << make_time(flight_length) << '\n';
|
|
std::cout << "arrival Tehran time: " << arrival << '\n';
|
|
}
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The output of the above program is:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
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
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The departure time is formed by transforming the local calendar date time into a
|
|
<code>local_time</code> and pairing that with the "America/New_York"
|
|
<code>time_zone</code> to form a <code>zoned_time</code>. The flight time is
|
|
just an ordinary <code>chrono::duration</code>.
|
|
</p>
|
|
|
|
<p>
|
|
The arrival time is formed by retrieving the departure time in terms of
|
|
<code>sys_time</code>, adding the length of the flight, and pairing that
|
|
<code>sys_time</code> with the "Asia/Tehran" <code>time_zone</code> to form a
|
|
<code>zoned_time</code>.
|
|
</p>
|
|
|
|
<p>
|
|
By doing the arithmetic (addition of the flight time) in the UTC (well system)
|
|
time zone, we do not have to worry about things like daylight savings time, or
|
|
other political changes to the either UTC offset. For example if we change one
|
|
line to look at the same flight 24 hours later:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
auto departure = make_zoned("America/New_York", local_days{dec/<b>31</b>/1978} + 12h + 1min);
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Then the output changes to:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
departure NYC time: 1978-12-<b>31</b> 12:01:00 EST
|
|
flight time is 14:44
|
|
arrival Tehran time: 1979-01-01 11:<b>15</b>:00 IRST
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
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. Because there was also a leap second insertion while the plane
|
|
was in the air. This can be taken into account with the following code:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
#include "tz.h"
|
|
#include <iostream>
|
|
|
|
int
|
|
main()
|
|
{
|
|
using namespace std::chrono_literals;
|
|
using namespace date;
|
|
|
|
auto departure = make_zoned("America/New_York", local_days{dec/31/1978} + 12h + 1min);
|
|
<b>auto departure_utc = to_utc_time(departure.get_sys_time());</b>
|
|
auto flight_length = 14h + 44min;
|
|
auto arrival = make_zoned("Asia/Tehran", <b>to_sys_time(departure_utc + flight_length)</b>);
|
|
|
|
std::cout << "departure NYC time: " << departure << '\n';
|
|
std::cout << "flight time is " << make_time(flight_length) << '\n';
|
|
std::cout << "arrival Tehran time: " << arrival << '\n';
|
|
}
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
This is just like the previous example except that the arithmetic (departure
|
|
time + flight length) is done in <code>utc_time</code> instead of
|
|
<code>sys_time</code>. To accomplish this, there is a conversion from
|
|
<code>sys_time</code> to <code>utc_time</code> before the arithmetic, and
|
|
another conversion from <code>utc_time</code> to <code>sys_time</code> after the
|
|
arithmetic. And the result changes to:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
departure NYC time: 1978-12-31 12:01:00 EST
|
|
flight time is 14:44
|
|
arrival Tehran time: 1979-01-01 11:<b>14:59</b> IRST
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
A common task in dealing with dates and times is converting from one string format
|
|
to another. This library is extremely flexible in handling this task. As an
|
|
example, let's say that you need to convert strings that look like this:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
Sun Sep 16 01:03:52 -0500 1973
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Into strings that look like this:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
1973-09-16T06:03:52.000Z
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
That is, given a local time with UTC offset, you need to not only update the format
|
|
to something more modern, but it also has to be converted to the UTC timezone and to
|
|
a precision of milliseconds. The code to do this is quite straight forward:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
std::string
|
|
convert(const std::string& input)
|
|
{
|
|
using namespace std;
|
|
using namespace std::chrono;
|
|
using namespace date;
|
|
istringstream stream{input};
|
|
sys_time<milliseconds> t;
|
|
stream >> parse("%a %b %d %T %z %Y", t);
|
|
if (stream.fail())
|
|
throw runtime_error("failed to parse " + input);
|
|
return format("%FT%TZ", t);
|
|
}
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Let's walk through this:
|
|
</p>
|
|
|
|
<p>
|
|
First, <code>date::parse</code> works with <code>istream</code>s so you can parse from
|
|
files, from strings, or anything else that is an <code>istream</code>.
|
|
</p>
|
|
|
|
<p>
|
|
Second, while we don't need to parse to a precision of milliseconds, we need to
|
|
format to that precision. It is easy just to parse into a
|
|
milliseconds-precision <code>sys_time</code> so that we can then just format it
|
|
back out with no change. If we needed to parse at finer precision than
|
|
formatting, then we would need to parse at the higher precision, truncate it (by
|
|
some rounding mode — <code>truncate</code>, <code>floor,</code>
|
|
<code>ceil</code> or <code>round</code>), and then format the truncated value.
|
|
</p>
|
|
|
|
<p>
|
|
To have the <code>parse</code> interpret the string as a local time offset by the
|
|
UTC offset, we need to ask for a <code>sys_time</code> to be parsed, and use
|
|
the <code>%z</code> in the proper location. The <code>parse</code> function will
|
|
then subtract the UTC offset to give us the proper <code>sys_time</code> value.
|
|
</p>
|
|
|
|
<p>
|
|
If <code>parse</code> fails to find <i>everything</i> in the parse/format string,
|
|
exactly as specified, it will set <code>failbit</code> in the <code>istream</code>.
|
|
</p>
|
|
|
|
<p>
|
|
Finally, once we know we have a successfully parsed
|
|
<code>sys_time<milliseconds></code> it is a very simple matter to format
|
|
it back out in whatever format is desired. As confirmed in the
|
|
<a href="#Reference">Reference</a>, <code>%S</code> and <code>%T</code> are
|
|
sensitive to the precision of the time point argument, and so there is no need
|
|
for extension formatting flags to indicate fractional seconds. <code>%S</code>
|
|
and <code>%T</code> just work.
|
|
</p>
|
|
|
|
<a name="Reference"></a><h2>Reference</h2>
|
|
|
|
<p>
|
|
Everything specified below is in <code>namespace date</code>, and accessed via the
|
|
header <code>"tz.h"</code>.
|
|
</p>
|
|
|
|
<a name="database"></a><h3>The database</h3>
|
|
<blockquote>
|
|
|
|
<p>
|
|
The following data structure is the time zone database, and the following
|
|
functions access it.
|
|
</p>
|
|
|
|
<pre>
|
|
struct TZ_DB
|
|
{
|
|
std::string version;
|
|
std::vector<time_zone> zones;
|
|
std::vector<link> links;
|
|
std::vector<leap> leaps;
|
|
std::vector<Rule> rules;
|
|
};
|
|
</pre>
|
|
|
|
<p>
|
|
The <cod>TZ_DB</code> database is a singleton. And access to it is
|
|
<i>read-only</i>, except for <code>reload_tzdb()</code> which re-initializes it.
|
|
Each <code>vector</code> is sorted to enable fast lookup. You don't have to explicitly
|
|
program binary search lookups on it. That is handled by the API. But you <i>can</i>
|
|
explicitly iterate over and inspect this database. And knowing that it is sorted may
|
|
be of benefit to your inspection logic.
|
|
</p>
|
|
|
|
<p>
|
|
<i>All</i> information in the
|
|
<a href="http://www.iana.org/time-zones">IANA time zone database</a> is
|
|
represented in the above <code>TZ_DB</code> data structure, except for the
|
|
comments in the database. Thus it is up to you, the client of this library, to
|
|
decide what to do with this data. This library makes it especially easy and
|
|
convenient to extract the data in the way that is most commonly used (e.g. time
|
|
conversions among time zones). But it represents <i>all</i> of the data, and
|
|
hides <i>none</i> of it.
|
|
</p>
|
|
|
|
<pre>
|
|
const TZ_DB& get_tzdb();
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> If this is the first access to the database, will initialize
|
|
the database. If <code>tz.cpp</code> was compiled with the configuration macro
|
|
<code>AUTO_DOWNLOAD == 1</code>, initialization will include checking the
|
|
<a href="http://www.iana.org/time-zones">IANA website</a> for the latest
|
|
version, and downloading the latest version if your local version is out of
|
|
date, or doesn't exist at the location referred to by the <code>install</code>
|
|
configuration variable in <code>tz.cpp</code>. If <code>tz.cpp</code> was
|
|
compiled with <code>AUTO_DOWNLOAD == 0</code>, you will have to download and
|
|
decompress the IANA database from the
|
|
<a href="http://www.iana.org/time-zones">IANA website</a> and place it at the
|
|
location referred to by the <code>install</code> configuration variable.
|
|
</p>
|
|
<p>
|
|
<code>AUTO_DOWNLOAD == 1</code> requires linking <code>tz.cpp</code> to
|
|
<a href="https://curl.haxx.se/libcurl/"><code>libcurl</code></a>.
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> A <code>const</code> reference to the database.
|
|
</p>
|
|
<p>
|
|
<i>Thread Safety:</i> It is safe to call this function from multiple threads at
|
|
one time. There will be no race to initialize the singleton database as long as
|
|
your compiler implements threadsafe function-local statics as specified by C++11.
|
|
</p>
|
|
<p>
|
|
<i>Throws:</i> <code>std::runtime_error</code> if for any reason a reference can not
|
|
be returned to a valid <code>TZ_DB</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
const time_zone* locate_zone(const std::string& tz_name);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Calls <code>get_tzdb()</code> which will initialize the timezone
|
|
database if this is the first reference to the database.
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> If a <code>time_zone</code> is found for which
|
|
<code>name() == tz_name</code>, returns a pointer to that <code>time_zone</code>.
|
|
Otherwise if a <code>link</code> is found where <code>tz_name == link.name()</code>,
|
|
then a pointer is returned to the <code>time_zone</code> for which
|
|
<code>zone.name() == link.target()</code> [<i>Note:</i> A <code>link</code> is an
|
|
alternative name for a <code>time_zone</code>. <i>— end note</i>]
|
|
</p>
|
|
<p>
|
|
<i>Throws:</i> Any exception propagated from <code>get_tzdb()</code>. If a
|
|
<code>const time_zone*</code> can not be found as described in the
|
|
<i>Returns</i> clause, throws a <code>std::runtime_error</code>. [<i>Note:</i>
|
|
On non-exceptional return, the return value is <i>always</i> a pointer to a
|
|
valid <code>time_zone</code>. <i>— end note</i>]
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
const time_zone* current_zone();
|
|
</pre>
|
|
<blockquote>
|
|
<i>Effects:</i> Calls <code>locate_zone()</code> which will initialize the timezone
|
|
database if this is the first reference to the database.
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> A <code>const time_zone*</code> referring to the time zone which your
|
|
computer has set as its local time zone.
|
|
</p>
|
|
<p>
|
|
<i>Throws:</i> Any exception propagated from <code>locate_zone()</code>.
|
|
[<i>Note:</i> On non-exceptional return, the return value is <i>always</i> a
|
|
pointer to a valid <code>time_zone</code>. <i>— end note</i>]
|
|
</blockquote>
|
|
|
|
<pre>
|
|
const TZ_DB& reload_tzdb();
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i>
|
|
</p>
|
|
<blockquote>
|
|
<p>
|
|
If If <code>tz.cpp</code> was compiled with the configuration macro
|
|
<code>AUTO_DOWNLOAD == 1</code>, this function first checks the latest version at the
|
|
<a href="http://www.iana.org/time-zones">IANA website</a>. If the
|
|
<a href="http://www.iana.org/time-zones">IANA website</a> is unavailable, or if the
|
|
latest version is already installed, there are no effects. Otherwise, a new version
|
|
is available. It is downloaded and installed, and then the program re-initializes
|
|
the <code>TZ_DB</code> singleton from the new disk files.
|
|
</p>
|
|
|
|
<p>
|
|
If <code>tz.cpp</code> was compiled with the configuration macro
|
|
<code>AUTO_DOWNLOAD == 0</code>, this function re-initializes the
|
|
<code>TZ_DB</code> singleton from the disk files. You can manually replace the
|
|
database without ill-effects after your program has called
|
|
<code>get_tzdb()</code> and before it calls <code>reload_tzdb()</code>, as there is
|
|
no access to the files on disk between the first call to <code>get_tzdb()</code> and
|
|
subsequent calls to <code>reload_tzdb()</code>.
|
|
</p>
|
|
</blockquote>
|
|
<p>
|
|
<i>Returns:</i> A <code>const</code> reference to the database.
|
|
</p>
|
|
<p>
|
|
<i>Thread Safety:</i> This function is <i>not</i> thread safe. You must
|
|
provide your own synchronization among threads accessing the time zone database
|
|
to safely use this function. If this function re-initializes the database (as
|
|
it <i>always</i> does when <code>AUTO_DOWNLOAD == 0</code>), all outstanding
|
|
<code>const time_zone*</code> are invalidated (including those held within
|
|
<code>zoned_time</code> objects). And afterwards, all outstanding
|
|
<code>sys_info</code> may hold obsolete data.
|
|
</p>
|
|
<p>
|
|
<i>Throws:</i> <code>std::runtime_error</code> if for any reason a reference can not
|
|
be returned to a valid <code>TZ_DB</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<p>
|
|
The following functions are available only if you compile with the configuration macro
|
|
<code>HAS_REMOTE_API == 1</code>. Use of this API requires linking to
|
|
<a href="https://curl.haxx.se/libcurl/"><code>libcurl</code></a>.
|
|
<code>AUTO_DOWNLOAD == 1</code> requires <code>HAS_REMOTE_API == 1</code>. You
|
|
will be notified at compile time if <code>AUTO_DOWNLOAD == 1</code> and
|
|
<code>HAS_REMOTE_API == 0</code>. If <code>HAS_REMOTE_API == 1</code>, then
|
|
<code>AUTO_DOWNLOAD</code> defaults to <code>1</code>, otherwise
|
|
<code>AUTO_DOWNLOAD</code> defaults to <code>0</code>. On Windows,
|
|
<code>HAS_REMOTE_API</code> defaults to <code>0</code>. Everywhere else it
|
|
defaults to <code>1</code>. This is because
|
|
<a href="https://curl.haxx.se/libcurl/"><code>libcurl</code></a> comes preinstalled
|
|
everywhere but Windows, but it is available for Windows.
|
|
</p>
|
|
|
|
<p>
|
|
[<i>Note:</i> Even with <code>AUTO_DOWNLOAD == 1</code>, there are no thread-safety
|
|
issues with this library unless one of the following functions are <i>explicitly</i>
|
|
called by your code:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
const TZ_DB& reload_tzdb();
|
|
bool remote_download(const std::string& version);
|
|
bool remote_install(const std::string& version);
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
Once your program has initialized the <code>TZ_DB</code> singleton, that singleton
|
|
can <i>never</i> be changed without <i>explicit</i> use of <code>reload_tzdb()</code>.
|
|
<i>— end note</i>]
|
|
</p>
|
|
|
|
<blockquote>
|
|
|
|
<pre>
|
|
std::string remote_version();
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> The latest database version number from the
|
|
<a href="http://www.iana.org/time-zones">IANA website</a>. If the
|
|
<a href="http://www.iana.org/time-zones">IANA website</a> can not be reached, or
|
|
if it can be reached but the latest version number is unexpectedly not
|
|
available, the empty string is returned.
|
|
</p>
|
|
<p>
|
|
<i>Note:</i> If non-empty, this can be compared with <code>get_tzdb().version</code> to
|
|
discover if you have the latest database installed.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
bool remote_download(const std::string& version);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> If <code>version == remote_version()</code> this function will download
|
|
the compressed tar file holding the latest time zone database from the
|
|
<a href="http://www.iana.org/time-zones">IANA website</a>. The tar file will be placed
|
|
at the location indicated by the <code>install</code> configuration variable in
|
|
<code>tz.cpp</code>.
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> <code>true</code> if the database was successfully downloaded, else
|
|
<code>false</code>.
|
|
</p>
|
|
<p>
|
|
<i>Thread safety:</i> If called by multiple threads, there will be a race on the
|
|
creation of the tar file at <code>install</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
bool remote_install(const std::string& version);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> If <code>version</code> refers to the file successfully
|
|
downloaded by <code>remote_download()</code> this function will remove the
|
|
existing time zone database at <code>install</code>, then extract a new database
|
|
from the tar file and place it at <code>install</code>, and finally will delete
|
|
the tar file.
|
|
</p>
|
|
<p>
|
|
This function <i>does not</i> cause your program to re-initialize itself from
|
|
this new database. In order to do that, you must call
|
|
<code>reload_tzdb()</code> (or <code>get_tzdb()</code> if the database has yet
|
|
to be initialized). If <code>tz.cpp</code> was compiled with
|
|
<code>AUTO_DOWNLOAD == 1</code>, then <code>reload_tzdb()</code> uses this API
|
|
to check if the database is out of date, and reinitializes it with a freshly downloaded
|
|
database only if it needs to. Indeed, if <code>AUTO_DOWNLOAD == 1</code> there is
|
|
never any need to call <code>remote_download()</code> or <code>remote_install()</code>
|
|
explicitly. You can just call <code>reload_tzdb()</code> instead. This API is
|
|
only exposed so that you can take care of this manually if desired
|
|
(<code>HAS_REMOTE_API == 1 && AUTO_DOWNLOAD == 0</code>).
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> <code>true</code> if the database was successfully replaced by
|
|
the tar file , else <code>false</code>.
|
|
</p>
|
|
<p>
|
|
<i>Thread safety:</i> If called by multiple threads, there will be a race on the
|
|
creation of the new database at <code>install</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
</blockquote>
|
|
|
|
<p>
|
|
Everything else in this library concerns <i>read-only</i> access to this
|
|
database, and intuitive ways to compute with that information, even while being
|
|
oblivious to the fact that you <i>are</i> accessing a database.
|
|
</p>
|
|
|
|
<p>
|
|
The entire database on disk occupies less than half of the disk space consumed by
|
|
an average Beatles song. Don't sweat multiple copies of it. It will easily fit in
|
|
your smart toaster.
|
|
</p>
|
|
|
|
</blockquote>
|
|
|
|
<a name="choose"></a><h3><code>choose</code></h3>
|
|
|
|
<blockquote>
|
|
<p>
|
|
For some conversions from <code>local_time</code> to a <code>sys_time</code>,
|
|
<code>choose::earliest</code> or <code>choose::latest</code> can be used to
|
|
convert a non-existent or ambiguous <code>local_time</code> into a
|
|
<code>sys_time</code>, instead of throwing an exception.
|
|
</p>
|
|
<pre>
|
|
enum class choose {earliest, latest};
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<a name="nonexistent_local_time"></a><h3><code>nonexistent_local_time</code></h3>
|
|
|
|
<blockquote>
|
|
<p>
|
|
<code>nonexistent_local_time</code> is thrown when one attempts to convert a
|
|
non-existent <code>local_time</code> to a <code>sys_time</code> without specifying
|
|
<code>choose::earliest</code> or <code>choose::latest</code>.
|
|
</p>
|
|
<pre>
|
|
class nonexistent_local_time
|
|
: public std::runtime_error
|
|
{
|
|
public:
|
|
// Construction is undocumented
|
|
};
|
|
</pre>
|
|
<p>
|
|
[<i>Example:</i>
|
|
</p>
|
|
<blockquote>
|
|
<pre>
|
|
#include "tz.h"
|
|
#include <iostream>
|
|
|
|
int
|
|
main()
|
|
{
|
|
using namespace date;
|
|
using namespace std::chrono_literals;
|
|
try
|
|
{
|
|
auto zt = make_zoned("America/New_York", local_days{sun[2]/mar/2016} + 2h + 30min);
|
|
}
|
|
catch (const nonexistent_local_time& e)
|
|
{
|
|
std::cout << e.what() << '\n';
|
|
}
|
|
}
|
|
</pre>
|
|
<p>
|
|
Which outputs:
|
|
</p>
|
|
<pre>
|
|
2016-03-13 02:30:00 is in a gap between
|
|
2016-03-13 02:00:00 EST and
|
|
2016-03-13 03:00:00 EDT which are both equivalent to
|
|
2016-03-13 07:00:00 UTC
|
|
</pre>
|
|
</blockquote>
|
|
<p>
|
|
<i>— end example:</i>]
|
|
</p>
|
|
</blockquote>
|
|
|
|
<a name="ambiguous_local_time"></a><h3><code>ambiguous_local_time</code></h3>
|
|
|
|
<blockquote>
|
|
<p>
|
|
<code>ambiguous_local_time</code> is thrown when one attempts to convert an ambiguous
|
|
<code>local_time</code> to a <code>sys_time</code> without specifying
|
|
<code>choose::earliest</code> or <code>choose::latest</code>.
|
|
</p>
|
|
<pre>
|
|
class ambiguous_local_time
|
|
: public std::runtime_error
|
|
{
|
|
public:
|
|
// Construction is undocumented
|
|
};
|
|
</pre>
|
|
<p>
|
|
[<i>Example:</i>
|
|
</p>
|
|
<blockquote>
|
|
<pre>
|
|
#include "tz.h"
|
|
#include <iostream>
|
|
|
|
int
|
|
main()
|
|
{
|
|
using namespace date;
|
|
using namespace std::chrono_literals;
|
|
try
|
|
{
|
|
auto zt = make_zoned("America/New_York", local_days{sun[1]/nov/2016} + 1h + 30min);
|
|
}
|
|
catch (const ambiguous_local_time& e)
|
|
{
|
|
std::cout << e.what() << '\n';
|
|
}
|
|
}
|
|
</pre>
|
|
<p>
|
|
Which outputs:
|
|
</p>
|
|
<pre>
|
|
2016-11-06 01:30:00 is ambiguous. It could be
|
|
2016-11-06 01:30:00 EDT == 2016-11-06 05:30:00 UTC or
|
|
2016-11-06 01:30:00 EST == 2016-11-06 06:30:00 UTC
|
|
</pre>
|
|
</blockquote>
|
|
<p>
|
|
<i>— end example:</i>]
|
|
</p>
|
|
</blockquote>
|
|
|
|
<a name="sys_info"></a><h3><code>sys_info</code></h3>
|
|
|
|
<blockquote>
|
|
<p>
|
|
This structure can be obtained from the combination of a <code>time_zone</code> and
|
|
either a <code>sys_time</code>, or <code>local_time</code>. It can also be obtained
|
|
from a <code>zoned_time</code> which is effectively a <code>pair</code> of
|
|
a <code>time_zone</code> and <code>sys_time</code>.
|
|
</p>
|
|
<p>
|
|
This structure represents a lower-level API. Typical conversions from
|
|
<code>sys_time</code> to <code>local_time</code> will use this structure
|
|
<i>implicitly</i>, not <i>explicitly</i>.
|
|
</p>
|
|
<pre>
|
|
struct sys_info
|
|
{
|
|
sys_seconds begin;
|
|
sys_seconds end;
|
|
std::chrono::seconds offset;
|
|
std::chrono::minutes save;
|
|
std::string abbrev;
|
|
};
|
|
</pre>
|
|
<p>
|
|
The <code>begin</code> and <code>end</code> fields indicate that for the
|
|
associated <code>time_zone</code> and <code>time_point</code>, the
|
|
<code>offset</code> and <code>abbrev</code> are in effect in the range
|
|
<code>[begin, end)</code>. This information can be used to efficiently iterate the
|
|
transitions of a <code>time_zone</code>.
|
|
</p>
|
|
<p>
|
|
The <code>offset</code> field indicates the UTC offset in effect for the associated
|
|
<code>time_zone</code> and <code>time_point</code>. The relationship between
|
|
<code>local_time</code> and <code>sys_time</code> is:
|
|
</p>
|
|
<pre>
|
|
offset = local_time - sys_time
|
|
</pre>
|
|
<p>
|
|
The <code>save</code> field is "extra" information not normally needed for
|
|
conversion between <code>local_time</code> and <code>sys_time</code>. If
|
|
<code>save != 0min</code>, this <code>sys_info</code> is said to be on "daylight
|
|
saving" time, and <code>offset - save</code> suggests what this
|
|
<code>time_zone</code> <i>might</i> use if it were off daylight saving. However
|
|
this information should not be taken as authoritative. The only sure way to get
|
|
such information is to query the <code>time_zone</code> with a
|
|
<code>time_point</code> that returns an <code>sys_info</code> where <code>save ==
|
|
0min</code>. There is no guarantee what <code>time_point</code> might return such
|
|
an <code>sys_info</code> except that it is guaranteed <i>not</i> to be in the range
|
|
<code>[begin, end)</code> (if <code>save != 0min</code> for this <code>sys_info</code>).
|
|
</p>
|
|
<p>
|
|
The <code>abbrev</code> field indicates the current abbreviation used for the
|
|
associated <code>time_zone</code> and <code>time_point</code>. Abbreviations
|
|
are not unique among the <code>time_zone</code>s, and so one can not reliably
|
|
map abbreviations back to a <code>time_zone</code> and UTC offset.
|
|
</p>
|
|
<p>
|
|
You can stream out a <code>sys_info</code>:
|
|
</p>
|
|
<pre>
|
|
std::ostream& operator<<(std::ostream& os, const sys_info& r);
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<a name="local_info"></a><h3><code>local_info</code></h3>
|
|
|
|
<blockquote>
|
|
<p>
|
|
This structure represents a lower-level API. Typical conversions from
|
|
<code>local_time</code> to <code>sys_time</code> will use this structure
|
|
<i>implicitly</i>, not <i>explicitly</i>.
|
|
</p>
|
|
<pre>
|
|
struct local_info
|
|
{
|
|
enum {unique, nonexistent, ambiguous} result;
|
|
sys_info first;
|
|
sys_info second;
|
|
};
|
|
</pre>
|
|
<p>
|
|
When a <code>local_time</code> to <code>sys_time</code> conversion is unique,
|
|
<code>result == unique</code>, <code>first</code> will be filled out with the
|
|
correct <code>sys_info</code> and <code>second</code> will be zero-initialized.
|
|
If the conversion stems from a nonexistent <code>local_time</code> then
|
|
<code>result == nonexistent</code>, <code>first</code> will be filled out with
|
|
the <code>sys_info</code> that ends just prior to the <code>local_time</code>
|
|
and <code>second</code> will be filled out with the <code>sys_info</code> that
|
|
begins just after the <code>local_time</code>. If the conversion stems from an
|
|
ambiguous <code>local_time</code> then <code>result == ambiguous</code>,
|
|
<code>first</code> will be filled out with the <code>sys_info</code> that ends
|
|
just after the <code>local_time</code> and <code>second</code> will be filled
|
|
out with the <code>sys_info</code> that starts just before the
|
|
<code>local_time</code>.
|
|
</p>
|
|
<p>
|
|
You can stream out a <code>local_info</code>:
|
|
</p>
|
|
<pre>
|
|
std::ostream& operator<<(std::ostream& os, const local_info& r);
|
|
</pre>
|
|
|
|
</blockquote>
|
|
|
|
<a name="time_zone"></a><h3><code>time_zone</code></h3>
|
|
|
|
<blockquote>
|
|
<p>
|
|
A <code>time_zone</code> represents all time zone transitions for a specific geographic
|
|
area. <code>time_zone</code> construction is undocumented, and done for you during
|
|
the database initialization. You can gain <code>const</code> access to a
|
|
<code>time_zone</code> via functions such as <code>locate_zone</code>.
|
|
</p>
|
|
<pre>
|
|
class time_zone
|
|
{
|
|
public:
|
|
time_zone(const time_zone&) = delete;
|
|
time_zone& operator=(const time_zone&) = delete;
|
|
|
|
const std::string& name() const;
|
|
|
|
template <class Duration> sys_info get_info(sys_time<Duration> st) const;
|
|
template <class Duration> local_info get_info(local_time<Duration> tp) const;
|
|
|
|
template <class Duration>
|
|
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
to_sys(local_time<Duration> tp) const;
|
|
|
|
template <class Duration>
|
|
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
to_sys(local_time<Duration> tp, choose z) const;
|
|
|
|
template <class Duration>
|
|
local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
to_local(sys_time<Duration> tp) const;
|
|
};
|
|
|
|
bool operator==(const time_zone& x, const time_zone& y);
|
|
bool operator!=(const time_zone& x, const time_zone& y);
|
|
bool operator< (const time_zone& x, const time_zone& y);
|
|
bool operator> (const time_zone& x, const time_zone& y);
|
|
bool operator<=(const time_zone& x, const time_zone& y);
|
|
bool operator>=(const time_zone& x, const time_zone& y);
|
|
|
|
std::ostream& operator<<(std::ostream& os, const time_zone& z)
|
|
</pre>
|
|
<pre>
|
|
const std::string& time_zone::name() const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> The name of the <code>time_zone</code>.
|
|
</p>
|
|
<p>
|
|
<i>Example:</i> "America/New_York".
|
|
</p>
|
|
<p>
|
|
<i>Note:</i> Here is an unofficial list of <code>time_zone</code> names:
|
|
<a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">https://en.wikipedia.org/wiki/List_of_tz_database_time_zones</a>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration> sys_info time_zone::get_info(sys_time<Duration> st) const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> A <code>sys_info</code> <code>i</code> for which <code>st</code> is in the
|
|
range <code>[i.begin, i.end)</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration> local_info time_zone::get_info(local_time<Duration> tp) const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> A <code>local_info</code> for <code>tp</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
time_zone::to_sys(local_time<Duration> tp) const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> A <code>sys_time</code> that is at least as fine as <code>seconds</code>,
|
|
and will be finer if the argument <code>tp</code> has finer precision. This
|
|
<code>sys_time</code> is the UTC equivalent of <code>tp</code> according to the rules
|
|
of this <code>time_zone</code>.
|
|
</p>
|
|
<p>
|
|
<i>Throws:</i> If the conversion from <code>tp</code> to a <code>sys_time</code>
|
|
is ambiguous, throws <code>ambiguous_local_time</code>. If the conversion from
|
|
<code>tp</code> to a <code>sys_time</code> is nonexistent, throws
|
|
<code>nonexistent_local_time</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
time_zone::to_sys(local_time<Duration> tp, choose z) const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> A <code>sys_time</code> that is at least as fine as
|
|
<code>seconds</code>, and will be finer if the argument <code>tp</code> has
|
|
finer precision. This <code>sys_time</code> is the UTC equivalent of
|
|
<code>tp</code> according to the rules of this <code>time_zone</code>. If the
|
|
conversion from <code>tp</code> to a <code>sys_time</code> is ambiguous, returns
|
|
the earlier <code>sys_time</code> if <code>z == choose::earliest</code>, and
|
|
returns the later <code>sys_time</code> if <code>z == choose::latest</code>. If
|
|
the <code>tp</code> represents a non-existent time between two UTC
|
|
<code>time_point</code>s, then the two UTC <code>time_point</code>s will be the
|
|
same, and that UTC <code>time_point</code> will be returned.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
local_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
time_zone::to_local(sys_time<Duration> tp) const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> The <code>local_time</code> associated with <code>tp</code> and this
|
|
<code>time_zone</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
bool operator==(const time_zone& x, const time_zone& y);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>x.name() == y.name()</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
bool operator!=(const time_zone& x, const time_zone& y);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>!(x == y)</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
bool operator<(const time_zone& x, const time_zone& y);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>x.name() < y.name()</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
bool operator>(const time_zone& x, const time_zone& y);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>y < x</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
bool operator<=(const time_zone& x, const time_zone& y);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>!(y < x)</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
bool operator>=(const time_zone& x, const time_zone& y);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>!(x < y)</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
std::ostream& operator<<(std::ostream& os, const time_zone& z)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
Produces an output that is probably more meaningful to me than it is to you. I found it
|
|
useful for debugging this library.
|
|
</p>
|
|
</blockquote>
|
|
|
|
</blockquote>
|
|
|
|
<a name="zoned_time"></a><h3><code>zoned_time</code></h3>
|
|
|
|
<blockquote>
|
|
<p>
|
|
<code>zoned_time</code> represents a logical paring of <code>time_zone</code> and a
|
|
<code>time_point</code> with precision <code>Duration</code>. If <code>seconds</code>
|
|
is not implicitly convertible to <code>Duration</code>, the instantiation is ill-formed.
|
|
[<i>Note:</i> There exist <code>time_zone</code>s with UTC offsets that require a
|
|
precision of <code>seconds</code>. <i>— end note:</i>]
|
|
</p>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
class zoned_time
|
|
{
|
|
const time_zone* zone_; // exposition only
|
|
sys_time<Duration> tp_; // exposition only
|
|
|
|
public:
|
|
zoned_time(const zoned_time&) = default;
|
|
zoned_time& operator=(const zoned_time&) = default;
|
|
|
|
zoned_time(sys_time<Duration> st);
|
|
explicit zoned_time(const time_zone* z);
|
|
explicit zoned_time(const std::string& name);
|
|
|
|
template <class Duration2,
|
|
class = std::enable_if_t
|
|
<
|
|
std::is_convertible<sys_time<Duration2>,
|
|
sys_time<Duration>>{}
|
|
>>
|
|
zoned_time(const zoned_time<Duration2>& zt) noexcept;
|
|
|
|
zoned_time(const time_zone* z, local_time<Duration> tp);
|
|
zoned_time(const std::string& name, local_time<Duration> tp);
|
|
zoned_time(const time_zone* z, local_time<Duration> tp, choose c);
|
|
zoned_time(const std::string& name, local_time<Duration> tp, choose c);
|
|
|
|
zoned_time(const time_zone* z, const zoned_time<Duration>& zt);
|
|
zoned_time(const std::string& name, const zoned_time<Duration>& zt);
|
|
zoned_time(const time_zone* z, const zoned_time<Duration>& zt, choose);
|
|
zoned_time(const std::string& name, const zoned_time<Duration>& zt, choose);
|
|
|
|
zoned_time(const time_zone* z, const sys_time<Duration>& st);
|
|
zoned_time(const std::string& name, const sys_time<Duration>& st);
|
|
|
|
zoned_time& operator=(sys_time<Duration> st);
|
|
zoned_time& operator=(local_time<Duration> ut);
|
|
|
|
operator sys_time<Duration>() const;
|
|
explicit operator local_time<Duration>() const;
|
|
|
|
const time_zone* get_time_zone() const;
|
|
local_time<Duration> get_local_time() const;
|
|
sys_time<Duration> get_sys_time() const;
|
|
sys_info get_info() const;
|
|
};
|
|
|
|
using zoned_seconds = zoned_time<std::chrono::seconds>;
|
|
|
|
template <class Duration1, class Duration2>
|
|
bool
|
|
operator==(const zoned_time<Duration1>& x, const zoned_time<Duration2>& y);
|
|
|
|
template <class Duration1, class Duration2>
|
|
bool
|
|
operator!=(const zoned_time<Duration1>& x, const zoned_time<Duration2>& y);
|
|
</pre>
|
|
|
|
<p>
|
|
An invariant of <code>zoned_time<Duration></code> is that it always refers
|
|
to a valid <code>time_zone</code>, and represents a point in time that exists
|
|
and is not ambiguous.
|
|
</p>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const zoned_time&) = default;
|
|
zoned_time<Duration>& zoned_time<Duration>::operator=(const zoned_time&) = default;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
The copy members transfer the associated <code>time_zone</code> from the source
|
|
to the destination. After copying, source and destination compare equal. If
|
|
<code>Duration</code> has <code>noexcept</code> copy members, then
|
|
<code>zoned_time<Duration></code> has <code>noexcept</code> copy
|
|
members.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(sys_time<Duration> st);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Constructs a <code>zoned_time</code> <code>zt</code> such that
|
|
<code>zt.get_time_zone()->name() == "UTC"</code>, and
|
|
<code>zt.get_sys_time() == st</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
explicit zoned_time<Duration>::zoned_time(const time_zone* z);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Requires:</i> <code>z</code> refers to a valid <code>time_zone</code>.
|
|
</p>
|
|
<p>
|
|
<i>Effects:</i> Constructs a <code>zoned_time</code> <code>zt</code> such that
|
|
<code>zt.get_time_zone()-> == z</code>, and
|
|
<code>zt.get_sys_time() == sys_seconds{}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
explicit zoned_time<Duration>::zoned_time(const std::string& name);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Equivalent to construction with <code>locate_zone(name)</code>.
|
|
</p>
|
|
<p>
|
|
<i>Throws:</i> Any exception propagating out of <code>locate_zone(name)</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration2,
|
|
class = std::enable_if_t
|
|
<
|
|
std::is_convertible<sys_time<Duration2>,
|
|
sys_time<Duration>>{}
|
|
>>
|
|
zoned_time<Duration>::zoned_time(const zoned_time<Duration2>& y) noexcept;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Constructs a <code>zoned_time</code> <code>x</code> such that
|
|
<code>x == y</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const time_zone* z, local_time<Duration> tp);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Requires:</i> <code>z</code> refers to a valid <code>time_zone</code>.
|
|
</p>
|
|
<p>
|
|
<i>Effects:</i> Constructs a <code>zoned_time</code> <code>zt</code> such that
|
|
<code>zt.get_time_zone()-> == z</code>, and <code>zt.get_local_time() == tp</code>.
|
|
</p>
|
|
<p>
|
|
<i>Throws:</i> Any exception that <code>z->to_sys(tp)</code> would throw.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const std::string& name, local_time<Duration> tp);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Equivalent to construction with <code>{locate_zone(name), tp}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const time_zone* z, local_time<Duration> tp, choose c);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Requires:</i> <code>z</code> refers to a valid <code>time_zone</code>.
|
|
</p>
|
|
<p>
|
|
<i>Effects:</i> Constructs a <code>zoned_time</code> <code>zt</code> such that
|
|
<code>zt.get_time_zone()-> == z</code>, and
|
|
<code>zt.get_sys_time() == z->to_sys(tp, c)</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const std::string& name, local_time<Duration> tp, choose c);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Equivalent to construction with <code>{locate_zone(name), tp, c}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const time_zone* z, const zoned_time<Duration>& y);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Requires:</i> <code>z</code> refers to a valid <code>time_zone</code>.
|
|
</p>
|
|
<p>
|
|
<i>Effects:</i> Constructs a <code>zoned_time</code> <code>zt</code> such that
|
|
<code>zt.get_time_zone()-> == z</code>, and
|
|
<code>zt.get_sys_time() == y.get_sys_time()</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const std::string& name, const zoned_time<Duration>& y);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Equivalent to construction with <code>{locate_zone(name), y}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const time_zone* z, const zoned_time<Duration>& y, choose);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Requires:</i> <code>z</code> refers to a valid <code>time_zone</code>.
|
|
</p>
|
|
<p>
|
|
<i>Effects:</i> Constructs a <code>zoned_time</code> <code>zt</code> such that
|
|
<code>zt.get_time_zone()-> == z</code>, and
|
|
<code>zt.get_sys_time() == y.get_sys_time()</code>.
|
|
</p>
|
|
<p>
|
|
<i>Note:</i> The <code>choose</code> parameter is allowed here, but has no impact.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const std::string& name, const zoned_time<Duration>& y, choose);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Equivalent to construction with <code>{locate_zone(name), y}</code>.
|
|
</p>
|
|
<p>
|
|
<i>Note:</i> The <code>choose</code> parameter is allowed here, but has no impact.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const time_zone* z, const sys_time<Duration>& st);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Requires:</i> <code>z</code> refers to a valid <code>time_zone</code>.
|
|
</p>
|
|
<p>
|
|
<i>Effects:</i> Constructs a <code>zoned_time</code> <code>zt</code> such that
|
|
<code>zt.get_time_zone()-> == z</code>, and <code>zt.get_sys_time() == st</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::zoned_time(const std::string& name, const sys_time<Duration>& st);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Equivalent to construction with <code>{locate_zone(name), st}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>& zoned_time<Duration>::operator=(sys_time<Duration> st);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> After assignment <code>get_sys_time() == st</code>. This assignment has
|
|
no effect on the return value of <code>get_time_zone()</code>.
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> <code>*this</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>& zoned_time<Duration>::operator=(local_time<Duration> lt);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> After assignment <code>get_local_time() == lt</code>. This assignment has
|
|
no effect on the return value of <code>get_time_zone()</code>.
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> <code>*this</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
zoned_time<Duration>::operator sys_time<Duration>() const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>get_sys_time()</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
explicit zoned_time<Duration>::operator local_time<Duration>() const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>get_local_time()</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
const time_zone* zoned_time<Duration>::get_time_zone() const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>zone_</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
local_time<Duration> zoned_time<Duration>::get_local_time() const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>zone_->to_local(tp_)</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
sys_time<Duration> zoned_time<Duration>::get_sys_time() const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>tp_</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
sys_info zoned_time<Duration>::get_info() const;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>zone_->get_info(tp_)</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration1, class Duration2>
|
|
bool
|
|
operator==(const zoned_time<Duration1>& x, const zoned_time<Duration2>& y);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>x.zone_ == y.zone_ && x.tp_ == y.tp_</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration1, class Duration2>
|
|
bool
|
|
operator!=(const zoned_time<Duration1>& x, const zoned_time<Duration2>& y);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>!(x == y)</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_ostream<class CharT, class Traits>&
|
|
operator<<(std::basic_ostream<class CharT, class Traits>& os, const zoned_time<Duration>& t)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Streams <code>t</code> to <code>os</code> using the format "%F %T %Z"
|
|
and the value returned from <code>t.get_local_time()</code>.
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> <code>os</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
</blockquote>
|
|
|
|
<a name="make_zoned"></a><h3><code>make_zoned</code></h3>
|
|
|
|
<blockquote>
|
|
<p>
|
|
There exist several overloaded functions named <code>make_zoned</code>
|
|
which serve as factory functions for <code>zoned_time<Duration></code> and
|
|
will deduce the correct <code>Duration</code> from the argument list. In every
|
|
case the correct return type is
|
|
<code>zoned_time<std::common_type_t<Duration, std::chrono::seconds>></code>.
|
|
</p>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(sys_time<Duration> tp)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{tp}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(const time_zone* zone, local_time<Duration> tp)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{zone, tp}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(const std::string& name, local_time<Duration> tp)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{name, tp}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(const time_zone* zone, local_time<Duration> tp, choose c)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{zone, tp, c}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(const std::string& name, local_time<Duration> tp, choose c)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{name, tp, c}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(const time_zone* zone, const zoned_time<Duration>& zt)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{zone, zt}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(const std::string& name, const zoned_time<Duration>& zt)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{name, zt}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(const time_zone* zone, const zoned_time<Duration>& zt, choose c)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{zone, zt, c}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(const std::string& name, const zoned_time<Duration>& zt, choose c)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{name, zt, c}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(const time_zone* zone, const sys_time<Duration>& st)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{zone, st}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
zoned_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
make_zoned(const std::string& name, const sys_time<Duration>& st)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>{name, st}</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
</blockquote>
|
|
|
|
<a name="format"></a><h3><code>format</code></h3>
|
|
<blockquote>
|
|
<pre>
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_string<class CharT, class Traits>
|
|
format(const std::locale& loc, std::basic_string<class CharT, class Traits> format,
|
|
const local_time<Duration>& tp);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_string<class CharT, class Traits>
|
|
format(std::basic_string<class CharT, class Traits> format, const local_time<Duration>& tp);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_string<class CharT, class Traits>
|
|
format(const std::locale& loc, std::basic_string<class CharT, class Traits> format,
|
|
const zoned_time<Duration>& tp);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_string<class CharT, class Traits>
|
|
format(std::basic_string<class CharT, class Traits> format, const zoned_time<Duration>& tp);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_string<class CharT, class Traits>
|
|
format(const std::locale& loc, std::basic_string<class CharT, class Traits> format,
|
|
const sys_time<Duration>& tp);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_string<class CharT, class Traits>
|
|
format(std::basic_string<class CharT, class Traits> format, const sys_time<Duration>& tp);
|
|
|
|
// const CharT* formats
|
|
|
|
template <class CharT, class Duration>
|
|
std::basic_string<class CharT>
|
|
format(const std::locale& loc, const CharT* format, const local_time<Duration>& tp);
|
|
|
|
template <class CharT, class Duration>
|
|
std::basic_string<class CharT>
|
|
format(const CharT* format, const local_time<Duration>& tp);
|
|
|
|
template <class CharT, class Duration>
|
|
std::basic_string<class CharT>
|
|
format(const std::locale& loc, const CharT* format, const zoned_time<Duration>& tp);
|
|
|
|
template <class CharT, class Duration>
|
|
std::basic_string<class CharT>
|
|
format(const CharT* format, const zoned_time<Duration>& tp);
|
|
|
|
template <class CharT, class Duration>
|
|
std::basic_string<class CharT>
|
|
format(const std::locale& loc, const CharT* format, const sys_time<Duration>& tp);
|
|
|
|
template <class CharT, class Duration>
|
|
std::basic_string<class CharT>
|
|
format(const CharT* format, const sys_time<Duration>& tp);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> These functions create a formatted time stamp using the
|
|
arguments, returning the result in a <code>std::string</code>.
|
|
</p>
|
|
<blockquote>
|
|
<p>
|
|
If a <code>locale</code> is passed in, then that <code>locale</code> is used for
|
|
any formatting that requires a <code>locale</code>. If no <code>locale</code>
|
|
is passed in, then if a <code>locale</code> is required for formatting, a
|
|
default constructed <code>locale</code> will be used (which makes a copy of the
|
|
global <code>locale</code>).
|
|
</p>
|
|
<p>
|
|
The <code>format</code> string follows the rules as specified for
|
|
<code>std::time_put</code> with the following exceptions:
|
|
</p>
|
|
<ul>
|
|
<li><p>
|
|
If <code>%S</code> or <code>%T</code> appears in the <code>format</code> string
|
|
and the argument <code>tp</code> 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 of <code>tp</code>. The character for
|
|
the decimal point is localized according to the <code>locale</code>.
|
|
</p></li>
|
|
|
|
<li><p>
|
|
If <code>%z</code> appears in the format, the behavior depends on the type of
|
|
<code>tp</code>:
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
<code>local_time</code>: An exception of type <code>std::runtime_error</code> is thrown.
|
|
</li>
|
|
<li>
|
|
<code>zoned_time</code>: The offset associated with <code>tp.get_time_zone()</code> is
|
|
used.
|
|
</li>
|
|
<li>
|
|
<code>sys_time</code>: <code>"+0000"</code> is used.
|
|
</li>
|
|
</ul>
|
|
<p>
|
|
If <code>%z</code> is modified by either <code>E</code> or <code>O</code>
|
|
(that is, <code>%Ez</code> or <code>%Oz</code>), then a colon is inserted
|
|
between the hours and minutes: <code>+00:00</code>.
|
|
</p>
|
|
</li>
|
|
|
|
<li><p>
|
|
If <code>%Z</code> appears in the format, the behavior depends on the type of
|
|
<code>tp</code>:
|
|
</p>
|
|
<ul>
|
|
<li>
|
|
<code>local_time</code>: An exception of type <code>std::runtime_error</code> is thrown.
|
|
</li>
|
|
<li>
|
|
<code>zoned_time</code>: The abbreviation associated with
|
|
<code>tp.get_time_zone()</code> is used.
|
|
</li>
|
|
<li>
|
|
<code>sys_time</code>: <code>"UTC"</code> is used.
|
|
</li>
|
|
</ul>
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
<p>
|
|
For the overloads taking a <code>zoned_time</code> it is the value returned by
|
|
<code>tz.get_local_time()</code> that is formatted.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<p>
|
|
<i>Returns:</i> The formatted string.
|
|
</p>
|
|
|
|
</blockquote>
|
|
</blockquote>
|
|
|
|
<a name="parse"></a><h3><code>parse</code></h3>
|
|
<blockquote>
|
|
<p>
|
|
One can parse in a <code>sys_time<Duration></code> or a
|
|
<code>local_time<Duration></code>. Optionally, one can also pass in a reference
|
|
to a <code>std::string</code> in order to capture the time zone abbreviation, or one
|
|
can pass in a reference to a <code>std::chrono::minutes</code> to capture a time zone
|
|
UTC offset (formatted as <code>+0000</code>), or one can pass in both in either order.
|
|
</p>
|
|
|
|
<pre>
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is,
|
|
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is,
|
|
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
|
|
std::basic_string<CharT, Traits>& abbrev);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is,
|
|
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
|
|
std::chrono::minutes& offset);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is,
|
|
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
|
|
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is,
|
|
const std::basic_string<CharT, Traits>& format, sys_time<Duration>& tp,
|
|
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is,
|
|
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is,
|
|
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
|
|
std::basic_string<CharT, Traits>& abbrev);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is,
|
|
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
|
|
std::chrono::minutes& offset);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is,
|
|
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
|
|
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is,
|
|
const std::basic_string<CharT, Traits>& format, local_time<Duration>& tp,
|
|
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev);
|
|
|
|
// const CharT* formats
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
|
|
std::basic_string<CharT, Traits>& abbrev);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
|
|
std::chrono::minutes& offset);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
|
|
std::basic_string<CharT, Traits>& abbrev, std::chrono::minutes& offset);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is, const CharT* format, sys_time<Duration>& tp,
|
|
std::chrono::minutes& offset, std::basic_string<CharT, Traits>& abbrev);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
|
|
local_time<Duration>& tp);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
|
|
local_time<Duration>& tp, std::basic_string<CharT, Traits>& abbrev);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
|
|
local_time<Duration>& tp, std::chrono::minutes& offset);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
|
|
local_time<Duration>& tp, std::basic_string<CharT, Traits>& abbrev,
|
|
std::chrono::minutes& offset);
|
|
|
|
template <class CharT, class Traits, class Duration>
|
|
void
|
|
parse(std::basic_istream<CharT, Traits>& is, const CharT* format,
|
|
local_time<Duration>& tp, std::chrono::minutes& offset,
|
|
std::basic_string<CharT, Traits>& abbrev);
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> These functions attempt to parse a <code>time_point</code> out of
|
|
<code>is</code> according to <code>format</code>. If the parse is unsuccessful,
|
|
calls <code>is.setstate(std::ios::failbit)</code> which may throw an exception.
|
|
<code>tp</code>, <code>abbrev</code>, and <code>offset</code> are altered only in
|
|
the event of a successful parse.
|
|
</p>
|
|
<blockquote>
|
|
<p>
|
|
The <code>format</code> string follows the rules as specified for <code>std::time_get</code>
|
|
with the following exceptions:
|
|
</p>
|
|
<ul>
|
|
<li><p>
|
|
If <code>%F</code> appears in the <code>format</code> string it is interpreted as
|
|
<code>%Y-%m-%d</code>.
|
|
</p></li>
|
|
|
|
<li><p>
|
|
If <code>%S</code> or <code>%T</code> appears in the <code>format</code> string
|
|
and the argument <code>tp</code> has precision finer than seconds, then the
|
|
seconds are parsed as a <code>double</code>, and if that parse is successful
|
|
contributes to the time stamp as if
|
|
<code>round<Duration>(duration<double>{s})</code> where
|
|
<code>s</code> is a local variable holding the parsed <code>double</code>.
|
|
</p></li>
|
|
|
|
<li><p>
|
|
If <code>%z</code> appears in the <code>format</code> string and an offset is
|
|
successfully parsed, the overloads taking <code>sys_time</code> interprets the
|
|
parsed time as a local time and subtracts the offset prior to assigning the
|
|
value to <code>tp</code>, resulting in a value of <code>tp</code> representing a
|
|
UTC timestamp. The overloads taking <code>local_time</code> require a valid
|
|
parse of the offset, but then ignore the offset in assigning a value to the
|
|
<code>local_time<Duration>& tp</code>. If <code>offset</code> is
|
|
passed in, on successful parse it will hold the value represented by
|
|
<code>%z</code> if present, or will be assigned <code>0min</code> if
|
|
<code>%z</code> is not present.
|
|
</p>
|
|
<p>
|
|
The format of the offset is <code>+/-hhmm</code>. The leading plus or minus
|
|
sign is required. If the format string was modified (i.e. <code>%Ez</code>
|
|
or <code>%Oz</code>), a colon is required between hours and minutes, and the leading
|
|
hours digit is optional:
|
|
<code>+/-[h]h:mm</code>.
|
|
</p>
|
|
</li>
|
|
|
|
<li><p>
|
|
If <code>%Z</code> appears in the <code>format</code> string then an
|
|
abbreviation is required in that position for a successful parse. The
|
|
abbreviation will be parsed as a <code>std::string</code> (delimited by white
|
|
space). The parsed abbreviation does not have to be a valid time zone
|
|
abbreviation, and has no impact on the value parsed into <code>tp</code>. Using
|
|
the overloads that take a <code>std::string&</code> one can discover what
|
|
that parsed abbreviation is. On successful parse, <code>abbrev</code> will be
|
|
assigned the value represented by <code>%Z</code> if present, or assigned the
|
|
empty string if <code>%Z</code> is not present.
|
|
</p></li>
|
|
</ul>
|
|
</blockquote>
|
|
<p>
|
|
<i>Note:</i> There is no unique mapping from a time zone abbreviation to a
|
|
<code>time_zone</code>. But given a time zone abbreviation and a <code>sys_time</code>
|
|
or <code>local_time</code>, one could make a list of potential <code>time_zone</code>s.
|
|
Given a UTC offset, one might even narrow that list down further.
|
|
</p>
|
|
</blockquote>
|
|
<p>Furthermore, for every signature
|
|
<code>parse(std::basic_istream<CharT, Traits>& is, Args...)</code> there exists
|
|
an input manipulator <code>parse(Args...)</code> that can be used like this:
|
|
</p>
|
|
<pre>
|
|
istream >> parse("%F %T", tp);
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<a name="utc_clock"></a><h3><code>utc_clock</code></h3>
|
|
<blockquote>
|
|
<pre>
|
|
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 = false;
|
|
|
|
static time_point now() noexcept;
|
|
};
|
|
|
|
template <class Duration>
|
|
using utc_time = std::chrono::time_point<utc_clock, Duration>;
|
|
|
|
using utc_seconds = utc_time<std::chrono::seconds>;
|
|
</pre>
|
|
|
|
<p>
|
|
In contrast to <code>sys_time</code> which does not take leap seconds into
|
|
account, <code>utc_clock</code> and its associated <code>time_point</code>,
|
|
<code>utc_time</code>, counts time, <i>including</i> leap seconds, since
|
|
1970-01-01 00:00:00 UTC. It also provides functions for converting between
|
|
<code>utc_time</code> and <code>sys_time</code>. These functions consult
|
|
<code>get_tzdb().leaps</code> to decide how many seconds to add/subtract
|
|
in performing those conversions.
|
|
</p>
|
|
|
|
<pre>
|
|
static utc_clock::time_point utc_clock::now() noexcept;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>to_utc_time(system_clock::now())</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
sys_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
to_sys_time(utc_time<Duration> u)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> A <code>sys_time</code> <code>t</code>, such that
|
|
<code>to_utc_time(t) == u</code> if such a mapping exists. Otherwise <code>u</code>
|
|
represents a <code>time_point</code> during a leap second insertion and the last
|
|
representable value of <code>sys_time</code> prior to the insertion of the leap
|
|
second is returned.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
utc_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
to_utc_time(sys_time<Duration> t)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> A <code>utc_time</code> <code>u</code>, such that
|
|
<code>u.time_since_epoch() - t.time_since_epoch()</code> is equal to the number
|
|
of leap seconds that were inserted between <code>t</code> and 1970-01-01. If
|
|
<code>t</code> is ambiguous on this issue (i.e. corresponds to the date of leap
|
|
second insertion), then the conversion counts that leap second as inserted.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
utc_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
to_utc_time(tai_time<Duration> t) noexcept
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>utc_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} - 378691210s</code>
|
|
</p>
|
|
<p>
|
|
<i>Note:</i> <code>378691210s == sys_days{1970y/jan/1} - sys_days{1958y/jan/1} + 10s</code>
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
utc_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
to_utc_time(gps_time<Duration> t) noexcept
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>utc_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} + 315964809s</code>
|
|
</p>
|
|
<p>
|
|
<i>Note:</i> <code>315964809s == sys_days{1980y/jan/sun[1]} - sys_days{1970y/jan/1} + 9s</code>
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_ostream<class CharT, class Traits>&
|
|
operator<<(std::basic_ostream<class CharT, class Traits>& os, const utc_time<Duration>& t)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Streams <code>t</code> to <code>os</code> using the format "%F %T". This
|
|
differs from streaming <code>sys_time</code> only by the use of <code>60</code> for the
|
|
seconds specifier when the value represents an inserted leap second.
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> <code>os</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
</blockquote>
|
|
|
|
<a name="tai_clock"></a><h3><code>tai_clock</code></h3>
|
|
<blockquote>
|
|
<pre>
|
|
class tai_clock
|
|
{
|
|
public:
|
|
using duration = std::chrono::system_clock::duration;
|
|
using rep = duration::rep;
|
|
using period = duration::period;
|
|
using time_point = std::chrono::time_point<tai_clock>;
|
|
static constexpr bool is_steady = false;
|
|
|
|
static time_point now() noexcept;
|
|
};
|
|
|
|
template <class Duration>
|
|
using tai_time = std::chrono::time_point<tai_clock, Duration>;
|
|
|
|
using tai_seconds = tai_time<std::chrono::seconds>;
|
|
</pre>
|
|
|
|
<p>
|
|
<code>tai_time</code> counts physical seconds continuously like <code>utc_itme</code>,
|
|
but when printed out, <i>always</i> has 60 seconds per minute. It's epoch
|
|
is 1958-01-01 and is offset ahead of <code>utc_time</code> by 10s in 1970-01-01.
|
|
With each leap second, the offset from <code>utc_time</code> grows by another
|
|
second.
|
|
</p>
|
|
|
|
<pre>
|
|
static tai_clock::time_point tai_clock::now() noexcept;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>to_tai_time(system_clock::now())</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
to_sys_time(tai_time<Duration> t)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Equivalent to:</i> <code>return to_sys_time(to_utc_time(t))</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
tai_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
to_tai_time(sys_time<Duration> t)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Equivalent to:</i> <code>return to_tai_time(to_utc_time(t))</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
tai_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
to_tai_time(utc_time<Duration> u) noexcept
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>tai_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} + 378691210s</code>
|
|
</p>
|
|
<p>
|
|
<i>Note:</i> <code>378691210s == sys_days{1970y/jan/1} - sys_days{1958y/jan/1} + 10s</code>
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
tai_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
to_tai_time(gps_time<Duration> t) noexcept
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>tai_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} + 694656019s</code>
|
|
</p>
|
|
<p>
|
|
<i>Note:</i> <code>694656019s == sys_days{1980y/jan/sun[1]} - sys_days{1958y/jan/1} + 19s</code>
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_ostream<class CharT, class Traits>&
|
|
operator<<(std::basic_ostream<class CharT, class Traits>& os, const tai_time<Duration>& t)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Creates a <code>sys_time</code> from <code>t</code> as if by:
|
|
</p>
|
|
<blockquote><pre>
|
|
auto tp = sys_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} -
|
|
(sys_days{1970_y/jan/1} - sys_days{1958_y/jan/1});
|
|
</pre></blockquote>
|
|
<p>
|
|
And then streams that <code>sys_time</code>: <code>os << tp</code>.
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> <code>os</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
</blockquote>
|
|
|
|
<a name="gps_clock"></a><h3><code>gps_clock</code></h3>
|
|
<blockquote>
|
|
<pre>
|
|
class gps_clock
|
|
{
|
|
public:
|
|
using duration = std::chrono::system_clock::duration;
|
|
using rep = duration::rep;
|
|
using period = duration::period;
|
|
using time_point = std::chrono::time_point<gps_clock>;
|
|
static constexpr bool is_steady = false;
|
|
|
|
static time_point now() noexcept;
|
|
};
|
|
|
|
template <class Duration>
|
|
using gps_time = std::chrono::time_point<gps_clock, Duration>;
|
|
|
|
using gps_seconds = gps_time<std::chrono::seconds>;
|
|
</pre>
|
|
|
|
<p>
|
|
<code>gps_time</code> counts physical seconds continuously like <code>utc_itme</code>,
|
|
but when printed out, <i>always</i> has 60 seconds per minute. It's epoch
|
|
is 1980-01-06 and was equivalent to UTC at that time. If drifts ahead of UTC
|
|
with each inserted leap second. It is always exactly 19s behind TAI.
|
|
</p>
|
|
|
|
<pre>
|
|
static gps_clock::time_point gps_clock::now() noexcept;
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>to_gps_time(system_clock::now())</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
sys_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
to_sys_time(gps_time<Duration> t)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Equivalent to:</i> <code>return to_sys_time(to_utc_time(t))</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
gps_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
to_gps_time(sys_time<Duration> t)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Equivalent to:</i> <code>return to_gps_time(to_utc_time(t))</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
gps_time<std::common_type_t<Duration, std::chrono::seconds>>
|
|
to_gps_time(utc_time<Duration> u) noexcept
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>gps_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} - 315964809s</code>
|
|
</p>
|
|
<p>
|
|
<i>Note:</i> <code>315964809s == sys_days{1980y/jan/sun[1]} - sys_days{1970y/jan/1} + 9s</code>
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class Duration>
|
|
gps_time<typename std::common_type<Duration, std::chrono::seconds>::type>
|
|
to_gps_time(tai_time<Duration> t) noexcept
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Returns:</i> <code>gps_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} - 694656019s</code>
|
|
</p>
|
|
<p>
|
|
<i>Note:</i> <code>694656019s == sys_days{1980y/jan/sun[1]} - sys_days{1958y/jan/1} + 19s</code>
|
|
</p>
|
|
</blockquote>
|
|
|
|
<pre>
|
|
template <class CharT, class Traits, class Duration>
|
|
std::basic_ostream<class CharT, class Traits>&
|
|
operator<<(std::basic_ostream<class CharT, class Traits>& os, const gps_time<Duration>& t)
|
|
</pre>
|
|
<blockquote>
|
|
<p>
|
|
<i>Effects:</i> Creates a <code>sys_time</code> from <code>t</code> as if by:
|
|
</p>
|
|
<blockquote><pre>
|
|
auto tp = sys_time<common_type_t<Duration, seconds>>{t.time_since_epoch()} +
|
|
(sys_days{1980y/jan/sun[1]} - sys_days{1970y/jan/1});
|
|
</pre></blockquote>
|
|
<p>
|
|
And then streams that <code>sys_time</code>: <code>os << tp</code>.
|
|
</p>
|
|
<p>
|
|
<i>Returns:</i> <code>os</code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<p>
|
|
[<i>Example:</i>
|
|
</p>
|
|
|
|
<p>
|
|
The following code prints out equivalent time stamps to millisecond precision for
|
|
times near the 2015-06-30 leap second insertion. Note that the mapping to
|
|
<code>sys_time</code> during the leap second collapses down to the last instant
|
|
prior to the leap second. But the maping between UTC, TAI and GPS is all one-to-one.
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
#include "tz.h"
|
|
#include <iostream>
|
|
|
|
int
|
|
main()
|
|
{
|
|
using namespace date;
|
|
using namespace std::chrono;
|
|
auto start = to_utc_time(sys_days{2015_y/jul/1} - 500ms);
|
|
auto end = start + 2s;
|
|
for (auto utc = start; utc < end; utc += 100ms)
|
|
{
|
|
auto sys = to_sys_time(utc);
|
|
auto tai = to_tai_time(utc);
|
|
auto gps = to_gps_time(utc);
|
|
std::cout << sys << " SYS == "
|
|
<< utc << " UTC == "
|
|
<< tai << " TAI == "
|
|
<< gps << " GPS\n";
|
|
}
|
|
}
|
|
</pre>
|
|
<p>
|
|
Output:
|
|
</p>
|
|
<pre>
|
|
2015-06-30 23:59:59.500 SYS == 2015-06-30 23:59:59.500 UTC == 2015-07-01 00:00:34.500 TAI == 2015-07-01 00:00:15.500 GPS
|
|
2015-06-30 23:59:59.600 SYS == 2015-06-30 23:59:59.600 UTC == 2015-07-01 00:00:34.600 TAI == 2015-07-01 00:00:15.600 GPS
|
|
2015-06-30 23:59:59.700 SYS == 2015-06-30 23:59:59.700 UTC == 2015-07-01 00:00:34.700 TAI == 2015-07-01 00:00:15.700 GPS
|
|
2015-06-30 23:59:59.800 SYS == 2015-06-30 23:59:59.800 UTC == 2015-07-01 00:00:34.800 TAI == 2015-07-01 00:00:15.800 GPS
|
|
2015-06-30 23:59:59.900 SYS == 2015-06-30 23:59:59.900 UTC == 2015-07-01 00:00:34.900 TAI == 2015-07-01 00:00:15.900 GPS
|
|
2015-06-30 23:59:<b>59.999</b> SYS == 2015-06-30 23:59:<b>60.000</b> UTC == 2015-07-01 00:00:35.000 TAI == 2015-07-01 00:00:16.000 GPS
|
|
2015-06-30 23:59:<b>59.999</b> SYS == 2015-06-30 23:59:<b>60.100</b> UTC == 2015-07-01 00:00:35.100 TAI == 2015-07-01 00:00:16.100 GPS
|
|
2015-06-30 23:59:<b>59.999</b> SYS == 2015-06-30 23:59:<b>60.200</b> UTC == 2015-07-01 00:00:35.200 TAI == 2015-07-01 00:00:16.200 GPS
|
|
2015-06-30 23:59:<b>59.999</b> SYS == 2015-06-30 23:59:<b>60.300</b> UTC == 2015-07-01 00:00:35.300 TAI == 2015-07-01 00:00:16.300 GPS
|
|
2015-06-30 23:59:<b>59.999</b> SYS == 2015-06-30 23:59:<b>60.400</b> UTC == 2015-07-01 00:00:35.400 TAI == 2015-07-01 00:00:16.400 GPS
|
|
2015-06-30 23:59:<b>59.999</b> SYS == 2015-06-30 23:59:<b>60.500</b> UTC == 2015-07-01 00:00:35.500 TAI == 2015-07-01 00:00:16.500 GPS
|
|
2015-06-30 23:59:<b>59.999</b> SYS == 2015-06-30 23:59:<b>60.600</b> UTC == 2015-07-01 00:00:35.600 TAI == 2015-07-01 00:00:16.600 GPS
|
|
2015-06-30 23:59:<b>59.999</b> SYS == 2015-06-30 23:59:<b>60.700</b> UTC == 2015-07-01 00:00:35.700 TAI == 2015-07-01 00:00:16.700 GPS
|
|
2015-06-30 23:59:<b>59.999</b> SYS == 2015-06-30 23:59:<b>60.800</b> UTC == 2015-07-01 00:00:35.800 TAI == 2015-07-01 00:00:16.800 GPS
|
|
2015-06-30 23:59:<b>59.999</b> SYS == 2015-06-30 23:59:<b>60.900</b> UTC == 2015-07-01 00:00:35.900 TAI == 2015-07-01 00:00:16.900 GPS
|
|
2015-07-01 00:00:00.000 SYS == 2015-07-01 00:00:00.000 UTC == 2015-07-01 00:00:36.000 TAI == 2015-07-01 00:00:17.000 GPS
|
|
2015-07-01 00:00:00.100 SYS == 2015-07-01 00:00:00.100 UTC == 2015-07-01 00:00:36.100 TAI == 2015-07-01 00:00:17.100 GPS
|
|
2015-07-01 00:00:00.200 SYS == 2015-07-01 00:00:00.200 UTC == 2015-07-01 00:00:36.200 TAI == 2015-07-01 00:00:17.200 GPS
|
|
2015-07-01 00:00:00.300 SYS == 2015-07-01 00:00:00.300 UTC == 2015-07-01 00:00:36.300 TAI == 2015-07-01 00:00:17.300 GPS
|
|
2015-07-01 00:00:00.400 SYS == 2015-07-01 00:00:00.400 UTC == 2015-07-01 00:00:36.400 TAI == 2015-07-01 00:00:17.400 GPS
|
|
</pre>
|
|
</blockquote>
|
|
|
|
<p>
|
|
<i>— end example</i>]
|
|
</p>
|
|
|
|
</blockquote>
|
|
<a name="leap"></a><h3><code>leap</code></h3>
|
|
<blockquote>
|
|
<pre>
|
|
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);
|
|
</pre>
|
|
|
|
<p>
|
|
<code>leap</code> is a copyable class that is constructed and stored in the time zone
|
|
database when initialized. You can explicitly convert it to a <code>sys_seconds</code>
|
|
with the member function <code>date()</code> and that will be the date of the leap second
|
|
insertion. <code>leap</code> is equality and less-than comparable, both with itself, and
|
|
with <code>sys_time<Duration></code>.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<a name="link"></a><h3><code>link</code></h3>
|
|
<blockquote>
|
|
<pre>
|
|
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);
|
|
</pre>
|
|
<p>
|
|
A <code>link</code> is an alternative name for a <code>time_zone</code>. The alternative
|
|
name is <code>name()</code>. The name of the <code>time_zone</code> for which this is
|
|
an alternative name is <code>target()</code>. <code>link</code>s will be constructed
|
|
for you when the time zone database is initialized.
|
|
</p>
|
|
</blockquote>
|
|
|
|
<a name="Installation"></a><h2>Installation</h2>
|
|
|
|
<p>
|
|
You will need the following four source files:
|
|
<a href="https://github.com/HowardHinnant/date/blob/master/tz.h"><code>date.h</code></a>,
|
|
<a href="https://github.com/HowardHinnant/date/blob/master/tz.h"><code>tz.h</code></a>,
|
|
<a href="https://github.com/HowardHinnant/date/blob/master/tz_private.h"><code>tz_private.h</code></a> and
|
|
<a href="https://github.com/HowardHinnant/date/blob/master/tz.cpp"><code>tz.cpp</code></a>.
|
|
These sources are located at the github repository
|
|
<a href="https://github.com/HowardHinnant/date">https://github.com/HowardHinnant/date</a>.
|
|
</p>
|
|
|
|
<p>
|
|
Compile <a href="https://github.com/HowardHinnant/date/blob/master/tz.cpp"><code>tz.cpp</code></a>
|
|
along with your other sources while providing pointers to your compiler for the location
|
|
of the header files (i.e. <a href="https://github.com/HowardHinnant/date/blob/master/tz.h"><code>tz.h</code></a>).
|
|
</p>
|
|
|
|
<p>
|
|
You can also customize the build by defining macros (e.g. on the command line) as follows:
|
|
</p>
|
|
|
|
<blockquote>
|
|
<dl>
|
|
|
|
<dt><code>INSTALL</code></dt>
|
|
<dd>
|
|
<p>
|
|
This is the location of your uncompressed
|
|
<a href="http://www.iana.org/time-zones">IANA Time Zone Database -- tzdataYYYYv.tar.gz</a>
|
|
(or where you want the software to install it for you if you compile with
|
|
<code>AUTO_DOWNLOAD == 1</code>).
|
|
</p>
|
|
<p>
|
|
If specified, <code>"/tzdata"</code> will be appended to whatever you supply
|
|
(<code>"\tzdata"</code> on Windows).
|
|
</p>
|
|
<p>
|
|
<i>Default:</i> <code>"~/Downloads/tzdata"</code>
|
|
(<code>"%homedrive%\%homepath%\downloads\tzdata"</code> on Windows).
|
|
</p>
|
|
<p>
|
|
<i>Example:</i> Put the database in the current directory:
|
|
</p>
|
|
<blockquote><pre>
|
|
-DINSTALL=.
|
|
</pre></blockquote>
|
|
<p>
|
|
<i>Warning:</i> When coupled with <code>AUTO_DOWNLOAD=1</CODE>, this <i>will</i> overwrite
|
|
everthing at <code>INSTALL/tzdata</code> if it already exists. Set with care.
|
|
</p>
|
|
</dd>
|
|
|
|
<dt><code>HAS_REMOTE_API</code></dt>
|
|
<dd>
|
|
<p>
|
|
If <code>HAS_REMOTE_API</code> is 1 then the <a href="#database">remote API</a> exists,
|
|
else it doesn't:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
std::string remote_version();
|
|
bool remote_download(const std::string& version);
|
|
bool remote_install(const std::string& version);
|
|
</pre></blockquote>
|
|
|
|
<p>
|
|
The remote API requires linking against <code>libcurl</code>
|
|
(<a href="https://curl.haxx.se/libcurl">https://curl.haxx.se/libcurl</a>).
|
|
On macOS and Linux this is done with <code>-lcurl</code>.
|
|
<code>libcurl</code> comes pre-installed on macOS and Linux, but not on Windows.
|
|
However one can download it for Windows.
|
|
</p>
|
|
<p>
|
|
<i>Default:</i> <code>1</code> on Linux and macOS, <code>0</code> on Windows.
|
|
</p>
|
|
<p>
|
|
<i>Example:</i> Disable the <a href="#database">remote API</a>:
|
|
</p>
|
|
<blockquote><pre>
|
|
-DHAS_REMOTE_API=0
|
|
</pre></blockquote>
|
|
</dd>
|
|
|
|
<dt><code>AUTO_DOWNLOAD</code></dt>
|
|
<dd>
|
|
<p>
|
|
If <code>AUTO_DOWNLOAD</code> is <code>1</code> 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.
|
|
</p>
|
|
<p>
|
|
If <code>AUTO_DOWNLOAD</code> is not enabled, you are responsible for keeping your
|
|
<a href="http://www.iana.org/time-zones">IANA Time Zone Database</a> 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.
|
|
</p>
|
|
|
|
<p>
|
|
If <code>AUTO_DOWNLOAD</code> is <code>1</code> then <code>HAS_REMOTE_API</code>
|
|
must be <code>1</code>, else a compile-time error will be emitted.
|
|
</p>
|
|
<p>
|
|
<i>Default:</i> Equal to <code>HAS_REMOTE_API</code>.
|
|
</p>
|
|
<p>
|
|
<i>Example:</i> Disable automatic downloading of the timezone database:
|
|
</p>
|
|
<blockquote><pre>
|
|
-DAUTO_DOWNLOAD=0
|
|
</pre></blockquote>
|
|
<p>
|
|
<i>Warning:</i> This <i>will</i> overwrite everthing at <code>INSTALL/tzdata</code> if
|
|
it already exists.
|
|
</p>
|
|
</dd>
|
|
|
|
<dt><code>USE_SHELL_API</code></dt>
|
|
<dd>
|
|
<p>
|
|
If <code>USE_SHELL_API</code> is <code>1</code> then <code>std::system</code> is used
|
|
to execute commands for downloading the timezone database. This may be useful (for
|
|
example) if your <code>tar</code> utility is installed in some place other than
|
|
<code>/usr/bin/tar</code>.
|
|
</p>
|
|
<p>
|
|
If <code>USE_SHELL_API</code> is <code>0</code> then <code>fork</code> is used
|
|
to execute commands for downloading the timezone database (<code>CreateProcess</code>
|
|
on Windows).
|
|
</p>
|
|
<p>
|
|
<i>Default:</i> <code>1</code>.
|
|
</p>
|
|
<p>
|
|
<i>Example:</i> Enable the use of the shell API:
|
|
</p>
|
|
<blockquote><pre>
|
|
-DUSE_SHELL_API=1
|
|
</pre></blockquote>
|
|
</dd>
|
|
|
|
</dl>
|
|
</blockquote>
|
|
|
|
<p>
|
|
Example compile command I commonly use on macOS:
|
|
</p>
|
|
|
|
<blockquote><pre>
|
|
clang++ -std=c++14 test.cpp -I../date ../date/tz.cpp -O3 -lcurl
|
|
</pre></blockquote>
|
|
|
|
<h3>Windows specific:</h3>
|
|
|
|
<p>
|
|
If you want to enable <code>HAS_REMOTE_API</code> and/or <code>AUTO_DOWNLOAD</code> on
|
|
Windows you will have to manually install
|
|
<a href="https://curl.haxx.se/libcurl/">curl</a> and
|
|
<a href="http://www.7-zip.org/">7-zip</a> into their default locations.
|
|
</p>
|
|
|
|
<p>
|
|
If you do not enable <code>HAS_REMOTE_API</code>, you will need to also install
|
|
<a href="http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml">
|
|
http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml</a> into your
|
|
<code>install</code> location. This will be done for you if you have enabled
|
|
<code>HAS_REMOTE_API</code> and let <code>AUTO_DOWNLOAD</code> default to 1.
|
|
</p>
|
|
|
|
<p>
|
|
mingw users: <code>-lpthread</code> is required.
|
|
</p>
|
|
|
|
<h3>iOS specific:</h3>
|
|
|
|
<p>
|
|
In addition to four aforementioned source files you will need following files:
|
|
<a href="https://github.com/HowardHinnant/date/blob/master/ios.h"><code>ios.h</code></a>,
|
|
<a href="https://github.com/HowardHinnant/date/blob/master/ios.cpp"><code>ios.cpp</code></a>.
|
|
</p>
|
|
<p>
|
|
In Xcode in <i>[Your Target]->Build Settings->Other C Flags</i> set following flags: <code>-DHAS_REMOTE_API=0</code>, <code>-DUSE_SHELL_API</code>, <code>-x objective-c++</code>.
|
|
</p>
|
|
<p>
|
|
Also you have to add IANA database archive (<code>*.tar.gz</code>) manually to your project, automatic download for iOS is not supported, this archive will be unpacked automatically into subdirectory <i>Library/tzdata</i> of installed application.
|
|
</p>
|
|
|
|
<a name="Acknowledgements"></a><h2>Acknowledgements</h2>
|
|
|
|
<p>
|
|
A database parser is nothing without its database. I would like to thank the founding
|
|
contributor of the <a href="http://www.iana.org/time-zones">IANA Time Zone Database</a>
|
|
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.
|
|
</p>
|
|
<p>
|
|
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.
|
|
</p>
|
|
<p>
|
|
And I would also especially like to thank contributors to this library: gmcode,
|
|
Ivan Pizhenko, tomy2105 and Ville Voutilainen.
|
|
</p>
|
|
</body>
|
|
</html>
|