| <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" | |
| xml:id="std.time" xreflabel="Time"> | |
| <?dbhtml filename="time.html"?> | |
| <info><title> | |
| Time | |
| <indexterm><primary>Time</primary></indexterm> | |
| </title> | |
| <keywordset> | |
| <keyword>ISO C++</keyword> | |
| <keyword>library</keyword> | |
| </keywordset> | |
| </info> | |
| <!-- Sect1 01 : Time zone database --> | |
| <section xml:id="std.time.zone.db" xreflabel=""><info><title>Time zone database</title></info> | |
| <?dbhtml filename="tzdb.html"?> | |
| <para> | |
| Since C++20 the <code><chrono></code> header provides time zone | |
| support via <code>std::chrono::tzdb</code>, a complete interface to the | |
| <link xmlns:xlink="http://www.w3.org/1999/xlink" | |
| xlink:href="https://www.iana.org/time-zones">IANA Time Zone Database</link>. | |
| The library supports converting times between UTC and the local time | |
| in a specific time zone, querying UTC offsets and DST information for a | |
| given time zone on a given date, and finding the system's current time zone. | |
| Key entry points are <code>std::chrono::get_tzdb()</code> to access | |
| the database, <code>std::chrono::locate_zone()</code> to look up | |
| a zone by name, and <code>std::chrono::current_zone()</code> to obtain | |
| the system's local time zone. The <code>std::chrono::zoned_time</code> | |
| class template represents a time point in a given time zone. | |
| The database can be reloaded at runtime | |
| via <code>std::chrono::reload_tzdb()</code> to pick up updated zone | |
| data without restarting the program. | |
| </para> | |
| <para> | |
| The <link xmlns:xlink="http://www.w3.org/1999/xlink" | |
| xlink:href="https://howardhinnant.github.io/date/tz.html">Time Zone Database | |
| Parser</link> by Howard E. Hinnant is a valuable source of information and | |
| examples of usage for the <code>date</code> library, on which the standard | |
| API is based. | |
| </para> | |
| <section xml:id="zone.db.zic" xreflabel="tzdb uses zic format"><info><title>tzdb uses zic format</title></info> | |
| <para> | |
| When support is enabled (which is default) the time zone database class, | |
| <code>tzdb</code>, uses the <link xmlns:xlink="http://www.w3.org/1999/xlink" | |
| xlink:href="https://man7.org/linux/man-pages/man8/zic.8.html#FILES"> | |
| <code>zic</code> file format</link>, both as the format of the input | |
| files, and for in-memory representation. This results in a reduced | |
| memory footprint for many programs, as time zone data is stored in | |
| a compact form until needed by the application. | |
| </para> | |
| <para> | |
| The transitions to/from DST (Daylight Savings Time) are generated and | |
| cached on the fly, when information | |
| for a given zone is requested. Consequently, the initial request for | |
| UTC conversion for a given <code>time_zone</code> object is slower. | |
| To mitigate this, a <code>time_zone</code> can be expanded for a | |
| particular time range at the start | |
| of the program (and after each reload), by iterating over the | |
| <code>sys_info</code> sequence, as in the example below. | |
| </para> | |
| <programlisting> | |
| void | |
| expand_zone(const std::chrono::time_zone* tz, | |
| const std::chrono::sys_seconds start, | |
| const std::chrono::sys_seconds end) | |
| { | |
| std::chrono::sys_seconds time = start; | |
| while (time < end) { | |
| const std::chrono::sys_info& info = tz->get_info(time); | |
| time = info.end + std::chrono::seconds(1); | |
| } | |
| } | |
| </programlisting> | |
| </section> | |
| <section xml:id="zone.current" xreflabel="current zone"><info><title>current zone</title></info> | |
| <para> | |
| The <code>time_zone</code> pointer returned from | |
| <code>std::chrono::current_zone</code>, is determined by looking up | |
| (by <code>std::chrono::locate_zone</code>) IANA zone name | |
| determined as follows (for platforms other than AIX and Windows): | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| On systems supporting <code>readlink</code>, suffix components of the | |
| path of the file linked by <code>/etc/localtime</code>. The suffixes | |
| are matched in the order of increasing length, starting from the final | |
| component, until the match is found in the time zone database. | |
| Any repeated slashes (<code>//</code>) are eliminated. | |
| </listitem> | |
| <listitem> | |
| Names stored in the files <code>/etc/timezone</code> (Debian | |
| derivatives) or <code>/var/db/zoneinfo</code> (FreeBSD) in that order. | |
| </listitem> | |
| <listitem> | |
| Values for <code>TIMEZONE</code> and <code>ZONE</code> keys in | |
| <code>/etc/sysconfig/clock</code>. | |
| </listitem> | |
| <listitem> | |
| <code>UTC</code>. | |
| </listitem> | |
| </itemizedlist> | |
| <para> | |
| For AIX, the value of <code>TZ</code> environment value is used, with | |
| fallback to <code>UTC</code>. | |
| </para> | |
| <para> | |
| On Windows <code>TimeZoneKeyName</code> is mapped to the IANA zone, using | |
| internal mapping hard-coded in library, with fallback to <code>UTC</code>: | |
| </para> | |
| <itemizedlist> | |
| <listitem> | |
| If the returned <code>TimeZoneKeyName</code> is empty or DST is disabled, | |
| then a value based on <code>Bias</code> is returned: <code>Etc/UTC</code> | |
| for zero, <code>Etc/GMT+/-N</code> for value that is multiply of 60, | |
| and empty string otherwise. | |
| </listitem> | |
| <listitem> | |
| If the mapping contains a single entry for <code>TimeZoneKeyName</code>, | |
| that name is used. | |
| </listitem> | |
| <listitem> | |
| If <code>TimeZoneKeyName</code> corresponds to multiple IANA zones, | |
| a 2-letter country code is used, retrieved by applying <code>GetGeoInfoW</code> | |
| on the result of <code>GetUserGeoID(GEOCLASS_NATION)</code>. | |
| If determining the country code fails, or no entry exists for a given code, | |
| the first mapping entry (<code>001</code>) is returned. | |
| </listitem> | |
| </itemizedlist> | |
| </section> | |
| <section xml:id="zone.db.sources" xreflabel="data sources"><info><title>data sources</title></info> | |
| <para> | |
| Depending on the build configuration (see | |
| <code>--with-libstdcxx-zoneinfo=</code> documentation in | |
| <xref linkend="manual.intro.setup.configure">Configure section</xref>). | |
| the content of the time zone database is sourced from | |
| <filename>tzdata.zi</filename> and <filename>leapseconds</filename> files | |
| located in <emphasis>zoneinfo_dir</emphasis>, or from static information | |
| embedded in the library. | |
| </para> | |
| <para> | |
| By default, <emphasis>zoneinfo_dir</emphasis> is set to the | |
| system-specific default directory (if a suitable dir is known for target), | |
| usually <code>/usr/share/zoneinfo</code>. If no such directory | |
| exists, or it does not contain the required files in the correct format, | |
| embedded static data is used as fallback. | |
| </para> | |
| <para> | |
| In addition to <code>--with-libstdcxx-zoneinfo=</code> configure option | |
| (used during GCC build), the path of <emphasis>zoneinfo_dir</emphasis> | |
| can be overridden by the application by providing a definition of the | |
| <code>__gnu_cxx::zoneinfo_dir_override()</code> function. The | |
| returned path should be a directory that contains <code>tzdata.zi</code> | |
| and <code>leapseconds</code> files in the | |
| <link xmlns:xlink="http://www.w3.org/1999/xlink" | |
| xlink:href="https://man7.org/linux/man-pages/man8/zic.8.html#FILES"> | |
| <code>zic</code> format</link>. | |
| </para> | |
| <para> | |
| The embedded timezone information corresponds to the copy of the | |
| IANA database at the time of the release, and its version can be queried | |
| using <code>std::chrono::get_tzdb().version</code>. | |
| </para> | |
| <para> | |
| The full time zone database can be disabled when GCC is configured, | |
| in which case a minimal time zone database is provided. This minimal | |
| database can be identified by <code>chrono::get_tzdb().version</code> | |
| being set to <code>"ersatz"</code>. This database contains leapseconds | |
| data, <code>Etc/UTC</code>, <code>Etc/GMT</code> zones, and their aliases | |
| (<code>Etc/Zulu</code>, <code>Etc/UCT</code>, <code>Etc/Universal</code>, | |
| <code>Etc/Greenwich</code>, <code>Etc/GMT0</code>, <code>Etc/GMT+0</code>, | |
| <code>Etc/GMT-0</code>). This information is sufficient to support | |
| conversion between <code>utc_clock</code> and <code>sys_clock</code>, | |
| as well as a <code>UTC</code> fallback for <code>current_zone</code> | |
| (<xref linkend="zone.current">link</xref>). | |
| </para> | |
| </section> | |
| <section xml:id="zone.db.iterator" xreflabel="tzdb_list::const_iterator extends lifetime"> | |
| <info><title>tzdb_list::const_iterator extends lifetime</title></info> | |
| <para> | |
| The <code>std::chrono::reload_tzdb()</code> function may be used to load | |
| updated content of the <code>tzdata.zi</code> and <code>leapseconds</code> | |
| files from <emphasis>zoneinfo_dir</emphasis> (if | |
| <xref linkend="zone.db.sources">enabled</xref>). If the version is different | |
| (<code>std::chrono::remote_version() != std::chrono::get_tzdb().version</code>), | |
| a new element is added at the front of the <code>tzdb_list</code>. | |
| This new database is used for subsequent calls to <code>current_zone</code> | |
| and <code>locate_zone</code>. | |
| </para> | |
| <para> | |
| The above process is thread-safe, and does not invalidate nor change any | |
| pre-existing pointers to <code>time_zone</code> objects. However, for a | |
| long-running application it may lead to accumulation of time zone data, | |
| and thus increased memory usage. In most cases, this is acceptable even | |
| for long-running applications, due to infrequent updates to the IANA database, | |
| and the reduced footprint of the libstdc++ implementation (see | |
| <xref linkend="zone.db.zic">link</xref>). | |
| </para> | |
| <para> | |
| If accumulating old <code>tzdb</code> databases is not acceptable | |
| (e.g. due to memory constraints), entries | |
| may be removed from <code>tzdb_list</code> using <code>tzdb_list::erase_after</code>. | |
| When using this function, you are responsible for ensuring that the application | |
| is no longer using any <code>time_zone*</code> to a removed database. | |
| If you erase a <code>tzdb</code> while some part of the application is still | |
| using it (or one of its <code>time_zone</code> objects) you will create | |
| a dangling pointer, leading to undefined behaviour. | |
| To make <code>tzdb_list::erase_after</code> safer, libstdc++ provides an | |
| <emphasis>extension</emphasis> that avoids creating dangling pointers. | |
| The <code>tzdb_list</code> uses <code>shared_ptr<tzdb></code> to | |
| refer to each entry in the list, and <code>tzdb_list::const_iterator</code> | |
| also uses a <code>shared_ptr<tzdb></code> to refer to its target. | |
| This means that iterators into the list share ownership of the list elements, | |
| so that erasing an element from the list does not destroy it if there are | |
| any iterators which share ownership of the element. The application can | |
| use this to ensure that <code>tzdb</code> and <code>time_zone</code> | |
| objects are not destroyed while they're still being used. The lifetime | |
| of a <code>tzdb</code> that is still in use can be extended by holding | |
| onto a <code>tzdb_list::const_iterator</code> that refers to it. | |
| </para> | |
| </section> | |
| </section> | |
| </chapter> |