Skip to content

Commit f78f93b

Browse files
committed
[libc++][chrono] Adds tzdb_list implementation.
This is the first step to implement time zone support in libc++. This adds the complete tzdb_list class and a minimal tzdb class. The tzdb class only contains the version, which is used by reload_tzdb. Next to these classes it contains documentation and build system support needed for time zone support. The code depends on the IANA Time Zone Database, which should be available on the platform used or provided by the libc++ vendors. The code is labeled as experimental since there will be ABI breaks during development; the tzdb class needs to have the standard headers. Implements parts of: - P0355 Extending <chrono> to Calendars and Time Zones Addresses: - LWG3319 Properly reference specification of IANA time zone database Reviewed By: #libc, ldionne Differential Revision: https://reviews.llvm.org/D154282
1 parent 460840c commit f78f93b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1354
-9
lines changed

libcxx/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,24 @@ option(LIBCXX_ENABLE_WIDE_CHARACTERS
8787
support the C functionality for wide characters. When wide characters are
8888
not supported, several parts of the library will be disabled, notably the
8989
wide character specializations of std::basic_string." ON)
90+
91+
# To use time zone support in libc++ the platform needs to have the IANA
92+
# database installed. Libc++ will fail to build if this is enabled on a
93+
# platform that does not provide the IANA database. The default is set to the
94+
# current implementation state on the different platforms.
95+
#
96+
# TODO TZDB make the default always ON when most platforms ship with the IANA
97+
# database.
98+
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
99+
set(ENABLE_TIME_ZONE_DATABASE_DEFAULT ON)
100+
else()
101+
set(ENABLE_TIME_ZONE_DATABASE_DEFAULT OFF)
102+
endif()
103+
option(LIBCXX_ENABLE_TIME_ZONE_DATABASE
104+
"Whether to include support for time zones in the library. Disabling
105+
time zone support can be useful when porting to platforms that don't
106+
ship the IANA time zone database. When time zones are not supported,
107+
time zone support in <chrono> will be disabled." ${ENABLE_TIME_ZONE_DATABASE_DEFAULT})
90108
option(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS
91109
"Whether to turn on vendor availability annotations on declarations that depend
92110
on definitions in a shared library. By default, we assume that we're not building
@@ -756,6 +774,7 @@ config_define_if_not(LIBCXX_ENABLE_LOCALIZATION _LIBCPP_HAS_NO_LOCALIZATION)
756774
config_define_if_not(LIBCXX_ENABLE_UNICODE _LIBCPP_HAS_NO_UNICODE)
757775
config_define_if_not(LIBCXX_ENABLE_WIDE_CHARACTERS _LIBCPP_HAS_NO_WIDE_CHARACTERS)
758776
config_define_if_not(LIBCXX_ENABLE_STD_MODULES _LIBCPP_HAS_NO_STD_MODULES)
777+
config_define_if_not(LIBCXX_ENABLE_TIME_ZONE_DATABASE _LIBCPP_HAS_NO_TIME_ZONE_DATABASE)
759778
config_define_if_not(LIBCXX_ENABLE_VENDOR_AVAILABILITY_ANNOTATIONS _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS)
760779
if (LIBCXX_HARDENING_MODE STREQUAL "hardened")
761780
config_define(1 _LIBCPP_ENABLE_HARDENED_MODE_DEFAULT)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
set(LIBCXX_ENABLE_TIME_ZONE_DATABASE OFF CACHE BOOL "")

libcxx/docs/BuildingLibcxx.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,15 @@ libc++ specific options
255255
support for ``wchar_t``. This is especially useful in embedded settings where
256256
C Standard Libraries don't always provide all the usual bells and whistles.
257257

258+
.. option:: LIBCXX_ENABLE_TIME_ZONE_DATABASE:BOOL
259+
260+
**Default**: ``ON``
261+
262+
Whether to include support for time zones in the library. Disabling
263+
time zone support can be useful when porting to platforms that don't
264+
ship the IANA time zone database. When time zones are not supported,
265+
time zone support in <chrono> will be disabled.
266+
258267
.. option:: LIBCXX_INSTALL_LIBRARY_DIR:PATH
259268

260269
**Default**: ``lib${LIBCXX_LIBDIR_SUFFIX}``

libcxx/docs/DesignDocs/TimeZone.rst

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
=================
2+
Time Zone Support
3+
=================
4+
5+
Introduction
6+
============
7+
8+
Starting with C++20 the ``<chrono>`` library has support for time zones.
9+
These are available in the
10+
`IANA Time Zone Database <https://data.iana.org/time-zones/tz-link.html>`_.
11+
This page describes the design decisions and trade-offs made to implement this
12+
feature. This page contains several links with more information regarding the
13+
contents of the IANA database, this page assumes the reader is familiar with
14+
this information.
15+
16+
Which version of the Time Zone Database to use
17+
==============================================
18+
19+
The data of the database is available on several platforms in different forms:
20+
21+
- Typically Unix systems ship the database as
22+
`TZif files <https://www.rfc-editor.org/rfc/rfc8536.html>`_. This format has
23+
3 versions and the ``time_zone_link`` information is not always available.
24+
If available, they are symlinks in the file system.
25+
These files don't provide the database version information. This information
26+
is needed for the functions ``std::chrono:: remote_version()`` and
27+
``std::chrono::reload_tzdb()``.
28+
29+
- On several Unix systems the time zone source files are available. These files
30+
are stored in several regions, mainly the continents. This file contains a
31+
large amount of comment with historical information regarding time zones.
32+
The format is documented in the
33+
`IANA documentation <https://data.iana.org/time-zones/tz-how-to.html>`_
34+
and in the `man page <https://man7.org/linux/man-pages/man8/zic.8.html>`_ of zic.
35+
The disadvantage of this version is that at least Linux versions don't have
36+
the database version information. This information is needed for the functions
37+
``std::chrono:: remote_version()`` and ``std::chrono::reload_tzdb()``.
38+
39+
- On Linux systems ``tzdata.zi`` is available. This contains the same
40+
information as the source files but in one file without the comments. This
41+
file uses the same format as the sources, but shortens the names. For example
42+
``Rule`` is abbreviated to ``R``. This file contains the database version
43+
information.
44+
45+
The disadvantage of the ``TZif`` format (which is a binary format) is that it's
46+
not possible to get the proper ``time_zone_link`` information on all platforms.
47+
The time zone database version number is also missing from ``TZif`` files.
48+
Since the time zone database is supposed to contain both these informations,
49+
``TZif`` files can't be used to create a conforming implementation.
50+
51+
Since it's easier to parse one file than a set of files we decided
52+
to use the ``tzdata.zi``. The other benefit is that the ``tzdata.zi`` file
53+
contains the database version information needed for a conforming
54+
implementation.
55+
56+
The ``tzdata.zi`` file is not available on all platforms as of August 2023, so
57+
some vendors will need to make changes to their platform. Most vendors already
58+
ship the database, so they only need to adjust the packaging of their time zone
59+
package to include the files we require. One notable exception is Windows,
60+
where no IANA time zone database is provided at all. However it's possible for
61+
Windows packagers to add these files to their libc++ packages. The IANA
62+
databases can be
63+
`downloaded <https://data.iana.org/time-zones/releases/>`_.
64+
65+
An alternative would be to ship the database with libc++, either as a file or
66+
compiled in the dylib. The text file is about 112 KB. For now libc++ will not
67+
ship this file. If it's hard to get vendors to ship these files we can
68+
reconsider based on that information.
69+
70+
Leap seconds
71+
------------
72+
73+
For the leap seconds libc++ will use the source file ``leap-seconds.list``.
74+
This file is easier to parse than the ``leapseconds`` file. Both files are
75+
present on Linux, but not always on other platforms. Since these platforms need
76+
to change their packaging for ``tzdata.zi``, adding two instead of one files
77+
seems a small change.
78+
79+
80+
Updating the Time Zone Database
81+
===============================
82+
83+
Per `[time.zone.db.remote]/1 <http://eel.is/c++draft/time.zone#db.remote-1>`_
84+
85+
.. code-block:: text
86+
87+
The local time zone database is that supplied by the implementation when the
88+
program first accesses the database, for example via current_zone(). While the
89+
program is running, the implementation may choose to update the time zone
90+
database. This update shall not impact the program in any way unless the
91+
program calls the functions in this subclause. This potentially updated time
92+
zone database is referred to as the remote time zone database.
93+
94+
There is an update mechanism in libc++, however this is not done automatically.
95+
Invoking the function ``std::chrono::remote_version()`` will parse the version
96+
information of the ``tzdata.zi`` file and return that information. Similarly,
97+
``std::chrono::reload_tzdb()`` will parse the ``tzdata.zi`` and
98+
``leap-seconds.list`` again. This makes it possible to update the database if
99+
needed by the application and gives the user full power over the update policy.
100+
101+
This approach has several advantages:
102+
103+
- It is simple to implement.
104+
- The library does not need to start a periodic background process to poll
105+
changes to the filesystem. When using a background process, it may become
106+
active when the application is busy with its core task, taking away resources
107+
from that task.
108+
- If there is no threading available this polling
109+
becomes more involved. For example, query the file every *x* calls to
110+
``std::chrono::get_tzdb()``. This mean calls to ``std::chrono::get_tzdb()``
111+
would have different performance characteristics.
112+
113+
The small drawback is:
114+
115+
- On platforms with threading enabled updating the database may take longer.
116+
On these platforms the remote database could have been loaded in a background
117+
process.
118+
119+
Another issue with the automatic update is that it may not be considered
120+
Standard compliant, since the Standard uses the wording "This update shall not
121+
impact the program in any way". Using resources could be considered as
122+
impacting the program.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
.. _implementation-defined-behavior:
2+
3+
===============================
4+
Implementation-defined behavior
5+
===============================
6+
7+
Contains the implementation details of the implementation-defined behavior in
8+
libc++. Implementation-defined is mandated to be documented by the Standard.
9+
10+
.. note:
11+
This page is far from complete.
12+
13+
14+
Implementation-defined behavior
15+
===============================
16+
17+
Updating the Time Zone Database
18+
-------------------------------
19+
20+
The Standard allows implementations to automatically update the
21+
*remote time zone database*. Libc++ opts not to do that. Instead calling
22+
23+
- ``std::chrono::remote_version()`` will update the version information of the
24+
*remote time zone database*,
25+
- ``std::chrono::reload_tzdb()``, if needed, will update the entire
26+
*remote time zone database*.
27+
28+
This offers a way for users to update the *remote time zone database* and
29+
give them full control over the process.
30+
31+
Listed in the index of implementation-defined behavior
32+
======================================================
33+
34+
The order of the entries matches the entries in the
35+
`draft of the Standard <http://eel.is/c++draft/impldefindex>`_.

libcxx/docs/Status/Cxx20.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,15 @@ Paper Status
4949
.. [#note-P0883.2] P0883: ``ATOMIC_FLAG_INIT`` was marked deprecated in version 14.0, but was undeprecated with the implementation of LWG3659 in version 15.0.
5050
.. [#note-P2231] P2231: Optional is complete. The changes to variant haven't been implemented yet.
5151
.. [#note-P0660] P0660: Section 32.3 Stop Tokens is complete. ``jthread`` hasn't been implemented yet.
52+
.. [#note-P0355] P0355: The implementation status is:
53+
54+
* ``Calendars`` mostly done in Clang 7
55+
* ``Input parsers`` not done
56+
* ``Stream output`` Obsolete due to `P1361R2 <https://wg21.link/P1361R2>`_ "Integration of chrono with text formatting"
57+
* ``Time zone and leap seconds`` In Progress
58+
* ``TAI clock`` not done
59+
* ``GPS clock`` not done
60+
* ``UTC clock`` not done
5261
5362
.. _issues-status-cxx20:
5463

libcxx/docs/Status/Cxx20Issues.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@
241241
"`3316 <https://wg21.link/LWG3316>`__","Correctly define epoch for ``utc_clock``\ / ``utc_timepoint``\ ","Prague","","","|chrono|"
242242
"`3317 <https://wg21.link/LWG3317>`__","Incorrect ``operator<<``\ for floating-point durations","Prague","","","|chrono|"
243243
"`3318 <https://wg21.link/LWG3318>`__","Clarify whether clocks can represent time before their epoch","Prague","","","|chrono|"
244-
"`3319 <https://wg21.link/LWG3319>`__","Properly reference specification of IANA time zone database","Prague","","","|chrono|"
244+
"`3319 <https://wg21.link/LWG3319>`__","Properly reference specification of IANA time zone database","Prague","|Nothing To Do|","","|chrono|"
245245
"`3320 <https://wg21.link/LWG3320>`__","``span::cbegin/cend``\ methods produce different results than ``std::[ranges::]cbegin/cend``\ ","Prague","|Complete|",""
246246
"`3321 <https://wg21.link/LWG3321>`__","``uninitialized_construct_using_allocator``\ should use ``construct_at``\ ","Prague","|Complete|","16.0"
247247
"`3323 <https://wg21.link/LWG3323>`__","``*has-tuple-element*``\ helper concept needs ``convertible_to``\ ","Prague","|Complete|","16.0","|ranges|"

libcxx/docs/Status/Cxx20Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
"`P0768R1 <https://wg21.link/P0768R1>`__","CWG","Library Support for the Spaceship (Comparison) Operator","Albuquerque","|Complete|",""
1818
"`P0777R1 <https://wg21.link/P0777R1>`__","LWG","Treating Unnecessary ``decay``\ ","Albuquerque","|Complete|","7.0"
1919
"`P0122R7 <https://wg21.link/P0122R7>`__","LWG","<span>","Jacksonville","|Complete|","7.0"
20-
"`P0355R7 <https://wg21.link/P0355R7>`__","LWG","Extending chrono to Calendars and Time Zones","Jacksonville","|In Progress|",""
20+
"`P0355R7 <https://wg21.link/P0355R7>`__","LWG","Extending chrono to Calendars and Time Zones","Jacksonville","|Partial| [#note-P0355]_",""
2121
"`P0551R3 <https://wg21.link/P0551R3>`__","LWG","Thou Shalt Not Specialize ``std``\ Function Templates!","Jacksonville","|Complete|","11.0"
2222
"`P0753R2 <https://wg21.link/P0753R2>`__","LWG","Manipulators for C++ Synchronized Buffered Ostream","Jacksonville","",""
2323
"`P0754R2 <https://wg21.link/P0754R2>`__","LWG","<version>","Jacksonville","|Complete|","7.0"

libcxx/docs/UsingLibcxx.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,13 @@ which no dialect declares as such (See the second form described above).
369369
* ``byteswap``
370370
* ``cbrt``
371371
* ``ceil``
372+
* ``chrono::tzdb_list::begin``
373+
* ``chrono::tzdb_list::cbegin``
374+
* ``chrono::tzdb_list::cend``
375+
* ``chrono::tzdb_list::end``
376+
* ``chrono::get_tzdb_list``
377+
* ``chrono::get_tzdb``
378+
* ``chrono::remote_version``
372379
* ``clamp``
373380
* ``copysign``
374381
* ``count_if``

libcxx/docs/index.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Getting Started with libc++
4040
BuildingLibcxx
4141
TestingLibcxx
4242
Contributing
43+
ImplementationDefinedBehavior
4344
Modules
4445
Hardening
4546
ReleaseProcedure
@@ -193,6 +194,7 @@ Design Documents
193194
DesignDocs/UniquePtrTrivialAbi
194195
DesignDocs/UnspecifiedBehaviorRandomization
195196
DesignDocs/VisibilityMacros
197+
DesignDocs/TimeZone
196198

197199

198200
Build Bots and Test Coverage

libcxx/include/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ set(files
283283
__chrono/steady_clock.h
284284
__chrono/system_clock.h
285285
__chrono/time_point.h
286+
__chrono/tzdb.h
287+
__chrono/tzdb_list.h
286288
__chrono/weekday.h
287289
__chrono/year.h
288290
__chrono/year_month.h

libcxx/include/__availability

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@
174174
// # define _LIBCPP_AVAILABILITY_HAS_NO_PMR
175175
# define _LIBCPP_AVAILABILITY_PMR
176176

177+
// This controls the availability of the C++20 time zone database.
178+
// The parser code is built in the library.
179+
// # define _LIBCPP_AVAILABILITY_HAS_NO_TZDB
180+
# define _LIBCPP_AVAILABILITY_TZDB
181+
177182
#elif defined(__APPLE__)
178183

179184
// shared_mutex and shared_timed_mutex
@@ -348,6 +353,9 @@
348353
# define _LIBCPP_AVAILABILITY_PMR
349354
# endif
350355

356+
# define _LIBCPP_AVAILABILITY_HAS_NO_TZDB
357+
# define _LIBCPP_AVAILABILITY_TZDB __attribute__((unavailable))
358+
351359
#else
352360

353361
// ...New vendors can add availability markup here...

libcxx/include/__chrono/tzdb.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
11+
12+
#ifndef _LIBCPP___CHRONO_TZDB_H
13+
#define _LIBCPP___CHRONO_TZDB_H
14+
15+
#include <version>
16+
// Enable the contents of the header only when libc++ was built with experimental features enabled.
17+
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
18+
19+
# include <string>
20+
21+
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22+
# pragma GCC system_header
23+
# endif
24+
25+
_LIBCPP_BEGIN_NAMESPACE_STD
26+
27+
# if _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM) && \
28+
!defined(_LIBCPP_HAS_NO_LOCALIZATION)
29+
30+
namespace chrono {
31+
32+
struct _LIBCPP_AVAILABILITY_TZDB tzdb {
33+
string version;
34+
};
35+
36+
} // namespace chrono
37+
38+
# endif // _LIBCPP_STD_VER >= 20 && !defined(_LIBCPP_HAS_NO_TIME_ZONE_DATABASE) && !defined(_LIBCPP_HAS_NO_FILESYSTEM)
39+
// && !defined(_LIBCPP_HAS_NO_LOCALIZATION)
40+
41+
_LIBCPP_END_NAMESPACE_STD
42+
43+
#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
44+
45+
#endif // _LIBCPP___CHRONO_TZDB_H

0 commit comments

Comments
 (0)