Files
date/tz.html
T

3540 lines
116 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-05-15<br/>
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/"> <img alt="Creative
Commons License" style="border-width:0"
src="http://i.creativecommons.org/l/by/4.0/80x15.png" /></a><br /> This work is licensed
under a <a rel="license" href="http://creativecommons.org/licenses/by/4.0/">Creative
Commons Attribution 4.0 International License</a>.
</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="#TheDatabase">The Database</a></li>
<li><a href="#remote">The remote API</a></li>
<li><a href="#Zone">Zone</a>
<ul>
<li><a href="#Infrastructure">Infrastructure</a></li>
<li><a href="#ZoneContinued">Zone continued</a></li>
</ul>
</li>
<li><a href="#flightexample1">Flight Example</a></li>
<li><a href="#utc_clock">utc_clock</a></li>
<li><a href="#flightexample2">Flight Example with leap seconds</a></li>
<li><a href="#Formatting">Formatting</a></li>
<li><a href="#Parsing">Parsing</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="#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>&lt;chrono&gt;</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>&lt;chrono&gt;</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>
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>
<h3>What is the current local time?</h3>
<p>
One of the first things people want to is find out what current local time it is.
Here is a complete program to print out the local time in human readable format:
</p>
<blockquote><pre>
#include "tz.h"
#include &lt;iostream&gt;
int
main()
{
using namespace date;
using namespace std::chrono;
auto local_time = make_zoned(current_zone(), system_clock::now());
std::cout &lt;&lt; local_time &lt;&lt; '\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>&lt;chrono&gt;</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>local_time</code> has microseconds precision as well.
</p></li>
<li><p>
The <code>local_time</code> is then 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&lt;milliseconds&gt;</code> in one place. This
makes <code>local_time</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 local_time = make_zoned(current_zone(), <b>floor&lt;milliseconds&gt;</b>(system_clock::now()));
std::cout &lt;&lt; local_time &lt;&lt; '\n'; // 2016-05-14 18:33:24.205 EDT
</pre></blockquote>
<p>
Seconds precision is just as easy:
</p>
<blockquote><pre>
auto local_time = make_zoned(current_zone(), <b>floor&lt;seconds&gt;</b>(system_clock::now()));
std::cout &lt;&lt; local_time &lt;&lt; '\n'; // 2016-05-14 18:33:24 EDT
</pre></blockquote>
<p>
The entire <code>strftime</code> / <code>time_put</code> formatting capability is
also at your fingertips (and at any precision):
</p>
<blockquote><pre>
auto local_time = make_zoned(current_zone(), system_clock::now());
std::cout &lt;&lt; <b>format("%a, %b %d, %Y at %I:%M %p %Z", local_time)</b> &lt;&lt; '\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 local_time = make_zoned(current_zone(), floor&lt;seconds&gt;(system_clock::now()));
std::cout &lt;&lt; format(<b>locale("de_DE")</b>, "%a, %b %d, %Y at %T %Z", local_time) &lt;&lt; '\n';
// Sa, Mai 14, 2016 at 18:33:24 EDT
</pre></blockquote>
<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 local_time = make_zoned(<b>zone</b>, floor&lt;seconds&gt;(system_clock::now()));
std::cout &lt;&lt; format(locale("de_DE"), "%a, %b %d, %Y at %T %Z", local_time) &lt;&lt; '\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 local_time = make_zoned(<b>"Europe/Berlin"</b>, floor&lt;seconds&gt;(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>
<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 &lt;iostream&gt;
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 &lt;&lt; "The New York meeting is " &lt;&lt; meet_nyc &lt;&lt; '\n';
std::cout &lt;&lt; "The London meeting is " &lt;&lt; meet_lon &lt;&lt; '\n';
std::cout &lt;&lt; "The Sydney meeting is " &lt;&lt; meet_syd &lt;&lt; '\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>
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="TheDatabase"></a><h3>The Database</h3>
<p>
The database is represented with the type <code>TZ_DB</code>:
</p>
<blockquote><pre>
struct TZ_DB
{
std::string version;
std::vector&lt;Zone&gt; zones;
std::vector&lt;Link&gt; links;
std::vector&lt;Leap&gt; leaps;
std::vector&lt;Rule&gt; rules;
};
</pre></blockquote>
<p>
This is a singleton class. You can get a <code>const TZ_DB&amp;</code> to the singleton
using this function:
</p>
<blockquote><pre>
const TZ_DB&amp; get_tzdb();
</pre></blockquote>
<p>
The first call to <code>get_tzdb()</code> will initialize the database from your local
copy of the <a href="http://www.iana.org/time-zones">IANA Time Zone Database</a> located
at <code>install</code> (a file-scope variable of type <code>std::string</code> in
<a href="https://github.com/HowardHinnant/date/blob/master/tz.cpp"><code>tz.cpp</code></a>).
You will need to catch the return of this function by <code>const&amp;</code> as the
<code>TZ_DB</code> is not constructible from a <code>const TZ_DB</code>. This can be done
with the following example code:
</p>
<blockquote><pre>
auto& db = get_tzdb();
</pre></blockquote>
<p>
With a reference to the database in hand, you have read-only access to the entire
database, which is nothing more than sorted <code>vector</code>s for the four types of
data contained in the database. With such a reference you could (for example) print the
names of all the Zones in the database:
</p>
<blockquote><pre>
for (auto&amp; z : db.zones)
std::cout &lt;&lt; z.name() &lt;&lt; '\n';
</pre></blockquote>
<p>
There are currently 377 zones in the database.
</p>
<p>
Or you could output the 89 <code>Link</code>s, including their <code>name()</code> and
<code>target()</code>:
</p>
<blockquote><pre>
for (auto&amp; link : db.links)
std::cout &lt;&lt; link &lt;&lt; '\n';
</pre></blockquote>
<p>
If you aren't happy with the format this outputs in, <code>Link</code> has public member
functions <code>name()</code> and <code>target()</code> so that you can achieve whatever
format you desire.
</p>
<p>
If needed, <code>db.version</code> is a <code>std::string</code> containing the
<a href="http://www.iana.org/time-zones">IANA Time Zone Database</a> version of the
database you are reading. For example the current version when this sentence
was written was "2016a".
</p>
<p>
You can even print the entire database out in a semi-human-readable format if desired:
</p>
<blockquote><pre>
std::cout &lt;&lt; db &lt;&lt; '\n';
</pre></blockquote>
<p>
If you constrain the geography or history of the database during installation, those
constraints will be reflected in these examples.
</p>
<p>
If you decide you need to reload the database say, because you want to install a new
version of the <a href="http://www.iana.org/time-zones">IANA Time Zone Database</a>
without stopping your program, you can use this function:
</p>
<blockquote><pre>
const TZ_DB&amp; reload_tzdb();
</pre></blockquote>
<p>
This re-initializes the database by reading from the <code>install</code> location you
customized on installation. The use of the <code>reload_tzdb</code> function is not
pain-free, and not for every application (not for most of them I'm guessing). For example
see the <b>Thread Safety</b> section for issues related to the use of these functions.
</p>
<a name="remote"></a><h3>The remote API</h3>
<p>
The remote API is enabled only if <code>HAS_REMOTE_API</code> is set to 1 during
compilation. See <a href="#Installation">Installation</a> for more details.
</p>
<blockquote><pre>
std::string remote_version();
</pre></blockquote>
<p>
This function will query the
<a href="http://www.iana.org/time-zones">IANA Time Zone Database website</a> for the
latest version number of the IANA database, and return it as a <code>std::string</code>.
If an internet connection can not be made, an empty <code>string</code> is returned.
This string can be compared against the version of your local copy of the database:
<code>get_tzdb().version</code>.
</p>
<blockquote><pre>
bool remote_download(const std::string&amp; version);
</pre></blockquote>
<p>
This function will attempt to download the database with the version <code>version</code>
from the <a href="http://www.iana.org/time-zones">IANA Time Zone Database website</a>.
If successful, <code>true</code> is returned and a file named
<code>version + ".tar.gz"</code> will be stored at the location <code>install</code>.
If not successful, <code>false</code> is returned.
</p>
<blockquote><pre>
bool remote_install(const std::string&amp; version);
</pre></blockquote>
<p>
This function will attempt to uncompress the tar file downloaded by
<code>remote_download(version)</code> and replace any existing database with
the result. It will then delete the tar file. If the tar file doesn't exist,
<code>remote_install</code> will do nothing. Returns <code>true</code> on
success, else returns <code>false</code>.
</p>
<a name="Zone"></a><h3>Zone</h3>
<p>
The <code>Zone</code> class is the most important type in this library. It provides the
main access to the functionality provided by this library. Each <code>Zone</code> is
named, represents a geographic area, and provides a mapping between UTC and the local
time, in both directions. This mapping from local time to UTC is in general not one to
one. The mapping, and even the specific rule, depends upon the input
<code>time_point</code>, which can represent either UTC or local time.
</p>
<p>
The detailed API of the <code>Zone</code> class depends upon a small amount of
infrastructure which is introduced first.
</p>
<a name="Infrastructure"></a><h4>Infrastructure</h4>
<blockquote><pre>
using second_point = std::chrono::time_point&lt;std::chrono::system_clock,
std::chrono::seconds&gt;;
</pre></blockquote>
<p>
<code>second_point</code> is a <code>std::chrono::time_point</code> based on
<code>system_clock</code> but with the precision of <code>seconds</code>. This library
will interoperate with <code>system_clock::time_point</code>s of <i>any</i> precision.
However the data in the database is largely based on <code>second_point</code>, and
some of the data which is presented, such as that in the <code>sys_info</code> class, uses
this type alias as a convenience, and to reduce verbosity. <code>second_point</code>
will implicitly convert to <code>system_clock::time_point</code>. And coarser
<code>time_point</code>s such as the <code>day_point</code> from the
<a href="date.html"><code>date</code></a> library will implicitly convert to
<code>second_point</code>.
</p>
<blockquote><pre>
struct sys_info
{
second_point begin;
second_point end;
std::chrono::seconds offset;
std::chrono::minutes save;
std::string abbrev;
};
</pre></blockquote>
<p>
The <code>sys_info</code> struct is the return type of the <code>get_info</code> member
function of the <code>Zone</code> class. It contains very detailed information about the
<code>Zone</code> at the <code>time_point</code> (UTC or local) input into this member
function. <code>sys_info</code> contains no pointers or references into the database.
Therefore clients do not need to be concerned about holding on to <code>sys_info</code>s
during a call to <code>reload_tzdb()</code>. Though a call to <code>reload_tzdb()</code>
could potentially make the data in an outstanding <code>sys_info</code> obsolete. See
<code>Zone::get_info</code> for more details.
</p>
<blockquote><pre>
enum class tz {utc, local};
enum class choose {earliest, latest};
</pre></blockquote>
<p>
These <code>enum</code>s are used as input to some of the <code>Zone</code> member
functions. <code>tz::utc</code> indicates that a <code>time_point</code> represents a
time in the UTC time zone. <code>tz::local</code> indicates that a
<code>time_point</code> represents a time in the <code>Zone</code>'s local time zone.
The <code>choose enum</code> allows a client to specify how a mapping from local to UTC
should behave when the mapping is not one to one. Alternatively one can not specify
a policy in the mapping, and if the mapping is not unique, an exception will be thrown.
</p>
<blockquote><pre>
class nonexistent_local_time
: public std::runtime_error
{
public:
const char* what() const override;
};
class ambiguous_local_time
: public std::runtime_error
{
public:
const char* what() const override;
};
</pre></blockquote>
<p>
These are the exception classes thrown by the local to UTC mapping. In addition to their
type indicating the nature of the exceptional circumstance, they also sport a
<code>what()</code> member function that will contain a very detailed explanation
including specific times for the specific <code>time_point</code>s involved in the
attempted mapping.
</p>
<p>
If in a call to <code>Zone::to_sys</code> the local <code>time_point</code> falls into a
"gap" for which no local time exists, a <code>nonexistent_local_time</code> exception is
thrown.
</p>
<p>
If in a call to <code>Zone::to_sys</code> the local <code>time_point</code> has an
ambiguous mapping to UTC, a <code>ambiguous_local_time</code> exception is thrown.
</p>
<p>
Either exceptional situation can be circumvented with the use of
<code>choose::earliest</code> or <code>choose::latest</code> in the call to
<code>to_sys</code>.
</p>
<a name="ZoneContinued"></a><h4>Zone continued</h4>
<blockquote><pre>
class Zone
{
public:
const std::string&amp; name() const;
template &lt;class Rep, class Period&gt;
std::pair
&lt;
std::chrono::time_point&lt;std::chrono::system_clock,
typename std::common_type&lt;std::chrono::duration&lt;Rep, Period&gt;,
std::chrono::seconds&gt;::type&gt;,
std::string
&gt;
to_local(std::chrono::time_point&lt;std::chrono::system_clock,
std::chrono::duration&lt;Rep, Period&gt;&gt; tp) const;
template &lt;class Rep, class Period&gt;
std::chrono::time_point&lt;std::chrono::system_clock,
typename std::common_type&lt;std::chrono::duration&lt;Rep, Period&gt;,
std::chrono::seconds&gt;::type&gt;
to_sys(std::chrono::time_point&lt;std::chrono::system_clock,
std::chrono::duration&lt;Rep, Period&gt;&gt; tp) const;
template &lt;class Rep, class Period&gt;
std::chrono::time_point&lt;std::chrono::system_clock,
typename std::common_type&lt;std::chrono::duration&lt;Rep, Period&gt;,
std::chrono::seconds&gt;::type&gt;
to_sys(std::chrono::time_point&lt;std::chrono::system_clock,
std::chrono::duration&lt;Rep, Period&gt;&gt; tp,
choose z) const;
template &lt;class Rep, class Period&gt;
sys_info
get_info(std::chrono::time_point&lt;std::chrono::system_clock,
std::chrono::duration&lt;Rep, Period&gt;&gt; tp,
tz timezone) const;
};
const Zone* locate_zone(const std::string&amp; tz_name);
const Zone* current_zone();
bool operator==(const Zone&amp; x, const Zone&amp; y);
bool operator!=(const Zone&amp; x, const Zone&amp; y);
bool operator&lt; (const Zone&amp; x, const Zone&amp; y);
bool operator&gt; (const Zone&amp; x, const Zone&amp; y);
bool operator&lt;=(const Zone&amp; x, const Zone&amp; y);
bool operator&gt;=(const Zone&amp; x, const Zone&amp; y);
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, const Zone&amp; z);
</pre></blockquote>
<p>
The entire public API of the <code>Zone</code> is <code>const</code>. Once the database
is initialized (or reloaded), <code>Zone</code>s are set in concrete.
</p>
<hr>
<p>
The current time zone associated with your computer can be retrieved with the namespace
scope function <code>current_zone()</code>. For example:
</p>
<blockquote><pre>
std::cout &lt;&lt; current_zone()-&gt;name() &lt;&lt; '\n';
</pre></blockquote>
<p>
For me the above currently outputs <code>America/New_York</code>.
</p>
<hr>
<blockquote><pre>
const Zone* locate_zone(const std::string&amp; tz_name);
</pre></blockquote>
<p>
<code>locate_zone</code> returns a pointer to a <code>Zone</code> in the database
associated with <code>tz_name</code>. If it can't find a <code>Zone</code> named
<code>tz_name</code>, the implementation will search for a <code>Link</code> named
<code>tz_name</code>, and then return the <code>Zone</code> associated with the
<code>Link</code>'s <code>target()</code>. If <code>tz_name</code> can not be found in the
database, a <code>std::runtime_error</code> is thrown.
</p>
<p>
Example:
</p>
<blockquote><pre>
try
{
cout &lt;&lt; locate_zone("Europe/London")-&gt;name() &lt;&lt; '\n'; // A Zone
cout &lt;&lt; locate_zone("Europe/Jersey")-&gt;name() &lt;&lt; '\n'; // A Link to a Zone
cout &lt;&lt; locate_zone("Europe/New_Jersey")-&gt;name() &lt;&lt; '\n'; // Doesn't exist
}
catch (const exception&amp; e)
{
cout &lt;&lt; e.what() &lt;&lt; '\n';
}
</pre></blockquote>
<p>
Which outputs:
</p>
<blockquote><pre>
Europe/London
Europe/London
Europe/New_Jersey not found in timezone database
</pre></blockquote>
<p>
Note that <code>locate_zone</code> never returns <code>nullptr</code>. Also note that
the first call to <code>locate_zone</code> may implicitly initialize the database.
</p>
<hr>
<blockquote><pre>
template &lt;class Rep, class Period&gt;
std::pair
&lt;
std::chrono::time_point&lt;std::chrono::system_clock,
typename std::common_type&lt;std::chrono::duration&lt;Rep, Period&gt;,
std::chrono::seconds&gt;::type&gt;,
std::string
&gt;
to_local(std::chrono::time_point&lt;std::chrono::system_clock,
std::chrono::duration&lt;Rep, Period&gt;&gt; tp) const;
</pre></blockquote>
<p>
<code>to_local</code> maps a <code>system_clock</code>-associated <code>time_point</code>
from UTC to local time, returning both the mapped <code>time_point</code> and an
abbreviation for the local time zone. This member function accepts any precision
<code>time_point</code>, but returns a <code>time_point</code> with a precision of
<code>seconds</code> or finer. This is done because it is possible that some of the
mappings returned by the database need the precision of a second.
</p>
<p>
There are only two ways this function can fail:
</p>
<ol>
<li><p>
Out of memory error. Not bloody likely. The only memory that possibly could be
allocated is for the abbreviation stored in a <code>std::string</code> and all known
implementations will fit all known abbreviations into their short string buffer.
</p></li>
<li><p>
If you curtailed history during installation, a <code>runtime_error</code> will be thrown
if <code>tp</code> refers to a <code>time_point</code> outside of the range
<code>min_year/jan/1 00:00:00</code> to <code>max_year/dec/31 23:59:59</code>. This can
not happen with the default settings of <code>min_year</code> and <code>max_year</code>.
</p></li>
</ol>
<p>
Example:
</p>
<blockquote><pre>
auto local = current_zone()-&gt;to_local(system_clock::now());
cout &lt;&lt; local.first &lt;&lt; ' ' &lt;&lt; local.second &lt;&lt; '\n';
</pre></blockquote>
<p>
Which just output for me:
</p>
<blockquote><pre>
2015-07-12 16:57:14.430467 EDT
</pre></blockquote>
<p>
Not quite 5pm in the US Eastern timezone during daylight saving time.
</p>
<p>
And for a historical example:
</p>
<blockquote><pre>
auto distant_past = locate_zone("America/New_York")-&gt;to_local(day_point(feb/9/1942) + 7h);
cout &lt;&lt; distant_past.first &lt;&lt; ' ' &lt;&lt; distant_past.second &lt;&lt; '\n';
</pre></blockquote>
<p>
Which outputs:
</p>
<blockquote><pre>
1942-02-09 03:00:00 EWT
</pre></blockquote>
<p>
The US shifted to "War Time."
</p>
<hr>
<p>
If you want to go the other direction (from local time to UTC) use:
</p>
<blockquote><pre>
template &lt;class Rep, class Period&gt;
std::chrono::time_point&lt;std::chrono::system_clock,
typename std::common_type&lt;std::chrono::duration&lt;Rep, Period&gt;,
std::chrono::seconds&gt;::type&gt;
to_sys(std::chrono::time_point&lt;std::chrono::system_clock,
std::chrono::duration&lt;Rep, Period&gt;&gt; tp) const;
</pre></blockquote>
<p>
For example:
</p>
<blockquote><pre>
auto distant_past = locate_zone("America/New_York")-&gt;to_sys(day_point(feb/9/1942) + 3h);
cout &lt;&lt; distant_past &lt;&lt; ' ' &lt;&lt; " UTC\n";
</pre></blockquote>
<p>
Which outputs:
</p>
<blockquote><pre>
1942-02-09 07:00:00 UTC
</pre></blockquote>
<p>
This function will throw an exception of type <code>nonexistent_local_time</code> if the
local time does not exist. This can happen when the local clock is discontinuously set
forward, such as when moving from standard time to daylight savings time.
</p>
<p>
For example:
</p>
<blockquote><pre>
try
{
auto distant_past = locate_zone("America/New_York")-&gt;to_sys(day_point(feb/9/1942) + 3h - 1ms);
cout &lt;&lt; distant_past &lt;&lt; ' ' &lt;&lt; " UTC\n";
}
catch (const exception&amp; e)
{
cout &lt;&lt; e.what() &lt;&lt; '\n';
}
</pre></blockquote>
<p>
Which outputs:
</p>
<blockquote><pre>
1942-02-09 02:59:59.999 is in a gap between
1942-02-09 02:00:00 EST and
1942-02-09 03:00:00 EWT which are both equivalent to
1942-02-09 07:00:00 UTC
</pre></blockquote>
<p>
And sometimes a local time can be ambiguous, mapping to more than one UTC time:
</p>
<blockquote><pre>
try
{
auto distant_past = locate_zone("America/New_York")-&gt;to_sys(day_point(sep/30/1945) + 2h - 1ns);
cout &lt;&lt; distant_past &lt;&lt; " UTC\n";
}
catch (const exception&amp; e)
{
cout &lt;&lt; e.what() &lt;&lt; '\n';
}
</pre></blockquote>
<blockquote><pre>
1945-09-30 01:59:59.999999999 is ambiguous. It could be
1945-09-30 01:59:59.999999999 EPT == 1945-09-30 05:59:59.999999999 UTC or
1945-09-30 01:59:59.999999999 EST == 1945-09-30 06:59:59.999999999 UTC
</pre></blockquote>
<hr>
<p>
If you would rather not deal with these rare exceptions, you can choose ahead of time
to select the earliest time or latest time when a local time falls into a gap:
</p>
<blockquote><pre>
auto z = locate_zone("America/New_York");
auto distant_past = z-&gt;to_sys(day_point(sep/30/1945) + 2h - 1ns, choose::earliest);
cout &lt;&lt; distant_past &lt;&lt; " UTC\n";
distant_past = z-&gt;to_sys(day_point(sep/30/1945) + 2h - 1ns, choose::latest);
cout &lt;&lt; distant_past &lt;&lt; " UTC\n";
</pre></blockquote>
<p>
Which outputs:
</p>
<blockquote><pre>
1945-09-30 05:59:59.999999999 UTC
1945-09-30 06:59:59.999999999 UTC
</pre></blockquote>
<p>
When using this form of <code>to_sys</code> and the local time is non-existent, both
choices will map to the single UTC time on either side of the gap:
</p>
<blockquote><pre>
auto z = locate_zone("America/New_York");
auto distant_past = z-&gt;to_sys(day_point(feb/9/1942) + 3h - 1ms, choose::earliest);
cout &lt;&lt; distant_past &lt;&lt; " UTC\n";
distant_past = z-&gt;to_sys(day_point(feb/9/1942) + 3h - 1ms, choose::latest);
cout &lt;&lt; distant_past &lt;&lt; " UTC\n";
</pre></blockquote>
<p>
Which outputs:
</p>
<blockquote><pre>
1942-02-09 07:00:00.000 UTC
1942-02-09 07:00:00.000 UTC
</pre></blockquote>
<hr>
<p>
So far I've shown how given a <code>Zone</code> and a <code>system_clock::time_point</code>
of arbitrary precision, you can use <code>to_local</code> to map UTC to local time, and
<code>to_sys</code> to map local time to UTC, with your choice of either detecting any
errors, or choosing how to resolve errors. But what if that is not enough? You may be
thinking: Do I have to call these mapping functions every second? How often does the
offset change?
</p>
<p>
This library offers a partial solution to this dilemma. If the location you are concerned
about doesn't change, and if the database isn't reloaded, then <code>get_info</code> can
tell you how far into the past, and far into the future a given offset and abbreviation
are guaranteed to stay valid:
</p>
<blockquote><pre>
template &lt;class Rep, class Period&gt;
sys_info
get_info(std::chrono::time_point&lt;std::chrono::system_clock,
std::chrono::duration&lt;Rep, Period&gt;&gt; tp,
tz timezone) const;
</pre></blockquote>
<p>
Input a <code>time_point tp</code>, and indicate whether <code>tp</code> represents a UTC
<code>time_point</code> (<code>tz::utc</code>) or a local <code>time_point</code>
(<code>tz::local</code>), and a struct <code>sys_info</code> for that <code>time_point</code>
is returned:
</p>
<blockquote><pre>
auto sys_info = locate_zone("America/New_York")-&gt;get_info(system_clock::now(), tz::utc);
</pre></blockquote>
<p>
Upon return <code>sys_info</code> will contain the following information:
</p>
<ul>
<li><p>
<code>sys_info.offset</code> has type <code>std::chrono::seconds</code> and indicates the
current offset from UTC. A positive offset indicates that local time is ahead of UTC and
a negative offset indicates that local time is behind UTC.
</p></li>
<li><p>
<code>sys_info.abbrev</code> has type <code>std::string</code> and indicates the
current abbreviation for the local time zone.
</p></li>
<li><p>
<code>sys_info.begin</code> has type <code>second_point</code> and indicates the first
instant guaranteed to have this same <code>offset</code> and <code>abbrev</code>. The
<code>time_point sys_info.begin</code> is implicitly in the UTC time zone. Note that it is
possible that the instant prior to <code>begin</code> may or may not have a
different <code>offset</code> or <code>abbrev</code>.
</p></li>
<li><p>
<code>sys_info.end</code> has type <code>second_point</code> and indicates the last instant
before which it is guaranteed to have this same <code>offset</code> and
<code>abbrev</code>. The <code>time_point sys_info.end</code> is implicitly in the UTC time
zone. The <code>offset</code> and <code>abbrev</code> associated with
<code>sys_info.end</code> and beyond may or may not be different.
</p></li>
<li><p>
<code>sys_info.save</code> has type <code>std::chrono::minutes</code> and indicates the
amount of time that daylight savings time has moved the current offset. This can be
used to detect whether or not daylight savings is in effect (no if the value is 0min).
Note that <code>save</code> is already incorporated into the value of <code>offset</code>,
so you don't have to look at this field to get the current offset. This field exists
just in the spirit of more information is better.
</p></li>
</ul>
<p>
The <code>sys_info</code> also has a streaming operator which is mainly useful for debugging
purposes. Here is sample code and output:
</p>
<blockquote><pre>
cout &lt;&lt; current_zone()-&gt;get_info(system_clock::now(), tz::utc);
2015-03-08 07:00:00
2015-11-01 06:00:00
-04:00:00
01:00
EDT
</pre></blockquote>
<p>
This is considered to be a low-level function, and as such there is no error detection
if you input a local time that either does not exist, or is ambiguous. Enough information
is returned for you to compute those conditions. Indeed, this is exactly how error
detection is computed in <code>to_sys</code>: by calling <code>get_info</code> and
analyzing how the input time relates to <code>begin</code> and <code>end</code>.
</p>
<p>
Additionally the <code>Zone</code> is equality and less-than comparable (using the
<code>name()</code>). And you can stream the <code>Zone</code> out to a stream, though
the output may not be crystal clear. The streaming output is mainly used as an aid in
debugging this library, not your code.
</p>
<a name="flightexample1"></a><h3>Flight Example</h3>
<p>
There's nothing like a real-world example to help demonstrate things. Imagine a
plane flying from New York, New York, USA to Tehran, Iran. To make it more realistic,
lets say this flight occurred before the hostage crisis, right at the end of 1978. Flight
time for a non-stop one way trip is 14 hours and 44 minutes.
</p>
<p>
Given that the departure is one minute past noon on Dec. 30, 1978, local time, what is
the local arrival time?
</p>
<blockquote><pre>
#include "tz.h"
#include &lt;iostream&gt;
int
main()
{
using namespace std::chrono;
using namespace date;
auto nyc_tz = locate_zone("America/New_York");
auto teh_tz = locate_zone("Asia/Tehran");
auto nyc_departure_sys = nyc_tz-&gt;to_sys(day_point(dec/30/1978) + 12h + 1min);
auto nyc_departure = nyc_tz-&gt;to_local(nyc_departure_sys);
auto flight_length = 14h + 44min;
auto teh_arrival_sys = nyc_departure_sys + flight_length;
auto teh_arrival = teh_tz-&gt;to_local(teh_arrival_sys);
std::cout &lt;&lt; "departure NYC time: " &lt;&lt; nyc_departure.first &lt;&lt; ' '
&lt;&lt; nyc_departure.second &lt;&lt; '\n';
std::cout &lt;&lt; "flight time is " &lt;&lt; make_time(flight_length) &lt;&lt; '\n';
std::cout &lt;&lt; "arrival Tehran time: " &lt;&lt; teh_arrival.first &lt;&lt; ' '
&lt;&lt; teh_arrival.second &lt;&lt; '\n';
}
</pre></blockquote>
<p>
There are several points to be made about the above code:
</p>
<ul>
<li><p>
A stylistic guide is to use "<code>sys</code>" for <code>system_clock time_points</code>.
This helps distinguish system times (UTC) from local times.
</p></li>
<li><p>
No time arithmetic is done using local <code>time_point</code>s. All time arithmetic is
done in the UTC time zone. Time arithmetic in terms of local <code>time_point</code>s is
error prone. Note though that this computation (using
<code>system_clock::time_point</code>) is ignorant of leap seconds. If you must, see how
to take leap seconds into account with <b>utc_clock</b>.
</p></li>
<li><p>
There is no <code>using namespace std</code> because "<code>dec</code>" is ambiguous if
both <code>date</code> and <code>std</code> are brought into scope. In <code>date</code>
"<code>dec</code>" means December. In <code>std</code> "<code>dec</code>" means:
</p>
<blockquote><pre>
ios_base&amp; dec(ios_base&amp; str);
</pre></blockquote>
<p>
Thank goodness for namespaces!
</p></li>
</ul>
<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>
And this program is <i>exactly correct</i>. But what happens with the same flight on
the following day?
</p>
<blockquote><pre>
auto nyc_departure_sys = nyc_tz->to_sys(day_point(dec/<b>31</b>/1978) + 12h + 1min);
departure NYC time: 1978-12-31 12:01:00 EST
flight time is 14:44
arrival Tehran time: 1979-01-01 <b>11:15:00</b> 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. See <b>Flight Example with leap seconds</b>.
</p>
<a name="utc_clock"></a><h3>utc_clock</h3>
<p>
One of the first questions everyone asks when a new date-time library comes out is:
</p>
<blockquote><p>
Does it handle leap seconds?
</p></blockquote>
<p>
The answer here is yes, this library can handle leap seconds. But be careful what you ask
for. Correctly handling leap seconds is error prone. Therefore this library handles leap
seconds in a completely different type-safe way, which can't be accidentally mixed with
everything else presented so far. The motivation for this separation is born from several
issues:
</p>
<ul>
<li><p>
<code>system_clock</code> (<a href="https://en.wikipedia.org/wiki/Unix_time">Unix
time</a>) <i>sort of</i> handles leaps seconds in that "now" in
<a href="https://en.wikipedia.org/wiki/Unix_time">Unix
time</a> <i>always</i> corresponds to "now" in UTC (UTC being leap second aware). It is
just that the difference between two
<a href="https://en.wikipedia.org/wiki/Unix_time">Unix time</a> <code>time_point</code>s
may produce a number of <code>std::chrono::seconds</code> which does not reflect the
exact number of physical seconds which has actually transpired.
</p></li>
<li><p>
Unless you are using a very special computer, directly connected to an atomic clock, your
computer is likely using <a href="https://en.wikipedia.org/wiki/Unix_time">Unix time</a>.
If you want to correctly interpret things such as time stamps, and you want to correctly
handle leap seconds, it is critical to know if those time stamps (the input data) were
generated by software that correctly handled leap seconds. Odds are very good that they
were generated by software following
<a href="https://en.wikipedia.org/wiki/Unix_time">Unix time</a>, or
<a href="http://www.ntp.org">Network Time Protocol</a> which for our purposes here, treats
leaps seconds in essentially the same way
<a href="https://en.wikipedia.org/wiki/Unix_time">Unix time</a> does (as a clock
correction).
</p></li>
<li><p>
Handling leap seconds is not free. Don't try to just so you can be "more exact." Do it
when your requirements actually demand it, and you have the resources to test that you are
indeed correctly handling leap seconds. If the person telling you to correctly handle
leap seconds has <a href="http://dilbert.com">pointy hair</a>, double down on your
testing, and have your atomic clock ready. The extra expense is not so much memory or
performance (those penalties exist but are relatively small), but in the problem of
believing you've achieved more accuracy when you actually haven't.
</p></li>
</ul>
<p>
<code>utc_clock</code> is a <code>std::chrono</code>-conforming clock with the same
<code>duration</code> as your <code>system_clock</code>, and a <code>now()</code>
function that returns the actual number of physical seconds since 1970-01-01 00:00:00 UTC
(counting leap seconds):
</p>
<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&lt;utc_clock&gt;;
static constexpr bool is_steady = true;
static time_point now() noexcept;
template &lt;class Duration&gt;
static
std::chrono::time_point&lt;utc_clock,
typename std::common_type&lt;Duration, std::chrono::seconds&gt;::type&gt;
sys_to_utc(std::chrono::time_point&lt;std::chrono::system_clock, Duration&gt; t);
template &lt;class Duration&gt;
static
std::chrono::time_point&lt;std::chrono::system_clock,
typename std::common_type&lt;Duration, std::chrono::seconds&gt;::type&gt;
utc_to_sys(std::chrono::time_point&lt;utc_clock, Duration&gt; t);
};
</pre></blockquote>
<p>
Additionally <code>utc_clock</code> has static member functions for converting between
<code>utc_clock</code>-based <code>time_point</code>s to and from
<code>system_clock</code>-based <code>time_point</code>s of any precision. But it is
important to remember that <code>utc_clock</code> isn't connected to a super accurate
atomic clock. All it does is look its <code>time_point</code> up in the database to
see how many leap seconds have passed since 1972, and adds or subtracts that number of
seconds to do the conversion. The <code>utc_clock::now()</code> function simply calls
<code>system_clock::now()</code> and adds the current total of leaps seconds (currently
26) to the result. This is useful behavior but it is important to understand that
<code>utc_clock</code> is not a highly accurate scientific instrument. It is precisely
as accurate as your existing <code>std::chrono::system_clock</code>.
</p>
<a name="flightexample2"></a><h3>Flight Example with leap seconds</h3>
<p>
In the preceding section a flight from New York City to Tehran was offered, demonstrating
how local political changes in the rules governing UTC offsets can affect time
computations. As it turns out, while that flight departing on <code>dec/31/1978</code>
was in the air, we also underwent a leap second addition. How does that impact the
computation, and how can this library be used to account for that (should it actually be
important)?
</p>
<blockquote><pre>
#include "tz.h"
#include &lt;iostream&gt;
int
main()
{
using namespace std::chrono;
using namespace date;
auto nyc_tz = locate_zone("America/New_York");
auto teh_tz = locate_zone("Asia/Tehran");
auto nyc_departure_sys = nyc_tz-&gt;to_sys(day_point(dec/31/1978) + 12h + 1min);
auto nyc_departure = nyc_tz-&gt;to_local(nyc_departure_sys);
<b>auto nyc_departure_utc = utc_clock::sys_to_utc(nyc_departure_sys);
</b>auto flight_length = 14h + 44min;<b>
auto teh_arrival_utc = nyc_departure_utc + flight_length;
auto teh_arrival_sys = utc_clock::utc_to_sys(teh_arrival_utc);</b>
auto teh_arrival = teh_tz-&gt;to_local(teh_arrival_sys);
std::cout &lt;&lt; "departure NYC time: " &lt;&lt; nyc_departure.first &lt;&lt; ' '
&lt;&lt; nyc_departure.second &lt;&lt; '\n';
std::cout &lt;&lt; "flight time is " &lt;&lt; make_time(flight_length) &lt;&lt; '\n';
std::cout &lt;&lt; "arrival Tehran time: " &lt;&lt; teh_arrival.first &lt;&lt; ' '
&lt;&lt; teh_arrival.second &lt;&lt; '\n';
}
departure NYC time: 1978-12-31 12:01:00 EST
flight time is 14:44
arrival Tehran time: 1979-01-01 <b>11:14:59</b> IRST
</pre></blockquote>
<p>
As can be seen, we now report an arrival time 1s before the arrival time we computed
without taking leap seconds into account. The key to working with leap seconds is to make
sure that all your time arithmetic takes place using <code>utc_clock</code>-based
<code>time_point</code>s, instead of <code>system_clock</code>-based
<code>time_point</code>s. Just convert to <code>system_clock</code> when you're ready to
break the date and time up into field-based structures, or are ready to further convert it
into a local <code>time_point</code>. In this example, the only time arithmetic is:
</p>
<blockquote><pre>
auto teh_arrival_utc = nyc_departure_utc + flight_length;
</pre></blockquote>
<p>
The reset of the code is simply about converting from local, to <code>system_clock</code>
to <code>utc_clock</code> and back.
</p>
<blockquote><p>
<i>Digression:</i> Doing computations with leap seconds is cool. But perhaps the true
power of this library is revealed in the ease with which I created this example. I sat
back and said to myself:
</p>
<blockquote><p>
I want to find a time and location where a timezone offset changed within 12 hours
of a leap second insertion. And then build my flight time example around that event.
</p></blockquote>
<p>
Subsequently I wrote the following code to search the entire planet, and the last 45
years, to find these rare chronological events:
</p>
<blockquote><pre>
const auto&amp; db = get_tzdb();
for (auto const&amp; leap : db.leaps)
{
for (auto const&amp; zone : db.zones)
{
auto info = zone.get_info(leap.date(), tz::utc);
if (leap.date() - info.begin &lt;= 12h)
{
auto prev = zone.get_info(info.begin - 1s, tz::utc);
if (prev.offset != info.offset)
std::cout &lt;&lt; zone.name() &lt;&lt; " " &lt;&lt; info.begin &lt;&lt; " : "
&lt;&lt; leap &lt;&lt; ' '
&lt;&lt; make_time(info.offset-prev.offset) &lt;&lt; '\n';
}
if (info.end - leap.date() &lt;= 12h)
{
auto next = zone.get_info(info.end, tz::utc);
if (next.offset != info.offset)
std::cout &lt;&lt; zone.name() &lt;&lt; " " &lt;&lt; info.end &lt;&lt; " : "
&lt;&lt; leap &lt;&lt; ' '
&lt;&lt; make_time(next.offset - info.offset) &lt;&lt; '\n';
}
}
}
</pre></blockquote>
<p>
The flight time example wasn't really about Iran, the US, and politics after all. It was
about finding this needle in a haystack of time and space, which turned out to be
relatively easy and incredibly efficient.
</p>
<p>
You too can analyze the <a href="http://www.iana.org/time-zones">IANA Time Zone
Database</a> in creative and interesting ways no one else has thought of. There is a lot
of history here.
</p></blockquote>
<a name="Formatting"></a><h3>Formatting</h3>
<p>
All of the types in this library, as well as in
<a href="date.html"><code>date.h</code></a> are streamable when you need quick and
simple output. However in addition to this simplistic streaming there is more
sophisticated formatting built on top of the C++11 <code>time_put&lt;char&gt;</code>
facet. <code>time_put&lt;char&gt;</code> itself is built on C's <code>strftime</code>
function. But <code>time_put&lt;char&gt;</code> is sensitive to C++ <code>locale</code>s.
</p>
<p>
The basic way to use formatting is to call the <code>format</code> function like this:
</p>
<blockquote><pre>
cout &lt;&lt; format("%A %F %T", floor&lt;seconds&gt;(system_clock::now())) &lt;&lt; '\n';
</pre></blockquote>
<p>
Which just output for me:
</p>
<blockquote><pre>
Sunday 2016-04-03 22:02:19
</pre></blockquote>
<p>
Note the cast to <code>seconds</code> precision in the call. This is how you control
the precision of the <code>seconds</code> output (if any). The modifiers <code>%S</code>
and <code>%T</code> will output seconds to whatever the precision is of the
<code>time_point</code>. For example:
</p>
<blockquote><pre>
cout &lt;&lt; format("%A %F %T", floor&lt;milliseconds&gt;(system_clock::now())) &lt;&lt; '\n';
</pre></blockquote>
<p>
would instead output:
</p>
<blockquote><pre>
Sunday 2016-04-03 22:02:19.656
</pre></blockquote>
<p>
Note that there is an implicit time zone being used here: UTC. The <code>%z</code> and
<code>%Z</code> modifiers can be used to show this:
</p>
<blockquote><pre>
cout &lt;&lt; format("%A %F %T %z %Z", floor&lt;milliseconds&gt;(system_clock::now())) &lt;&lt; '\n';
</pre></blockquote>
<p>
would instead output:
</p>
<blockquote><pre>
Sunday 2016-04-03 22:02:19.656 +0000 UTC
</pre></blockquote>
<p>
A <code>Zone</code> can also be passed in and then the <code>%z</code> and
<code>%Z</code> modifiers will reflect that passed-in zone. It is important to
remember however that <code>format</code> <em>never</em> shifts the
<code>time_point</code> for you. Instead you pass in a <code>Zone</code> that you know
to be associated with your <code>time_point</code>. For example:
</p>
<blockquote><pre>
auto zone = locate_zone("Europe/Berlin");
auto local = zone-&gt;to_local(floor&lt;milliseconds&gt;(system_clock::now())).first;
cout &lt;&lt; format("%A %F %T %z %Z", local, zone) &lt;&lt; '\n';
</pre></blockquote>
<blockquote><pre>
Monday 2016-04-04 00:02:19.656 +0200 CEST
</pre></blockquote>
<p>
The <i>only</i> thing <code>format</code> ever does with a <code>Zone</code> is extract
the offset and/or the abbreviation for use with the <code>%z</code> and <code>%Z</code>
modifiers.
</p>
<p>
You can also pass in a <code>locale</code> to <code>format</code>:
</p>
<blockquote><pre>
cout &lt;&lt; format(locale("de_DE"), "%A %F %T %z %Z", local, zone) &lt;&lt; '\n';
</pre></blockquote>
<blockquote><pre>
Montag 2016-04-04 00:02:19,656 +0200 CEST
</pre></blockquote>
<p>
The set of named locales that your OS supports is defined by your OS, not this library.
</p>
<p>
Instead of a <code>time_point</code> you can also pass in anything that is implicitly
convertible to <code>day_point</code>:
</p>
<blockquote><pre>
cout &lt;&lt; format(locale("de_DE"), "%A %B %e, %Y", 2016_y/jul/mon[1]) &lt;&lt; '\n';
</pre></blockquote>
<blockquote><pre>
Montag Juli 4, 2016
</pre></blockquote>
<p>
In summary, use <code>format</code> by passing in a format string and a
<code>time_point</code>, or something implicitly convertible to a <code>day_point</code>.
You can optionally pass in a <code>locale</code> as the first parameter, and a
<code>Zone</code> as the last parameter. <code>format</code> will never alter the value
of your <code>time_point</code>. The precision of the <code>time_point</code> controls
the precision of seconds with the <code>%S</code> and <code>%T</code> modifiers. If you
pass in a <code>Zone</code>, this will only impact the output of <code>%z</code> and
<code>%Z</code> (which default to <code>+0000</code> and <code>UTC</code> respectively).
The output of <code>format</code> is a <code>std::string</code>.
</p>
<a name="Parsing"></a><h3>Parsing</h3>
<p>
Since all parts of all date-types in this library can be constructed with integral types,
you can parse any format you wish as integrals, and create dates from any format you
wish that way.
</p>
<p>
However this section introduces a <code>parse</code> function which is built on top
of the C++11 <code>time_get</code> facet which can also be used:
</p>
<blockquote><pre>
template &lt;class Duration&gt;
void
parse(std::istream&amp; is, const std::string&amp; format,
std::chrono::time_point&lt;std::chrono::system_clock, Duration&gt;&amp; tp);
</pre></blockquote>
<p>
You can input any <code>istream</code>, and a format string much like that used for
<code>format</code> and <code>strftime</code>, and a <code>time_point</code> of any
precision, and this function will attempt to extract the <code>time_point</code> from
the <code>istream</code> by using the format <code>string</code>. If not successful,
the <code>time_point</code> will not be altered.
</p>
<p>
Example use:
</p>
<blockquote><pre>
istringstream is("Montag 2016-04-04 00:02:19,656 +0200");
is.imbue(locale("de_DE"));
system_clock::time_point tp;
parse(is, "%A %F %T %z", tp);
cout &lt;&lt; tp &lt;&lt; '\n';
</pre></blockquote>
<p>
Which outputs:
</p>
<blockquote><pre>
2016-04-03 22:02:19.656000
</pre></blockquote>
<p>
Note that the <code>locale</code> associated with the <code>istream</code> is respected.
If the format string contains a <code>%z</code> which matches the input stream, this is
used to convert the value to UTC. If there is no <code>%z</code>, then no conversion
happens (you can assume whatever timezone you want). Note that fractional seconds are
accepted as long as one uses <code>%T</code> or <code>%S</code>, and the precision of the
<code>time_point</code> is fine enough to accept fractional seconds.
</p>
<p>
<code>%Z</code> is not accepted as the mapping from a timezone abbreviation to UTC is
in general, ambiguous. If you have a <code>%Z</code> in the format string, this will
result in <code>is.fail()</code> returning <code>true</code> after the call to
<code>parse</code>.
</p>
<p>
However, if you absolutely must parse a timestamp with a timezone abbreviation in it,
an extra <code>parse</code> overload is provided:
</p>
<blockquote><pre>
template &lt;class Duration&gt;
void
parse(std::istream&amp; is, const std::string&amp; format,
std::chrono::time_point&lt;std::chrono::system_clock, Duration&gt;&amp; tp,
std::string& abbrev);
</pre></blockquote>
<p>
Now if <code>%Z</code> matches a word in <code>is</code> <em>and</em> if the rest of
<code>is</code> correctly parses according to <code>format</code>, then
<code>abbrev</code> will be assigned the word which matched <code>%Z</code>. This
<i>will not</i> have any impact on the value of <code>tp</code> (no timezone offset
applied). However perhaps there is enough a-priori knowledge in your application to
make use of the value of <code>abbrev</code> to correctly interpret the meaning of
the timestamp and the resulting value of <code>tp</code>.
</p>
<p>
As an example of how this option can be both useful <i>and</i> dangerous, consider
an example where we need to parse the timestamp "Thu Apr 07 11:45:28 AEST 2016", and
we want to discover what the corresponding time is in UTC, and what timezone this
timestamp represents.
</p>
<p>
The following program parses this, and then searches
the entire timezone database looking for timezones which have "AEST" as an abbreviation
at a local time of Apr 07 11:45:28 2016. The program finds the first one, notes its UTC
offset, and then searches for more. If it finds more, and the UTC offset is the same,
it simply outputs the name of each additional timezone found. If the additional timezones
have a different UTC offset, that is noted too by outputting the UTC timestamp associated
with the additional timezone.
</p>
<blockquote><pre>
#include "tz.h"
#include &lt;string&gt;
#include &lt;iostream&gt;
#include &lt;sstream&gt;
#include &lt;cassert&gt;
int
main()
{
using namespace std::chrono;
using namespace date;
auto&amp; db = get_tzdb();
std::istringstream in("Thu Apr 07 11:45:28 AEST 2016");
time_point&lt;system_clock, seconds&gt; tp_local;
std::string abbrev;
parse(in, "%a %b %d %T %Z %Y", tp_local, abbrev);
assert(!in.fail());
auto i = std::find_if(db.zones.begin(), db.zones.end(),
[&amp;tp_local, &amp;abbrev](auto const&amp; z)
{
return z.get_info(tp_local, tz::local).abbrev == abbrev;
});
if (i != db.zones.end())
{
auto tp_utc = i-&gt;to_sys(tp_local);
std::cout &lt;&lt; tp_utc &lt;&lt; " UTC " &lt;&lt; i-&gt;name() &lt;&lt; '\n';
for (++i; i != db.zones.end(); ++i)
{
if (i-&gt;get_info(tp_local, tz::local).abbrev != abbrev)
continue;
auto tp = i-&gt;to_sys(tp_local);
if (tp != tp_utc)
std::cout &lt;&lt; tp &lt;&lt; " UTC ";
std::cout &lt;&lt; i-&gt;name() &lt;&lt; '\n';
}
}
}
</pre></blockquote>
<p>
This program outputs:
</p>
<blockquote><pre>
2016-04-07 01:45:28 UTC Australia/Brisbane
Australia/Currie
Australia/Hobart
Australia/Lindeman
Australia/Melbourne
Australia/Sydney
</pre></blockquote>
<p>
This indicates that "Thu Apr 07 11:45:28 AEST 2016" unambiguously refers to
2016-04-07 01:45:28 UTC (a UTC offset of +1000). However which IANA timezone is referred
to is ambiguous. This means that past or future timepoints using any of these timezones
may or may not have the same UTC offsets (or abbreviations) among this set of timezones.
</p>
<p>
And this is a good case. Consider just altering the abbreviation in the above example
from AEST to BST. Now the output is:
</p>
<blockquote><pre>
2016-04-07 10:45:28 UTC Europe/London
2016-04-07 00:45:28 UTC Pacific/Bougainville
</pre></blockquote>
<p>
Meaning: Not only do we not know what timezone this refers to, it could mean one of
two different UTC timepoints!
</p>
<p>
So in summary, it is dangerous to parse timezone abbreviations. You should avoid it if at
all possible. However, if you are forced to, this library has the power to find out every
thing that is knowable about that timestamp.
</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&lt;time_zone&gt; zones;
std::vector&lt;Link&gt; links;
std::vector&lt;Leap&gt; leaps;
std::vector&lt;Rule&gt; 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&amp; 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&amp; 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>&mdash; 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>&mdash; 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>&mdash; end note</i>]
</blockquote>
<pre>
const TZ_DB&amp; 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&amp; reload_tzdb();
bool remote_download(const std::string&amp; version);
bool remote_install(const std::string&amp; 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>&mdash; 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&amp; 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&amp; 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 &amp;&amp; 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 &lt;iostream&gt;
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&amp; e)
{
std::cout &lt;&lt; e.what() &lt;&lt; '\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>&mdash; 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 &lt;iostream&gt;
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&amp; e)
{
std::cout &lt;&lt; e.what() &lt;&lt; '\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>&mdash; 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&amp; operator&lt;&lt;(std::ostream&amp; os, const sys_info&amp; 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&amp; operator&lt;&lt;(std::ostream&amp; os, const local_info&amp; 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&amp;) = delete;
time_zone&amp; operator=(const time_zone&amp;) = delete;
const std::string&amp; name() const;
template &lt;class Duration&gt; sys_info get_info(sys_time&lt;Duration&gt; st) const;
template &lt;class Duration&gt; local_info get_info(local_time&lt;Duration&gt; tp) const;
template &lt;class Duration&gt;
sys_time&lt;typename std::common_type&lt;Duration, std::chrono::seconds&gt;::type&gt;
to_sys(local_time&lt;Duration&gt; tp) const;
template &lt;class Duration&gt;
sys_time&lt;typename std::common_type&lt;Duration, std::chrono::seconds&gt;::type&gt;
to_sys(local_time&lt;Duration&gt; tp, choose z) const;
template &lt;class Duration&gt;
local_time&lt;typename std::common_type&lt;Duration, std::chrono::seconds&gt;::type&gt;
to_local(sys_time&lt;Duration&gt; tp) const;
};
bool operator==(const time_zone&amp; x, const time_zone&amp; y);
bool operator!=(const time_zone&amp; x, const time_zone&amp; y);
bool operator&lt; (const time_zone&amp; x, const time_zone&amp; y);
bool operator&gt; (const time_zone&amp; x, const time_zone&amp; y);
bool operator&lt;=(const time_zone&amp; x, const time_zone&amp; y);
bool operator&gt;=(const time_zone&amp; x, const time_zone&amp; y);
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, const time_zone&amp; z)
</pre>
<pre>
const std::string&amp; 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 &lt;class Duration&gt; sys_info time_zone::get_info(sys_time&lt;Duration&gt; 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 &lt;class Duration&gt; local_info time_zone::get_info(local_time&lt;Duration&gt; tp) const;
</pre>
<blockquote>
<p>
<i>Returns:</i> A <code>local_info</code> for <code>tp</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
sys_time&lt;typename std::common_type&lt;Duration, std::chrono::seconds&gt;::type&gt;
time_zone::to_sys(local_time&lt;Duration&gt; 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 &lt;class Duration&gt;
sys_time&lt;typename std::common_type&lt;Duration, std::chrono::seconds&gt;::type&gt;
time_zone::to_sys(local_time&lt;Duration&gt; 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 &lt;class Duration&gt;
local_time&lt;typename std::common_type&lt;Duration, std::chrono::seconds&gt;::type&gt;
time_zone::to_local(sys_time&lt;Duration&gt; 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&amp; x, const time_zone&amp; y);
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>x.name() == y.name()</code>.
</p>
</blockquote>
<pre>
bool operator!=(const time_zone&amp; x, const time_zone&amp; y);
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>!(x == y)</code>.
</p>
</blockquote>
<pre>
bool operator&lt;(const time_zone&amp; x, const time_zone&amp; y);
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>x.name() &lt; y.name()</code>.
</p>
</blockquote>
<pre>
bool operator&gt;(const time_zone&amp; x, const time_zone&amp; y);
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>y &lt; x</code>.
</p>
</blockquote>
<pre>
bool operator&lt;=(const time_zone&amp; x, const time_zone&amp; y);
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>!(y &lt; x)</code>.
</p>
</blockquote>
<pre>
bool operator&gt;=(const time_zone&amp; x, const time_zone&amp; y);
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>!(x &lt; y)</code>.
</p>
</blockquote>
<pre>
std::ostream&amp; operator&lt;&lt;(std::ostream&amp; os, const time_zone&amp; 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>&mdash; end note:</i>]
</p>
<pre>
template &lt;class Duration&gt;
class zoned_time
{
const time_zone* zone_; // exposition only
sys_time&lt;Duration&gt; tp_; // exposition only
public:
zoned_time(const zoned_time&amp;) = default;
zoned_time&amp; operator=(const zoned_time&amp;) = default;
zoned_time(sys_time&lt;Duration&gt; st);
explicit zoned_time(const time_zone* z);
explicit zoned_time(const std::string&amp; name);
template &lt;class Duration2,
class = std::enable_if_t
&lt;
std::is_convertible&lt;sys_time&lt;Duration2&gt;,
sys_time&lt;Duration&gt;&gt;{}
&gt;&gt;
zoned_time(const zoned_time&lt;Duration2&gt;&amp; zt) noexcept;
zoned_time(const time_zone* z, local_time&lt;Duration&gt; tp);
zoned_time(const std::string&amp; name, local_time&lt;Duration&gt; tp);
zoned_time(const time_zone* z, local_time&lt;Duration&gt; tp, choose c);
zoned_time(const std::string&amp; name, local_time&lt;Duration&gt; tp, choose c);
zoned_time(const time_zone* z, const zoned_time&lt;Duration&gt;&amp; zt);
zoned_time(const std::string&amp; name, const zoned_time&lt;Duration&gt;&amp; zt);
zoned_time(const time_zone* z, const zoned_time&lt;Duration&gt;&amp; zt, choose);
zoned_time(const std::string&amp; name, const zoned_time&lt;Duration&gt;&amp; zt, choose);
zoned_time(const time_zone* z, const sys_time&lt;Duration&gt;&amp; st);
zoned_time(const std::string&amp; name, const sys_time&lt;Duration&gt;&amp; st);
zoned_time&amp; operator=(sys_time&lt;Duration&gt; st);
zoned_time&amp; operator=(local_time&lt;Duration&gt; ut);
operator sys_time&lt;Duration&gt;() const;
explicit operator local_time&lt;Duration&gt;() const;
const time_zone* get_time_zone() const;
local_time&lt;Duration&gt; get_local_time() const;
sys_time&lt;Duration&gt; get_sys_time() const;
sys_info get_info() const;
};
using zoned_seconds = zoned_time&lt;std::chrono::seconds&gt;;
template &lt;class Duration1, class Duration2&gt;
bool
operator==(const zoned_time&lt;Duration1&gt;&amp; x, const zoned_time&lt;Duration2&gt;&amp; y);
template &lt;class Duration1, class Duration2&gt;
bool
operator!=(const zoned_time&lt;Duration1&gt;&amp; x, const zoned_time&lt;Duration2&gt;&amp; y);
</pre>
<p>
An invariant of <code>zoned_time&lt;Duration&gt;</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&lt;Duration&gt;::zoned_time(const zoned_time&amp;) = default;
zoned_time&lt;Duration&gt;&amp; zoned_time&lt;Duration&gt;::operator=(const zoned_time&amp;) = 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&lt;Duration&gt;</code> has <code>noexcept</code> copy
members.
</p>
</blockquote>
<pre>
zoned_time&lt;Duration&gt;::zoned_time(sys_time&lt;Duration&gt; st);
</pre>
<blockquote>
<p>
<i>Effects:</i> Constructs a <code>zoned_time</code> <code>zt</code> such that
<code>zt.get_time_zone()-&gt;name() == "UTC"</code>, and
<code>zt.get_sys_time() == st</code>.
</p>
</blockquote>
<pre>
explicit zoned_time&lt;Duration&gt;::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()-&gt; == z</code>, and
<code>zt.get_sys_time() == sys_seconds{}</code>.
</p>
</blockquote>
<pre>
explicit zoned_time&lt;Duration&gt;::zoned_time(const std::string&amp; 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 &lt;class Duration2,
class = std::enable_if_t
&lt;
std::is_convertible&lt;sys_time&lt;Duration2&gt;,
sys_time&lt;Duration&gt;&gt;{}
&gt;&gt;
zoned_time&lt;Duration&gt;::zoned_time(const zoned_time&lt;Duration2&gt;&amp; 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&lt;Duration&gt;::zoned_time(const time_zone* z, local_time&lt;Duration&gt; 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()-&gt; == z</code>, and <code>zt.get_local_time() == tp</code>.
</p>
<p>
<i>Throws:</i> Any exception that <code>z-&gt;to_sys(tp)</code> would throw.
</p>
</blockquote>
<pre>
zoned_time&lt;Duration&gt;::zoned_time(const std::string&amp; name, local_time&lt;Duration&gt; tp);
</pre>
<blockquote>
<p>
<i>Effects:</i> Equivalent to construction with <code>{locate_zone(name), tp}</code>.
</p>
</blockquote>
<pre>
zoned_time&lt;Duration&gt;::zoned_time(const time_zone* z, local_time&lt;Duration&gt; 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()-&gt; == z</code>, and
<code>zt.get_sys_time() == z-&gt;to_sys(tp, c)</code>.
</p>
</blockquote>
<pre>
zoned_time&lt;Duration&gt;::zoned_time(const std::string&amp; name, local_time&lt;Duration&gt; 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&lt;Duration&gt;::zoned_time(const time_zone* z, const zoned_time&lt;Duration&gt;&amp; 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()-&gt; == z</code>, and
<code>zt.get_sys_time() == y.get_sys_time()</code>.
</p>
</blockquote>
<pre>
zoned_time&lt;Duration&gt;::zoned_time(const std::string&amp; name, const zoned_time&lt;Duration&gt;&amp; y);
</pre>
<blockquote>
<p>
<i>Effects:</i> Equivalent to construction with <code>{locate_zone(name), y}</code>.
</p>
</blockquote>
<pre>
zoned_time&lt;Duration&gt;::zoned_time(const time_zone* z, const zoned_time&lt;Duration&gt;&amp; 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()-&gt; == 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&lt;Duration&gt;::zoned_time(const std::string&amp; name, const zoned_time&lt;Duration&gt;&amp; 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&lt;Duration&gt;::zoned_time(const time_zone* z, const sys_time&lt;Duration&gt;&amp; 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()-&gt; == z</code>, and <code>zt.get_sys_time() == st</code>.
</p>
</blockquote>
<pre>
zoned_time&lt;Duration&gt;::zoned_time(const std::string&amp; name, const sys_time&lt;Duration&gt;&amp; st);
</pre>
<blockquote>
<p>
<i>Effects:</i> Equivalent to construction with <code>{locate_zone(name), st}</code>.
</p>
</blockquote>
<pre>
zoned_time&lt;Duration&gt;&amp; zoned_time&lt;Duration&gt;::operator=(sys_time&lt;Duration&gt; 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&lt;Duration&gt;&amp; zoned_time&lt;Duration&gt;::operator=(local_time&lt;Duration&gt; 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&lt;Duration&gt;::operator sys_time&lt;Duration&gt;() const;
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>get_sys_time()</code>.
</p>
</blockquote>
<pre>
explicit zoned_time&lt;Duration&gt;::operator local_time&lt;Duration&gt;() const;
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>get_local_time()</code>.
</p>
</blockquote>
<pre>
const time_zone* zoned_time&lt;Duration&gt;::get_time_zone() const;
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>zone_</code>.
</p>
</blockquote>
<pre>
local_time&lt;Duration&gt; zoned_time&lt;Duration&gt;::get_local_time() const;
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>zone_-&gt;to_local(tp_)</code>.
</p>
</blockquote>
<pre>
sys_time&lt;Duration&gt; zoned_time&lt;Duration&gt;::get_sys_time() const;
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>tp_</code>.
</p>
</blockquote>
<pre>
sys_info zoned_time&lt;Duration&gt;::get_info() const;
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>zone_-&gt;get_info(tp_)</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration1, class Duration2&gt;
bool
operator==(const zoned_time&lt;Duration1&gt;&amp; x, const zoned_time&lt;Duration2&gt;&amp; y);
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>x.zone_ == y.zone_ &amp;&amp; x.tp_ == y.tp_</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration1, class Duration2&gt;
bool
operator!=(const zoned_time&lt;Duration1&gt;&amp; x, const zoned_time&lt;Duration2&gt;&amp; y);
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>!(x == y)</code>.
</p>
</blockquote>
<pre>
template <class Duration>
std::ostream&
operator<<(std::ostream& 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&lt;Duration&gt;</code> and
will deduce the correct <code>Duration</code> from the argument list. In every
case the correct return type is
<code>zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;</code>.
</p>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(sys_time&lt;Duration&gt; tp)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>{tp}</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(const time_zone* zone, local_time&lt;Duration&gt; tp)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>{zone, tp}</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(const std::string&amp; name, local_time&lt;Duration&gt; tp)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>{name, tp}</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(const time_zone* zone, local_time&lt;Duration&gt; tp, choose c)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>{zone, tp, c}</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(const std::string&amp; name, local_time&lt;Duration&gt; tp, choose c)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>{name, tp, c}</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(const time_zone* zone, const zoned_time&lt;Duration&gt;&amp; zt)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>{zone, zt}</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(const std::string&amp; name, const zoned_time&lt;Duration&gt;&amp; zt)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>{name, zt}</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(const time_zone* zone, const zoned_time&lt;Duration&gt;&amp; zt, choose c)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>{zone, zt, c}</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(const std::string&amp; name, const zoned_time&lt;Duration&gt;&amp; zt, choose c)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>{name, zt, c}</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(const time_zone* zone, const sys_time&lt;Duration&gt;&amp; st)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>{zone, st}</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
zoned_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
make_zoned(const std::string&amp; name, const sys_time&lt;Duration&gt;&amp; 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 &lt;class Duration&gt;
std::string
format(const std::locale&amp; loc, std::string format, local_time&lt;Duration&gt; tp);
template &lt;class Duration&gt;
std::string
format(std::string format, local_time&lt;Duration&gt; tp);
template &lt;class Duration&gt;
std::string
format(const std::locale&amp; loc, std::string format, const zoned_time&lt;Duration&gt;&amp; tp);
template &lt;class Duration&gt;
std::string
format(std::string format, const zoned_time&lt;Duration&gt;&amp; tp);
template &lt;class Duration&gt;
std::string
format(const std::locale&amp; loc, std::string format, sys_time&lt;Duration&gt; tp);
template &lt;class Duration&gt;
std::string
format(std::string format, sys_time&lt;Duration&gt; 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>
</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>
<pre>
template &lt;class Duration&gt;
void
parse(std::istream&amp; is, const std::string&amp; format, sys_time&lt;Duration&gt;&amp; tp);
template &lt;class Duration&gt;
void
parse(std::istream&amp; is, const std::string&amp; format, local_time&lt;Duration&gt;&amp; tp);
template &lt;class Duration&gt;
void
parse(std::istream&amp; is, const std::string&amp; format, local_time&lt;Duration&gt;&amp; tp,
std::string&amp; 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> is 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>%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&lt;Duration&gt;(duration&lt;double&gt;{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 first overload (<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 second and third overloads require a valid parse of the
offset, but then ignore the offset in assigning a value to the
<code>local_time&lt;Duration&gt;&amp; tp</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. However 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 third overload one can discover what that
parsed abbreviation is. If the third overload is used, but <code>%Z</code> does
not appear in the format, then <code>abbrev</code> is not altered.
</p></li>
</ul>
</blockquote>
<p>
<i>Note:</i> There is no unique mapping from a time zone abbreviation to a
<code>time_zone</code>.
</p>
</blockquote>
</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&lt;utc_clock&gt;;
static constexpr bool is_steady = true;
static time_point now() noexcept;
template &lt;class Duration&gt;
static
utc_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
sys_to_utc(sys_time&lt;Duration&gt; t);
template &lt;class Duration&gt;
static
sys_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
utc_to_sys(utc_time&lt;Duration&gt; u);
};
template &lt;class Duration&gt;
using utc_time = std::chrono::time_point&lt;utc_clock, Duration&gt;;
using utc_seconds = utc_time&lt;std::chrono::seconds&gt;;
</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>sys_to_utc(system_clock::now())</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
static
utc_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
utc_clock::sys_to_utc(sys_time&lt;Duration&gt; 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 &lt;class Duration&gt;
static
sys_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
utc_clock::utc_to_sys(utc_time&lt;Duration&gt; u);
</pre>
<blockquote>
<p>
<i>Returns:</i> A <code>sys_time</code> <code>t</code>, such that
<code>utc_clock::sys_to_utc(t) == u</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
utc_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
to_utc_time(sys_time&lt;Duration&gt; t)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>utc_clock::sys_to_utc(t)</code>.
</p>
</blockquote>
<pre>
template &lt;class Duration&gt;
sys_time&lt;std::common_type_t&lt;Duration, std::chrono::seconds&gt;&gt;
to_sys_time(utc_time&lt;Duration&gt; u)
</pre>
<blockquote>
<p>
<i>Returns:</i> <code>utc_clock::utc_to_sys(u)</code>.
</p>
</blockquote>
<p>
[<i>Example:</i>
</p>
<blockquote><pre>
#include "tz.h"
#include &lt;iostream&gt;
int
main()
{
using namespace date;
using namespace std::chrono_literals;
auto t0 = sys_days{1972_y/jul/1} - 1ms;
auto u0 = to_utc_time(t0);
auto t1 = to_sys_time(u0);
std::cout &lt;&lt; t0 &lt;&lt; ":\n";
std::cout &lt;&lt; (u0.time_since_epoch() - t0.time_since_epoch()).count() &lt;&lt; "ms\n";
std::cout &lt;&lt; (t1 - t0).count() &lt;&lt; "ms\n\n";
t0 += 1ms;
u0 = to_utc_time(t0);
t1 = to_sys_time(u0);
std::cout &lt;&lt; t0 &lt;&lt; ":\n";
std::cout &lt;&lt; (u0.time_since_epoch() - t0.time_since_epoch()).count() &lt;&lt; "ms\n";
std::cout &lt;&lt; (t1 - t0).count() &lt;&lt; "ms\n";
}
</pre>
<p>
Output:
</p>
<pre>
1972-06-30 23:59:59.999:
0ms
0ms
1972-07-01 00:00:00.000:
1000ms
0ms
</pre>
</blockquote>
<p>
<i>&mdash; end example</i>]
</p>
</blockquote>
<a name="Leap"></a><h3><code>Leap</code></h3>
<blockquote>
<pre>
class Leap
{
public:
Leap(const Leap&amp;) = default;
Leap&amp; operator=(const Leap&amp;) = default;
// Undocumented constructors
sys_seconds date() const;
};
bool operator==(const Leap&amp; x, const Leap&amp; y);
bool operator!=(const Leap&amp; x, const Leap&amp; y);
bool operator&lt; (const Leap&amp; x, const Leap&amp; y);
bool operator&gt; (const Leap&amp; x, const Leap&amp; y);
bool operator&lt;=(const Leap&amp; x, const Leap&amp; y);
bool operator&gt;=(const Leap&amp; x, const Leap&amp; y);
template &lt;class Duration&gt; bool operator==(const const Leap&amp; x, const sys_time&lt;Duration&gt;&amp; y);
template &lt;class Duration&gt; bool operator==(const sys_time&lt;Duration&gt;&amp; x, const Leap&amp; y);
template &lt;class Duration&gt; bool operator!=(const Leap&amp; x, const sys_time&lt;Duration&gt;&amp; y);
template &lt;class Duration&gt; bool operator!=(const sys_time&lt;Duration&gt;&amp; x, const Leap&amp; y);
template &lt;class Duration&gt; bool operator&lt; (const Leap&amp; x, const sys_time&lt;Duration&gt;&amp; y);
template &lt;class Duration&gt; bool operator&lt; (const sys_time&lt;Duration&gt;&amp; x, const Leap&amp; y);
template &lt;class Duration&gt; bool operator&gt; (const Leap&amp; x, const sys_time&lt;Duration&gt;&amp; y);
template &lt;class Duration&gt; bool operator&gt; (const sys_time&lt;Duration&gt;&amp; x, const Leap&amp; y);
template &lt;class Duration&gt; bool operator&lt;=(const Leap&amp; x, const sys_time&lt;Duration&gt;&amp; y);
template &lt;class Duration&gt; bool operator&lt;=(const sys_time&lt;Duration&gt;&amp; x, const Leap&amp; y);
template &lt;class Duration&gt; bool operator&gt;=(const Leap&amp; x, const sys_time&lt;Duration&gt;&amp; y);
template &lt;class Duration&gt; bool operator&gt;=(const sys_time&lt;Duration&gt;&amp; x, const Leap&amp; 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&lt;Duration&gt;</code>.
</p>
</blockquote>
<a name="Link"></a><h3><code>Link</code></h3>
<blockquote>
<pre>
class Link
{
public:
Link(const Link&amp;) = default;
Link&amp; operator=(const Link&amp;) = default;
// Undocumented constructors
const std::string&amp; name() const;
const std::string&amp; target() const;
};
bool operator==(const Link&amp; x, const Link&amp; y);
bool operator!=(const Link&amp; x, const Link&amp; y);
bool operator&lt; (const Link&amp; x, const Link&amp; y);
bool operator&gt; (const Link&amp; x, const Link&amp; y);
bool operator&lt;=(const Link&amp; x, const Link&amp; y);
bool operator&gt;=(const Link&amp; x, const Link&amp; 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>.
The source
<a href="https://github.com/HowardHinnant/date/blob/master/tz.cpp"><code>tz.cpp</code></a>
contains the following string near the top:
</p>
<blockquote><pre>
static std::string install{"~/Downloads/tzdata"}; // "c:\\tzdata" on Windows
</pre></blockquote>
<p>
You should set this such that <code>install</code> points to the directory
where your library or application can find the downloaded and uncompressed
<a href="http://www.iana.org/time-zones">IANA Time Zone Database</a> (or where
you want the software to install it for you if you compile with
<code>AUTO_DOWNLOAD == 1</code>).
</p>
<p>
There are three configuration macros that can be defined on the command line during
compilation, or you can ignore them and they will take on default values.
</p>
<blockquote>
<table cellpadding="5">
<tr>
<td><code>HAS_REMOTE_API</code></td>
<td>Defaults to 1 on Linux and OS X, and to 0 on Windows</td>
</tr>
<tr>
<td><code>AUTO_DOWNLOAD</code></td>
<td>Defaults to <code>HAS_REMOTE_API</code></td>
</tr>
<tr>
<td><code>LAZY_INIT</code></td>
<td>Defaults to 1</td>
</tr>
</table>
</blockquote>
<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&amp; version);
bool remote_install(const std::string&amp; 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 OS X and Linux this is done with <code>-lcurl</code>.
<code>libcurl</code> comes pre-installed on OS X and Linux, but not on Windows.
However one can download it for Windows.
</p>
<p>
If <code>AUTO_DOWNLOAD</code> is 1 then first access to the timezone database will install
it if it hasn't been installed, and if it has, will use the remote API to install the
latest version if not already installed.
</p>
<h3>Optional installation tweaks</h3>
<p>
If <code>LAZY_INIT</code> is on, the <code>Zone</code>s are not fully compiled upon first
access to the database. As each <code>Zone</code> is accessed individaully by the
programmer (when they are used), they are fully compiled at that point. However, this
further <code>Zone</code> compilation does not involve any access to the local copy of the
tz database files.
</p>
<p>
If <code>LAZY_INIT</code> is off, every <code>Zone</code> is fully compiled upon first
access to the database.
</p>
<p>
<code>LAZY_INIT</code> speeds up the initialization of the database, but slows down the
first use of any individual <code>Zone</code>. If you are only using a few
<code>Zone</code>s then <code>LAZY_INIT</code> is a clear win. If you are immediately
using all of the <code>Zone</code>s (say for some database analysis) then
<code>LAZY_INIT</code> is not a win.
</p>
<p>
If <code>LAZY_INIT</code> is off, and you are on multi-core hardware, and your application
has other unrelated initialization it has to take care of, spinning off timezone
initialization into a detached thread can be an attractive option:
</p>
<blockquote><pre>
int
main()
{
std::thread(date::get_tzdb).detach();
// other initialization ...
}
</pre></blockquote>
<p>
By the time your application actually needs to use the timezone database, it is likely to
be fully initialized and ready to go. And if it is not, C++11 threadsafe function local
statics ensure there is no race condition on the initialization.
</p>
<p>
If you would like to trade off functionality for size, you can reduce the size of the
database in two ways:
</p>
<ul>
<li>Limit geography.</li>
<li>Limit history.</li>
</ul>
<p>
You can limit geography by removing one or more of the files in this list:
</p>
<blockquote><pre>
const std::vector&lt;const std::string&gt; files =
{
"africa", "antarctica", "asia", "australasia", "backward", "etcetera", "europe",
"pacificnew", "northamerica", "southamerica", "systemv", "leapseconds"
};
</pre></blockquote>
<p>
You can limit history by setting <code>min_year</code> to something more recent such as:
</p>
<blockquote><pre>
CONSTDATA auto min_year = 2015_y;
</pre></blockquote>
<p>
When you do so, if you ask to convert a date prior to <code>min_year</code>, an exception
will be thrown.
</p>
<p>
The entire database consumes about 859Kb.
</p>
<p>
Compile
<a href="https://github.com/HowardHinnant/date/blob/master/tz.cpp"><code>tz.cpp</code></a>
in with the rest of your library or application.
</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>
There is no preprocessing of the
<a href="http://www.iana.org/time-zones">IANA Time Zone Database</a> required. This
library efficiently initializes itself directly from the files of the
<a href="http://www.iana.org/time-zones">IANA Time Zone Database</a>.
</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>