aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/cctz
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:45:01 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:01 +0300
commit2d37894b1b037cf24231090eda8589bbb44fb6fc (patch)
treebe835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/cctz
parent718c552901d703c502ccbefdfc3c9028d608b947 (diff)
downloadydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/cctz')
-rw-r--r--contrib/libs/cctz/CONTRIBUTING.md58
-rw-r--r--contrib/libs/cctz/LICENSE.txt406
-rw-r--r--contrib/libs/cctz/README.md454
-rw-r--r--contrib/libs/cctz/include/cctz/civil_time.h14
-rw-r--r--contrib/libs/cctz/include/cctz/civil_time_detail.h190
-rw-r--r--contrib/libs/cctz/include/cctz/time_zone.h210
-rw-r--r--contrib/libs/cctz/include/cctz/zone_info_source.h14
-rw-r--r--contrib/libs/cctz/src/civil_time_detail.cc30
-rw-r--r--contrib/libs/cctz/src/time_zone_fixed.cc106
-rw-r--r--contrib/libs/cctz/src/time_zone_fixed.h10
-rw-r--r--contrib/libs/cctz/src/time_zone_format.cc550
-rw-r--r--contrib/libs/cctz/src/time_zone_if.cc12
-rw-r--r--contrib/libs/cctz/src/time_zone_if.h38
-rw-r--r--contrib/libs/cctz/src/time_zone_impl.cc68
-rw-r--r--contrib/libs/cctz/src/time_zone_impl.h40
-rw-r--r--contrib/libs/cctz/src/time_zone_info.cc602
-rw-r--r--contrib/libs/cctz/src/time_zone_info.h38
-rw-r--r--contrib/libs/cctz/src/time_zone_libc.cc484
-rw-r--r--contrib/libs/cctz/src/time_zone_libc.h14
-rw-r--r--contrib/libs/cctz/src/time_zone_lookup.cc192
-rw-r--r--contrib/libs/cctz/src/time_zone_posix.cc12
-rw-r--r--contrib/libs/cctz/src/time_zone_posix.h52
-rw-r--r--contrib/libs/cctz/src/tzfile.h32
-rw-r--r--contrib/libs/cctz/src/zone_info_source.cc146
-rw-r--r--contrib/libs/cctz/test/civil_time_test.cc72
-rw-r--r--contrib/libs/cctz/test/time_zone_format_test.cc3176
-rw-r--r--contrib/libs/cctz/test/time_zone_lookup_test.cc694
-rw-r--r--contrib/libs/cctz/test/ya.make20
-rw-r--r--contrib/libs/cctz/tzdata/factory.cpp2
-rw-r--r--contrib/libs/cctz/ya.make60
30 files changed, 3898 insertions, 3898 deletions
diff --git a/contrib/libs/cctz/CONTRIBUTING.md b/contrib/libs/cctz/CONTRIBUTING.md
index ceb5bbddfa..cf0912ea86 100644
--- a/contrib/libs/cctz/CONTRIBUTING.md
+++ b/contrib/libs/cctz/CONTRIBUTING.md
@@ -1,29 +1,29 @@
-Want to contribute? Great! First, read this page (including the small print at
-the end).
-
-### Before you contribute
-
-Before we can use your code, you must sign the [Google Individual Contributor
-License
-Agreement](https://developers.google.com/open-source/cla/individual?csw=1)
-(CLA), which you can do online. The CLA is necessary mainly because you own the
-copyright to your changes, even after your contribution becomes part of our
-codebase, so we need your permission to use and distribute your code. We also
-need to be sure of various other things&mdash;for instance that you'll tell us
-if you know that your code infringes on other people's patents. You don't have
-to sign the CLA until after you've submitted your code for review and a member
-has approved it, but you must do it before we can put your code into our
-codebase. Before you start working on a larger contribution, you should get in
-touch with us first through the issue tracker with your idea so that we can help
-out and possibly guide you. Coordinating up front makes it much easier to avoid
-frustration later on.
-
-### Code reviews
-
-All submissions, including submissions by project members, require review. We
-use Github pull requests for this purpose.
-
-### The small print
-
-Contributions made by corporations are covered by a different agreement than the
-one above, the Software Grant and Corporate Contributor License Agreement.
+Want to contribute? Great! First, read this page (including the small print at
+the end).
+
+### Before you contribute
+
+Before we can use your code, you must sign the [Google Individual Contributor
+License
+Agreement](https://developers.google.com/open-source/cla/individual?csw=1)
+(CLA), which you can do online. The CLA is necessary mainly because you own the
+copyright to your changes, even after your contribution becomes part of our
+codebase, so we need your permission to use and distribute your code. We also
+need to be sure of various other things&mdash;for instance that you'll tell us
+if you know that your code infringes on other people's patents. You don't have
+to sign the CLA until after you've submitted your code for review and a member
+has approved it, but you must do it before we can put your code into our
+codebase. Before you start working on a larger contribution, you should get in
+touch with us first through the issue tracker with your idea so that we can help
+out and possibly guide you. Coordinating up front makes it much easier to avoid
+frustration later on.
+
+### Code reviews
+
+All submissions, including submissions by project members, require review. We
+use Github pull requests for this purpose.
+
+### The small print
+
+Contributions made by corporations are covered by a different agreement than the
+one above, the Software Grant and Corporate Contributor License Agreement.
diff --git a/contrib/libs/cctz/LICENSE.txt b/contrib/libs/cctz/LICENSE.txt
index b7bf950ee7..ccd61dcfe3 100644
--- a/contrib/libs/cctz/LICENSE.txt
+++ b/contrib/libs/cctz/LICENSE.txt
@@ -1,203 +1,203 @@
-
- Apache License
- Version 2.0, January 2004
- https://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
-
- END OF TERMS AND CONDITIONS
-
- APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
- Copyright [yyyy] [name of copyright owner]
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- https://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
+
+ Apache License
+ Version 2.0, January 2004
+ https://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ https://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/contrib/libs/cctz/README.md b/contrib/libs/cctz/README.md
index baf079b20e..b535fd65d9 100644
--- a/contrib/libs/cctz/README.md
+++ b/contrib/libs/cctz/README.md
@@ -1,227 +1,227 @@
-This is not an official Google product.
-
-# Overview
-
-CCTZ contains two libraries that cooperate with `<chrono>` to give C++
-programmers all the necessary tools for computing with dates, times, and time
-zones in a simple and correct manner. The libraries in CCTZ are:
-
-* **The Civil-Time Library** &mdash; This is a header-only library that
- supports computing with human-scale time, such as dates (which are
- represented by the `cctz::civil_day` class). This library is declared in
- [`include/cctz/civil_time.h`](https://github.com/google/cctz/blob/master/include/cctz/civil_time.h).
-* **The Time-Zone Library** &mdash; This library uses the IANA time zone
- database that is installed on the system to convert between *absolute time*
- and *civil time*. This library is declared in
- [`include/cctz/time_zone.h`](https://github.com/google/cctz/blob/master/include/cctz/time_zone.h).
-
-These libraries are currently known to work on **Linux**, **Mac OS X**, and
-**Android**.
-
-They will also work on **Windows** if you install the zoneinfo files. We are
-interested, though, in an implementation of the cctz::TimeZoneIf interface that
-calls the Windows time APIs instead. Please contact us if you're interested in
-contributing.
-
-# Getting Started
-
-CCTZ is best built and tested using the [Bazel](https://bazel.io) build system
-and the [Google Test](https://github.com/google/googletest) framework. (There is
-also a simple [`Makefile`](https://github.com/google/cctz/blob/master/Makefile)
-and a
-[`CMakeLists.txt`](https://github.com/google/cctz/blob/master/CMakeLists.txt)
-that should work if you're unable to use Bazel.)
-
-1. Download/install
- [Bazel](https://docs.bazel.build/versions/master/install.html)
-2. Get the cctz source: `git clone https://github.com/google/cctz.git` then `cd
- cctz`
-3. Build cctz and run the tests: `bazel test :all`
-
-With CMake:
-
-1. Make sure you have CMake >= 2.8.12 installed.
-2. Get the cctz source: `git clone https://github.com/google/cctz.git` then `cd
- cctz`.
-3. Build cctz so that is can be used by shared libraries and run the tests (use
- `-DBUILD_TESTING=OFF` to skip the tests):
-
- mkdir mybuild
- cd mybuild
- cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=ON ..
- cmake --build . --config Release
- ctest
- cmake --build . --config Release --target install
-
-4. Use in your CMake-based project with:
-
- ```cmake
- find_package(cctz REQUIRED)
- add_executable(mytarget file.cc)
- target_link_libraries(mytarget cctz::cctz)
- ```
-
-Note: When using CCTZ in your own project, you might find it easiest to compile
-the sources using your existing build system.
-
-Next Steps:
-
-1. See the documentation for the libraries in CCTZ:
- * Civil Time:
- [`include/cctz/civil_time.h`](https://github.com/google/cctz/blob/master/include/cctz/civil_time.h)
- * Time Zone:
- [`include/cctz/time_zone.h`](https://github.com/google/cctz/blob/master/include/cctz/time_zone.h)
-2. Look at the examples in https://github.com/google/cctz/tree/master/examples
-3. Join our mailing list to ask questions and keep informed of changes:
- * https://groups.google.com/forum/#!forum/cctz
-
-# Fundamental Concepts
-
-*[The concepts presented here describe general truths about the problem domain
-and are library and language agnostic. An understanding of these concepts helps
-the programmer correctly reason about even the most-complicated time-programming
-challenges and produce the simplest possible solutions.]*
-
-There are two main ways to think about time in a computer program: as *absolute
-time*, and as *civil time*. Both have their uses and it is important to
-understand when each is appropriate. Absolute and civil times may be converted
-back and forth using a *time zone* &mdash; this is the only way to correctly
-convert between them. Let us now look more deeply at the three main concepts of
-time programming: Absolute Time, Civil Time, and Time Zone.
-
-*Absolute time* uniquely and universally represents a specific instant in time.
-It has no notion of calendars, or dates, or times of day. Instead, it is a
-measure of the passage of real time, typically as a simple count of ticks since
-some epoch. Absolute times are independent of all time zones and do not suffer
-from human-imposed complexities such as daylight-saving time (DST). Many C++
-types exist to represent absolute times, classically `time_t` and more recently
-`std::chrono::time_point`.
-
-*Civil time* is the legally recognized representation of time for ordinary
-affairs (cf. https://www.merriam-webster.com/dictionary/civil). It is a
-human-scale representation of time that consists of the six fields &mdash; year,
-month, day, hour, minute, and second (sometimes shortened to "YMDHMS") &mdash;
-and it follows the rules of the Proleptic Gregorian Calendar, with 24-hour days
-divided into 60-minute hours and 60-second minutes. Like absolute times, civil
-times are also independent of all time zones and their related complexities
-(e.g., DST). While `std::tm` contains the six civil-time fields (YMDHMS), plus a
-few more, it does not have behavior to enforce the rules of civil time.
-
-*Time zones* are geo-political regions within which human-defined rules are
-shared to convert between the absolute-time and civil-time domains. A time
-zone's rules include things like the region's offset from the UTC time standard,
-daylight-saving adjustments, and short abbreviation strings. Time zones often
-have a history of disparate rules that apply only for certain periods, because
-the rules may change at the whim of a region's local government. For this
-reason, time-zone rules are usually compiled into data snapshots that are used
-at runtime to perform conversions between absolute and civil times. There is
-currently no C++ standard library supporting arbitrary time zones.
-
-In order for programmers to reason about and program applications that correctly
-deal with these concepts, they must have a library that correctly implements the
-above concepts. CCTZ adds to the existing C++11 `<chrono>` library to fully
-implement the above concepts.
-
-* Absolute time &mdash; This is implemented by the existing C++11
- [`<chrono>`](https://en.cppreference.com/w/cpp/chrono) library without
- modification. For example, an absolute point in time is represented by a
- `std::chrono::time_point`.
-* Civil time &mdash; This is implemented by the
- [`include/cctz/civil_time.h`](https://github.com/google/cctz/blob/master/include/cctz/civil_time.h)
- library that is provided as part of CCTZ. For example, a "date" is
- represented by a `cctz::civil_day`.
-* Time zone &mdash; This is implemented by the
- [`include/cctz/time_zone.h`](https://github.com/google/cctz/blob/master/include/cctz/time_zone.h)
- library that is provided as part of CCTZ. For example, a time zone is
- represented by an instance of the class `cctz::time_zone`.
-
-# Examples
-
-## Hello February 2016
-
-This "hello world" example uses a for-loop to iterate the days from the first of
-February until the month of March. Each day is streamed to output, and if the
-day happens to be the 29th, we also output the day of the week.
-
-```
-#include <iostream>
-#include "cctz/civil_time.h"
-
-int main() {
- for (cctz::civil_day d(2016, 2, 1); d < cctz::civil_month(2016, 3); ++d) {
- std::cout << "Hello " << d;
- if (d.day() == 29) {
- std::cout << " <- leap day is a " << cctz::get_weekday(d);
- }
- std::cout << "\n";
- }
-}
-```
-
-The output of the above program is
-
-```
-Hello 2016-02-01
-Hello 2016-02-02
-Hello 2016-02-03
-[...]
-Hello 2016-02-27
-Hello 2016-02-28
-Hello 2016-02-29 <- leap day is a Monday
-```
-
-## One giant leap
-
-This example shows how to use all three libraries (`<chrono>`, civil time, and
-time zone) together. In this example, we know that viewers in New York watched
-Neil Armstrong's first walk on the moon on July 20, 1969 at 10:56 PM. But we'd
-like to see what time it was for our friend watching in Sydney, Australia.
-
-```
-#include <iostream>
-#include "cctz/civil_time.h"
-#include "cctz/time_zone.h"
-
-int main() {
- cctz::time_zone nyc;
- cctz::load_time_zone("America/New_York", &nyc);
-
- // Converts the input civil time in NYC to an absolute time.
- const auto moon_walk =
- cctz::convert(cctz::civil_second(1969, 7, 20, 22, 56, 0), nyc);
-
- std::cout << "Moon walk in NYC: "
- << cctz::format("%Y-%m-%d %H:%M:%S %Ez\n", moon_walk, nyc);
-
- cctz::time_zone syd;
- if (!cctz::load_time_zone("Australia/Sydney", &syd)) return -1;
- std::cout << "Moon walk in SYD: "
- << cctz::format("%Y-%m-%d %H:%M:%S %Ez\n", moon_walk, syd);
-}
-```
-
-The output of the above program is
-
-```
-Moon walk in NYC: 1969-07-20 22:56:00 -04:00
-Moon walk in SYD: 1969-07-21 12:56:00 +10:00
-```
-
-This example shows that the absolute time (the `std::chrono::time_point`) of the
-first walk on the moon is the same no matter the time zone of the viewer (the
-same time point is used in both calls to `format()`). The only difference is the
-time zone in which the `moon_walk` time point is rendered. And in this case we
-can see that our friend in Sydney was probably eating lunch while watching that
-historic event.
-
-# References
-
-* CCTZ [FAQ](https://github.com/google/cctz/wiki/FAQ)
-* See also the [Time Programming Fundamentals](https://youtu.be/2rnIHsqABfM)
- talk from CppCon 2015 ([slides available here](https://goo.gl/ofof4N)). This
- talk mostly describes the older CCTZ v1 API, but the *concepts* are the
- same.
-* ISO C++ proposal to standardize the Civil-Time Library:
- https://github.com/devjgm/papers/blob/master/d0215r1.md
-* ISO C++ proposal to standardize the Time-Zone Library:
- https://github.com/devjgm/papers/blob/master/d0216r1.md
+This is not an official Google product.
+
+# Overview
+
+CCTZ contains two libraries that cooperate with `<chrono>` to give C++
+programmers all the necessary tools for computing with dates, times, and time
+zones in a simple and correct manner. The libraries in CCTZ are:
+
+* **The Civil-Time Library** &mdash; This is a header-only library that
+ supports computing with human-scale time, such as dates (which are
+ represented by the `cctz::civil_day` class). This library is declared in
+ [`include/cctz/civil_time.h`](https://github.com/google/cctz/blob/master/include/cctz/civil_time.h).
+* **The Time-Zone Library** &mdash; This library uses the IANA time zone
+ database that is installed on the system to convert between *absolute time*
+ and *civil time*. This library is declared in
+ [`include/cctz/time_zone.h`](https://github.com/google/cctz/blob/master/include/cctz/time_zone.h).
+
+These libraries are currently known to work on **Linux**, **Mac OS X**, and
+**Android**.
+
+They will also work on **Windows** if you install the zoneinfo files. We are
+interested, though, in an implementation of the cctz::TimeZoneIf interface that
+calls the Windows time APIs instead. Please contact us if you're interested in
+contributing.
+
+# Getting Started
+
+CCTZ is best built and tested using the [Bazel](https://bazel.io) build system
+and the [Google Test](https://github.com/google/googletest) framework. (There is
+also a simple [`Makefile`](https://github.com/google/cctz/blob/master/Makefile)
+and a
+[`CMakeLists.txt`](https://github.com/google/cctz/blob/master/CMakeLists.txt)
+that should work if you're unable to use Bazel.)
+
+1. Download/install
+ [Bazel](https://docs.bazel.build/versions/master/install.html)
+2. Get the cctz source: `git clone https://github.com/google/cctz.git` then `cd
+ cctz`
+3. Build cctz and run the tests: `bazel test :all`
+
+With CMake:
+
+1. Make sure you have CMake >= 2.8.12 installed.
+2. Get the cctz source: `git clone https://github.com/google/cctz.git` then `cd
+ cctz`.
+3. Build cctz so that is can be used by shared libraries and run the tests (use
+ `-DBUILD_TESTING=OFF` to skip the tests):
+
+ mkdir mybuild
+ cd mybuild
+ cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_POSITION_INDEPENDENT_CODE=ON ..
+ cmake --build . --config Release
+ ctest
+ cmake --build . --config Release --target install
+
+4. Use in your CMake-based project with:
+
+ ```cmake
+ find_package(cctz REQUIRED)
+ add_executable(mytarget file.cc)
+ target_link_libraries(mytarget cctz::cctz)
+ ```
+
+Note: When using CCTZ in your own project, you might find it easiest to compile
+the sources using your existing build system.
+
+Next Steps:
+
+1. See the documentation for the libraries in CCTZ:
+ * Civil Time:
+ [`include/cctz/civil_time.h`](https://github.com/google/cctz/blob/master/include/cctz/civil_time.h)
+ * Time Zone:
+ [`include/cctz/time_zone.h`](https://github.com/google/cctz/blob/master/include/cctz/time_zone.h)
+2. Look at the examples in https://github.com/google/cctz/tree/master/examples
+3. Join our mailing list to ask questions and keep informed of changes:
+ * https://groups.google.com/forum/#!forum/cctz
+
+# Fundamental Concepts
+
+*[The concepts presented here describe general truths about the problem domain
+and are library and language agnostic. An understanding of these concepts helps
+the programmer correctly reason about even the most-complicated time-programming
+challenges and produce the simplest possible solutions.]*
+
+There are two main ways to think about time in a computer program: as *absolute
+time*, and as *civil time*. Both have their uses and it is important to
+understand when each is appropriate. Absolute and civil times may be converted
+back and forth using a *time zone* &mdash; this is the only way to correctly
+convert between them. Let us now look more deeply at the three main concepts of
+time programming: Absolute Time, Civil Time, and Time Zone.
+
+*Absolute time* uniquely and universally represents a specific instant in time.
+It has no notion of calendars, or dates, or times of day. Instead, it is a
+measure of the passage of real time, typically as a simple count of ticks since
+some epoch. Absolute times are independent of all time zones and do not suffer
+from human-imposed complexities such as daylight-saving time (DST). Many C++
+types exist to represent absolute times, classically `time_t` and more recently
+`std::chrono::time_point`.
+
+*Civil time* is the legally recognized representation of time for ordinary
+affairs (cf. https://www.merriam-webster.com/dictionary/civil). It is a
+human-scale representation of time that consists of the six fields &mdash; year,
+month, day, hour, minute, and second (sometimes shortened to "YMDHMS") &mdash;
+and it follows the rules of the Proleptic Gregorian Calendar, with 24-hour days
+divided into 60-minute hours and 60-second minutes. Like absolute times, civil
+times are also independent of all time zones and their related complexities
+(e.g., DST). While `std::tm` contains the six civil-time fields (YMDHMS), plus a
+few more, it does not have behavior to enforce the rules of civil time.
+
+*Time zones* are geo-political regions within which human-defined rules are
+shared to convert between the absolute-time and civil-time domains. A time
+zone's rules include things like the region's offset from the UTC time standard,
+daylight-saving adjustments, and short abbreviation strings. Time zones often
+have a history of disparate rules that apply only for certain periods, because
+the rules may change at the whim of a region's local government. For this
+reason, time-zone rules are usually compiled into data snapshots that are used
+at runtime to perform conversions between absolute and civil times. There is
+currently no C++ standard library supporting arbitrary time zones.
+
+In order for programmers to reason about and program applications that correctly
+deal with these concepts, they must have a library that correctly implements the
+above concepts. CCTZ adds to the existing C++11 `<chrono>` library to fully
+implement the above concepts.
+
+* Absolute time &mdash; This is implemented by the existing C++11
+ [`<chrono>`](https://en.cppreference.com/w/cpp/chrono) library without
+ modification. For example, an absolute point in time is represented by a
+ `std::chrono::time_point`.
+* Civil time &mdash; This is implemented by the
+ [`include/cctz/civil_time.h`](https://github.com/google/cctz/blob/master/include/cctz/civil_time.h)
+ library that is provided as part of CCTZ. For example, a "date" is
+ represented by a `cctz::civil_day`.
+* Time zone &mdash; This is implemented by the
+ [`include/cctz/time_zone.h`](https://github.com/google/cctz/blob/master/include/cctz/time_zone.h)
+ library that is provided as part of CCTZ. For example, a time zone is
+ represented by an instance of the class `cctz::time_zone`.
+
+# Examples
+
+## Hello February 2016
+
+This "hello world" example uses a for-loop to iterate the days from the first of
+February until the month of March. Each day is streamed to output, and if the
+day happens to be the 29th, we also output the day of the week.
+
+```
+#include <iostream>
+#include "cctz/civil_time.h"
+
+int main() {
+ for (cctz::civil_day d(2016, 2, 1); d < cctz::civil_month(2016, 3); ++d) {
+ std::cout << "Hello " << d;
+ if (d.day() == 29) {
+ std::cout << " <- leap day is a " << cctz::get_weekday(d);
+ }
+ std::cout << "\n";
+ }
+}
+```
+
+The output of the above program is
+
+```
+Hello 2016-02-01
+Hello 2016-02-02
+Hello 2016-02-03
+[...]
+Hello 2016-02-27
+Hello 2016-02-28
+Hello 2016-02-29 <- leap day is a Monday
+```
+
+## One giant leap
+
+This example shows how to use all three libraries (`<chrono>`, civil time, and
+time zone) together. In this example, we know that viewers in New York watched
+Neil Armstrong's first walk on the moon on July 20, 1969 at 10:56 PM. But we'd
+like to see what time it was for our friend watching in Sydney, Australia.
+
+```
+#include <iostream>
+#include "cctz/civil_time.h"
+#include "cctz/time_zone.h"
+
+int main() {
+ cctz::time_zone nyc;
+ cctz::load_time_zone("America/New_York", &nyc);
+
+ // Converts the input civil time in NYC to an absolute time.
+ const auto moon_walk =
+ cctz::convert(cctz::civil_second(1969, 7, 20, 22, 56, 0), nyc);
+
+ std::cout << "Moon walk in NYC: "
+ << cctz::format("%Y-%m-%d %H:%M:%S %Ez\n", moon_walk, nyc);
+
+ cctz::time_zone syd;
+ if (!cctz::load_time_zone("Australia/Sydney", &syd)) return -1;
+ std::cout << "Moon walk in SYD: "
+ << cctz::format("%Y-%m-%d %H:%M:%S %Ez\n", moon_walk, syd);
+}
+```
+
+The output of the above program is
+
+```
+Moon walk in NYC: 1969-07-20 22:56:00 -04:00
+Moon walk in SYD: 1969-07-21 12:56:00 +10:00
+```
+
+This example shows that the absolute time (the `std::chrono::time_point`) of the
+first walk on the moon is the same no matter the time zone of the viewer (the
+same time point is used in both calls to `format()`). The only difference is the
+time zone in which the `moon_walk` time point is rendered. And in this case we
+can see that our friend in Sydney was probably eating lunch while watching that
+historic event.
+
+# References
+
+* CCTZ [FAQ](https://github.com/google/cctz/wiki/FAQ)
+* See also the [Time Programming Fundamentals](https://youtu.be/2rnIHsqABfM)
+ talk from CppCon 2015 ([slides available here](https://goo.gl/ofof4N)). This
+ talk mostly describes the older CCTZ v1 API, but the *concepts* are the
+ same.
+* ISO C++ proposal to standardize the Civil-Time Library:
+ https://github.com/devjgm/papers/blob/master/d0215r1.md
+* ISO C++ proposal to standardize the Time-Zone Library:
+ https://github.com/devjgm/papers/blob/master/d0216r1.md
diff --git a/contrib/libs/cctz/include/cctz/civil_time.h b/contrib/libs/cctz/include/cctz/civil_time.h
index ada9915833..57bd86cc06 100644
--- a/contrib/libs/cctz/include/cctz/civil_time.h
+++ b/contrib/libs/cctz/include/cctz/civil_time.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
#ifndef CCTZ_CIVIL_TIME_H_
#define CCTZ_CIVIL_TIME_H_
-#include "cctz/civil_time_detail.h"
+#include "cctz/civil_time_detail.h"
namespace cctz {
@@ -148,7 +148,7 @@ namespace cctz {
//
// All civil-time types have accessors for all six of the civil-time fields:
// year, month, day, hour, minute, and second. Recall that fields inferior to
-// the type's alignment will be set to their minimum valid value.
+// the type's alignment will be set to their minimum valid value.
//
// civil_day d(2015, 6, 28);
// // d.year() == 2015
@@ -277,7 +277,7 @@ using civil_second = detail::civil_second;
//
using detail::weekday;
-// Returns the weekday for the given civil-time value.
+// Returns the weekday for the given civil-time value.
//
// civil_day a(2015, 8, 13);
// weekday wd = get_weekday(a); // wd == weekday::thursday
@@ -304,14 +304,14 @@ using detail::get_weekday;
//
// civil_day d = ...
// // Gets the following Thursday if d is not already Thursday
-// civil_day thurs1 = next_weekday(d - 1, weekday::thursday);
+// civil_day thurs1 = next_weekday(d - 1, weekday::thursday);
// // Gets the previous Thursday if d is not already Thursday
-// civil_day thurs2 = prev_weekday(d + 1, weekday::thursday);
+// civil_day thurs2 = prev_weekday(d + 1, weekday::thursday);
//
using detail::next_weekday;
using detail::prev_weekday;
-// Returns the day-of-year for the given civil-time value.
+// Returns the day-of-year for the given civil-time value.
//
// civil_day a(2015, 1, 1);
// int yd_jan_1 = get_yearday(a); // yd_jan_1 = 1
diff --git a/contrib/libs/cctz/include/cctz/civil_time_detail.h b/contrib/libs/cctz/include/cctz/civil_time_detail.h
index d843c7b8e1..ea1a1dc276 100644
--- a/contrib/libs/cctz/include/cctz/civil_time_detail.h
+++ b/contrib/libs/cctz/include/cctz/civil_time_detail.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,8 +20,8 @@
#include <ostream>
#include <type_traits>
-// Disable constexpr support unless we are in C++14 mode.
-#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
+// Disable constexpr support unless we are in C++14 mode.
+#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
#define CONSTEXPR_D constexpr // data
#define CONSTEXPR_F constexpr // function
#define CONSTEXPR_M constexpr // member
@@ -101,64 +101,64 @@ CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept {
CONSTEXPR_F fields n_day(year_t y, month_t m, diff_t d, diff_t cd,
hour_t hh, minute_t mm, second_t ss) noexcept {
- year_t ey = y % 400;
- const year_t oey = ey;
- ey += (cd / 146097) * 400;
+ year_t ey = y % 400;
+ const year_t oey = ey;
+ ey += (cd / 146097) * 400;
cd %= 146097;
if (cd < 0) {
- ey -= 400;
+ ey -= 400;
cd += 146097;
}
- ey += (d / 146097) * 400;
+ ey += (d / 146097) * 400;
d = d % 146097 + cd;
if (d > 0) {
if (d > 146097) {
- ey += 400;
+ ey += 400;
d -= 146097;
}
} else {
if (d > -365) {
// We often hit the previous year when stepping a civil time backwards,
// so special case it to avoid counting up by 100/4/1-year chunks.
- ey -= 1;
- d += days_per_year(ey, m);
+ ey -= 1;
+ d += days_per_year(ey, m);
} else {
- ey -= 400;
+ ey -= 400;
d += 146097;
}
}
if (d > 365) {
- for (;;) {
- int n = days_per_century(ey, m);
- if (d <= n) break;
+ for (;;) {
+ int n = days_per_century(ey, m);
+ if (d <= n) break;
d -= n;
- ey += 100;
+ ey += 100;
}
- for (;;) {
- int n = days_per_4years(ey, m);
- if (d <= n) break;
+ for (;;) {
+ int n = days_per_4years(ey, m);
+ if (d <= n) break;
d -= n;
- ey += 4;
+ ey += 4;
}
- for (;;) {
- int n = days_per_year(ey, m);
- if (d <= n) break;
+ for (;;) {
+ int n = days_per_year(ey, m);
+ if (d <= n) break;
d -= n;
- ++ey;
+ ++ey;
}
}
if (d > 28) {
- for (;;) {
- int n = days_per_month(ey, m);
- if (d <= n) break;
+ for (;;) {
+ int n = days_per_month(ey, m);
+ if (d <= n) break;
d -= n;
if (++m > 12) {
- ++ey;
+ ++ey;
m = 1;
}
}
}
- return fields(y + (ey - oey), m, static_cast<day_t>(d), hh, mm, ss);
+ return fields(y + (ey - oey), m, static_cast<day_t>(d), hh, mm, ss);
}
CONSTEXPR_F fields n_mon(year_t y, diff_t m, diff_t d, diff_t cd,
hour_t hh, minute_t mm, second_t ss) noexcept {
@@ -363,12 +363,12 @@ class civil_time {
: civil_time(ct.f_) {}
// Factories for the maximum/minimum representable civil_time.
- static CONSTEXPR_F civil_time (max)() {
- const auto max_year = (std::numeric_limits<std::int_least64_t>::max)();
+ static CONSTEXPR_F civil_time (max)() {
+ const auto max_year = (std::numeric_limits<std::int_least64_t>::max)();
return civil_time(max_year, 12, 31, 23, 59, 59);
}
- static CONSTEXPR_F civil_time (min)() {
- const auto min_year = (std::numeric_limits<std::int_least64_t>::min)();
+ static CONSTEXPR_F civil_time (min)() {
+ const auto min_year = (std::numeric_limits<std::int_least64_t>::min)();
return civil_time(min_year, 1, 1, 0, 0, 0);
}
@@ -382,10 +382,10 @@ class civil_time {
// Assigning arithmetic.
CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept {
- return *this = *this + n;
+ return *this = *this + n;
}
CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
- return *this = *this - n;
+ return *this = *this - n;
}
CONSTEXPR_M civil_time& operator++() noexcept {
return *this += 1;
@@ -405,18 +405,18 @@ class civil_time {
}
// Binary arithmetic operators.
- friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept {
- return civil_time(step(T{}, a.f_, n));
+ friend CONSTEXPR_F civil_time operator+(civil_time a, diff_t n) noexcept {
+ return civil_time(step(T{}, a.f_, n));
}
- friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept {
- return a + n;
+ friend CONSTEXPR_F civil_time operator+(diff_t n, civil_time a) noexcept {
+ return a + n;
}
- friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept {
- return n != (std::numeric_limits<diff_t>::min)()
- ? civil_time(step(T{}, a.f_, -n))
- : civil_time(step(T{}, step(T{}, a.f_, -(n + 1)), 1));
+ friend CONSTEXPR_F civil_time operator-(civil_time a, diff_t n) noexcept {
+ return n != (std::numeric_limits<diff_t>::min)()
+ ? civil_time(step(T{}, a.f_, -n))
+ : civil_time(step(T{}, step(T{}, a.f_, -(n + 1)), 1));
}
- friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept {
+ friend CONSTEXPR_F diff_t operator-(civil_time lhs, civil_time rhs) noexcept {
return difference(T{}, lhs.f_, rhs.f_);
}
@@ -434,8 +434,8 @@ class civil_time {
// Disallows difference between differently aligned types.
// auto n = civil_day(...) - civil_hour(...); // would be confusing.
-template <typename T, typename U>
-CONSTEXPR_F diff_t operator-(civil_time<T>, civil_time<U>) = delete;
+template <typename T, typename U>
+CONSTEXPR_F diff_t operator-(civil_time<T>, civil_time<U>) = delete;
using civil_year = civil_time<year_tag>;
using civil_month = civil_time<month_tag>;
@@ -503,71 +503,71 @@ enum class weekday {
sunday,
};
-CONSTEXPR_F weekday get_weekday(const civil_second& cs) noexcept {
- CONSTEXPR_D weekday k_weekday_by_mon_off[13] = {
- weekday::monday, weekday::tuesday, weekday::wednesday,
- weekday::thursday, weekday::friday, weekday::saturday,
- weekday::sunday, weekday::monday, weekday::tuesday,
- weekday::wednesday, weekday::thursday, weekday::friday,
+CONSTEXPR_F weekday get_weekday(const civil_second& cs) noexcept {
+ CONSTEXPR_D weekday k_weekday_by_mon_off[13] = {
+ weekday::monday, weekday::tuesday, weekday::wednesday,
+ weekday::thursday, weekday::friday, weekday::saturday,
+ weekday::sunday, weekday::monday, weekday::tuesday,
+ weekday::wednesday, weekday::thursday, weekday::friday,
weekday::saturday,
};
CONSTEXPR_D int k_weekday_offsets[1 + 12] = {
-1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4,
};
- year_t wd = 2400 + (cs.year() % 400) - (cs.month() < 3);
- wd += wd / 4 - wd / 100 + wd / 400;
- wd += k_weekday_offsets[cs.month()] + cs.day();
- return k_weekday_by_mon_off[wd % 7 + 6];
+ year_t wd = 2400 + (cs.year() % 400) - (cs.month() < 3);
+ wd += wd / 4 - wd / 100 + wd / 400;
+ wd += k_weekday_offsets[cs.month()] + cs.day();
+ return k_weekday_by_mon_off[wd % 7 + 6];
}
////////////////////////////////////////////////////////////////////////
CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept {
- CONSTEXPR_D weekday k_weekdays_forw[14] = {
- weekday::monday, weekday::tuesday, weekday::wednesday,
- weekday::thursday, weekday::friday, weekday::saturday,
- weekday::sunday, weekday::monday, weekday::tuesday,
- weekday::wednesday, weekday::thursday, weekday::friday,
- weekday::saturday, weekday::sunday,
- };
- weekday base = get_weekday(cd);
- for (int i = 0;; ++i) {
- if (base == k_weekdays_forw[i]) {
- for (int j = i + 1;; ++j) {
- if (wd == k_weekdays_forw[j]) {
- return cd + (j - i);
- }
- }
- }
- }
+ CONSTEXPR_D weekday k_weekdays_forw[14] = {
+ weekday::monday, weekday::tuesday, weekday::wednesday,
+ weekday::thursday, weekday::friday, weekday::saturday,
+ weekday::sunday, weekday::monday, weekday::tuesday,
+ weekday::wednesday, weekday::thursday, weekday::friday,
+ weekday::saturday, weekday::sunday,
+ };
+ weekday base = get_weekday(cd);
+ for (int i = 0;; ++i) {
+ if (base == k_weekdays_forw[i]) {
+ for (int j = i + 1;; ++j) {
+ if (wd == k_weekdays_forw[j]) {
+ return cd + (j - i);
+ }
+ }
+ }
+ }
}
CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept {
- CONSTEXPR_D weekday k_weekdays_back[14] = {
- weekday::sunday, weekday::saturday, weekday::friday,
- weekday::thursday, weekday::wednesday, weekday::tuesday,
- weekday::monday, weekday::sunday, weekday::saturday,
- weekday::friday, weekday::thursday, weekday::wednesday,
- weekday::tuesday, weekday::monday,
- };
- weekday base = get_weekday(cd);
- for (int i = 0;; ++i) {
- if (base == k_weekdays_back[i]) {
- for (int j = i + 1;; ++j) {
- if (wd == k_weekdays_back[j]) {
- return cd - (j - i);
- }
- }
- }
- }
-}
-
-CONSTEXPR_F int get_yearday(const civil_second& cs) noexcept {
+ CONSTEXPR_D weekday k_weekdays_back[14] = {
+ weekday::sunday, weekday::saturday, weekday::friday,
+ weekday::thursday, weekday::wednesday, weekday::tuesday,
+ weekday::monday, weekday::sunday, weekday::saturday,
+ weekday::friday, weekday::thursday, weekday::wednesday,
+ weekday::tuesday, weekday::monday,
+ };
+ weekday base = get_weekday(cd);
+ for (int i = 0;; ++i) {
+ if (base == k_weekdays_back[i]) {
+ for (int j = i + 1;; ++j) {
+ if (wd == k_weekdays_back[j]) {
+ return cd - (j - i);
+ }
+ }
+ }
+ }
+}
+
+CONSTEXPR_F int get_yearday(const civil_second& cs) noexcept {
CONSTEXPR_D int k_month_offsets[1 + 12] = {
-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334,
};
- const int feb29 = (cs.month() > 2 && impl::is_leap_year(cs.year()));
- return k_month_offsets[cs.month()] + feb29 + cs.day();
+ const int feb29 = (cs.month() > 2 && impl::is_leap_year(cs.year()));
+ return k_month_offsets[cs.month()] + feb29 + cs.day();
}
////////////////////////////////////////////////////////////////////////
diff --git a/contrib/libs/cctz/include/cctz/time_zone.h b/contrib/libs/cctz/include/cctz/time_zone.h
index 0ec6fdc71a..4fc1a2a24f 100644
--- a/contrib/libs/cctz/include/cctz/time_zone.h
+++ b/contrib/libs/cctz/include/cctz/time_zone.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,31 +25,31 @@
#include <string>
#include <utility>
-#include "cctz/civil_time.h"
+#include "cctz/civil_time.h"
namespace cctz {
// Convenience aliases. Not intended as public API points.
template <typename D>
using time_point = std::chrono::time_point<std::chrono::system_clock, D>;
-using seconds = std::chrono::duration<std::int_fast64_t>;
-using sys_seconds = seconds; // Deprecated. Use cctz::seconds instead.
+using seconds = std::chrono::duration<std::int_fast64_t>;
+using sys_seconds = seconds; // Deprecated. Use cctz::seconds instead.
namespace detail {
template <typename D>
-inline std::pair<time_point<seconds>, D>
+inline std::pair<time_point<seconds>, D>
split_seconds(const time_point<D>& tp) {
- auto sec = std::chrono::time_point_cast<seconds>(tp);
+ auto sec = std::chrono::time_point_cast<seconds>(tp);
auto sub = tp - sec;
if (sub.count() < 0) {
- sec -= seconds(1);
- sub += seconds(1);
+ sec -= seconds(1);
+ sub += seconds(1);
}
return {sec, std::chrono::duration_cast<D>(sub)};
}
-inline std::pair<time_point<seconds>, seconds>
-split_seconds(const time_point<seconds>& tp) {
- return {tp, seconds::zero()};
+inline std::pair<time_point<seconds>, seconds>
+split_seconds(const time_point<seconds>& tp) {
+ return {tp, seconds::zero()};
}
} // namespace detail
@@ -70,10 +70,10 @@ split_seconds(const time_point<seconds>& tp) {
//
// See also:
// - http://www.iana.org/time-zones
-// - https://en.wikipedia.org/wiki/Zoneinfo
+// - https://en.wikipedia.org/wiki/Zoneinfo
class time_zone {
public:
- time_zone() : time_zone(nullptr) {} // Equivalent to UTC
+ time_zone() : time_zone(nullptr) {} // Equivalent to UTC
time_zone(const time_zone&) = default;
time_zone& operator=(const time_zone&) = default;
@@ -98,7 +98,7 @@ class time_zone {
bool is_dst; // is offset non-standard?
const char* abbr; // time-zone abbreviation (e.g., "PST")
};
- absolute_lookup lookup(const time_point<seconds>& tp) const;
+ absolute_lookup lookup(const time_point<seconds>& tp) const;
template <typename D>
absolute_lookup lookup(const time_point<D>& tp) const {
return lookup(detail::split_seconds(tp).first);
@@ -117,9 +117,9 @@ class time_zone {
// of the given civil-time argument, and the pre, trans, and post
// members will give the absolute time answers using the pre-transition
// offset, the transition point itself, and the post-transition offset,
- // respectively (all three times are equal if kind == UNIQUE). If any
+ // respectively (all three times are equal if kind == UNIQUE). If any
// of these three absolute times is outside the representable range of a
- // time_point<seconds> the field is set to its maximum/minimum value.
+ // time_point<seconds> the field is set to its maximum/minimum value.
//
// Example:
// cctz::time_zone lax;
@@ -151,83 +151,83 @@ class time_zone {
SKIPPED, // the civil time did not exist (pre >= trans > post)
REPEATED, // the civil time was ambiguous (pre < trans <= post)
} kind;
- time_point<seconds> pre; // uses the pre-transition offset
- time_point<seconds> trans; // instant of civil-offset change
- time_point<seconds> post; // uses the post-transition offset
+ time_point<seconds> pre; // uses the pre-transition offset
+ time_point<seconds> trans; // instant of civil-offset change
+ time_point<seconds> post; // uses the post-transition offset
};
civil_lookup lookup(const civil_second& cs) const;
- // Finds the time of the next/previous offset change in this time zone.
- //
- // By definition, next_transition(tp, &trans) returns false when tp has
- // its maximum value, and prev_transition(tp, &trans) returns false
- // when tp has its minimum value. If the zone has no transitions, the
- // result will also be false no matter what the argument.
- //
- // Otherwise, when tp has its minimum value, next_transition(tp, &trans)
- // returns true and sets trans to the first recorded transition. Chains
- // of calls to next_transition()/prev_transition() will eventually return
- // false, but it is unspecified exactly when next_transition(tp, &trans)
- // jumps to false, or what time is set by prev_transition(tp, &trans) for
- // a very distant tp.
- //
- // Note: Enumeration of time-zone transitions is for informational purposes
- // only. Modern time-related code should not care about when offset changes
- // occur.
- //
- // Example:
- // cctz::time_zone nyc;
- // if (!cctz::load_time_zone("America/New_York", &nyc)) { ... }
- // const auto now = std::chrono::system_clock::now();
- // auto tp = cctz::time_point<cctz::seconds>::min();
- // cctz::time_zone::civil_transition trans;
- // while (tp <= now && nyc.next_transition(tp, &trans)) {
- // // transition: trans.from -> trans.to
- // tp = nyc.lookup(trans.to).trans;
- // }
- struct civil_transition {
- civil_second from; // the civil time we jump from
- civil_second to; // the civil time we jump to
- };
- bool next_transition(const time_point<seconds>& tp,
- civil_transition* trans) const;
- template <typename D>
- bool next_transition(const time_point<D>& tp,
- civil_transition* trans) const {
- return next_transition(detail::split_seconds(tp).first, trans);
- }
- bool prev_transition(const time_point<seconds>& tp,
- civil_transition* trans) const;
- template <typename D>
- bool prev_transition(const time_point<D>& tp,
- civil_transition* trans) const {
- return prev_transition(detail::split_seconds(tp).first, trans);
- }
+ // Finds the time of the next/previous offset change in this time zone.
+ //
+ // By definition, next_transition(tp, &trans) returns false when tp has
+ // its maximum value, and prev_transition(tp, &trans) returns false
+ // when tp has its minimum value. If the zone has no transitions, the
+ // result will also be false no matter what the argument.
+ //
+ // Otherwise, when tp has its minimum value, next_transition(tp, &trans)
+ // returns true and sets trans to the first recorded transition. Chains
+ // of calls to next_transition()/prev_transition() will eventually return
+ // false, but it is unspecified exactly when next_transition(tp, &trans)
+ // jumps to false, or what time is set by prev_transition(tp, &trans) for
+ // a very distant tp.
+ //
+ // Note: Enumeration of time-zone transitions is for informational purposes
+ // only. Modern time-related code should not care about when offset changes
+ // occur.
+ //
+ // Example:
+ // cctz::time_zone nyc;
+ // if (!cctz::load_time_zone("America/New_York", &nyc)) { ... }
+ // const auto now = std::chrono::system_clock::now();
+ // auto tp = cctz::time_point<cctz::seconds>::min();
+ // cctz::time_zone::civil_transition trans;
+ // while (tp <= now && nyc.next_transition(tp, &trans)) {
+ // // transition: trans.from -> trans.to
+ // tp = nyc.lookup(trans.to).trans;
+ // }
+ struct civil_transition {
+ civil_second from; // the civil time we jump from
+ civil_second to; // the civil time we jump to
+ };
+ bool next_transition(const time_point<seconds>& tp,
+ civil_transition* trans) const;
+ template <typename D>
+ bool next_transition(const time_point<D>& tp,
+ civil_transition* trans) const {
+ return next_transition(detail::split_seconds(tp).first, trans);
+ }
+ bool prev_transition(const time_point<seconds>& tp,
+ civil_transition* trans) const;
+ template <typename D>
+ bool prev_transition(const time_point<D>& tp,
+ civil_transition* trans) const {
+ return prev_transition(detail::split_seconds(tp).first, trans);
+ }
+
+ // version() and description() provide additional information about the
+ // time zone. The content of each of the returned strings is unspecified,
+ // however, when the IANA Time Zone Database is the underlying data source
+ // the version() string will be in the familar form (e.g, "2018e") or
+ // empty when unavailable.
+ //
+ // Note: These functions are for informational or testing purposes only.
+ std::string version() const; // empty when unknown
+ std::string description() const;
+
+ // Relational operators.
+ friend bool operator==(time_zone lhs, time_zone rhs) {
+ return &lhs.effective_impl() == &rhs.effective_impl();
+ }
+ friend bool operator!=(time_zone lhs, time_zone rhs) {
+ return !(lhs == rhs);
+ }
- // version() and description() provide additional information about the
- // time zone. The content of each of the returned strings is unspecified,
- // however, when the IANA Time Zone Database is the underlying data source
- // the version() string will be in the familar form (e.g, "2018e") or
- // empty when unavailable.
- //
- // Note: These functions are for informational or testing purposes only.
- std::string version() const; // empty when unknown
- std::string description() const;
-
- // Relational operators.
- friend bool operator==(time_zone lhs, time_zone rhs) {
- return &lhs.effective_impl() == &rhs.effective_impl();
- }
- friend bool operator!=(time_zone lhs, time_zone rhs) {
- return !(lhs == rhs);
- }
-
class Impl;
private:
explicit time_zone(const Impl* impl) : impl_(impl) {}
- const Impl& effective_impl() const; // handles implicit UTC
- const Impl* impl_;
+ const Impl& effective_impl() const; // handles implicit UTC
+ const Impl* impl_;
};
// Loads the named time zone. May perform I/O on the initial load.
@@ -241,10 +241,10 @@ time_zone utc_time_zone();
// Returns a time zone that is a fixed offset (seconds east) from UTC.
// Note: If the absolute value of the offset is greater than 24 hours
// you'll get UTC (i.e., zero offset) instead.
-time_zone fixed_time_zone(const seconds& offset);
+time_zone fixed_time_zone(const seconds& offset);
// Returns a time zone representing the local time zone. Falls back to UTC.
-// Note: local_time_zone.name() may only be something like "localtime".
+// Note: local_time_zone.name() may only be something like "localtime".
time_zone local_time_zone();
// Returns the civil time (cctz::civil_second) within the given time zone at
@@ -261,8 +261,8 @@ inline civil_second convert(const time_point<D>& tp, const time_zone& tz) {
// it was either repeated or non-existent), then the returned time_point is
// the best estimate that preserves relative order. That is, this function
// guarantees that if cs1 < cs2, then convert(cs1, tz) <= convert(cs2, tz).
-inline time_point<seconds> convert(const civil_second& cs,
- const time_zone& tz) {
+inline time_point<seconds> convert(const civil_second& cs,
+ const time_zone& tz) {
const time_zone::civil_lookup cl = tz.lookup(cs);
if (cl.kind == time_zone::civil_lookup::SKIPPED) return cl.trans;
return cl.pre;
@@ -270,34 +270,34 @@ inline time_point<seconds> convert(const civil_second& cs,
namespace detail {
using femtoseconds = std::chrono::duration<std::int_fast64_t, std::femto>;
-std::string format(const std::string&, const time_point<seconds>&,
+std::string format(const std::string&, const time_point<seconds>&,
const femtoseconds&, const time_zone&);
bool parse(const std::string&, const std::string&, const time_zone&,
- time_point<seconds>*, femtoseconds*, std::string* err = nullptr);
+ time_point<seconds>*, femtoseconds*, std::string* err = nullptr);
} // namespace detail
// Formats the given time_point in the given cctz::time_zone according to
// the provided format string. Uses strftime()-like formatting options,
// with the following extensions:
//
-// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
-// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
+// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
// - %E#S - Seconds with # digits of fractional precision
// - %E*S - Seconds with full fractional precision (a literal '*')
// - %E#f - Fractional seconds with # digits of precision
// - %E*f - Fractional seconds with full precision (a literal '*')
// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
-// - %ET - The RFC3339 "date-time" separator "T"
+// - %ET - The RFC3339 "date-time" separator "T"
//
-// Note that %E0S behaves like %S, and %E0f produces no characters. In
+// Note that %E0S behaves like %S, and %E0f produces no characters. In
// contrast %E*f always produces at least one digit, which may be '0'.
//
// Note that %Y produces as many characters as it takes to fully render the
// year. A year outside of [-999:9999] when formatted with %E4Y will produce
// more than four characters, just like %Y.
//
-// Tip: Format strings should include the UTC offset (e.g., %z, %Ez, or %E*z)
-// so that the resulting string uniquely identifies an absolute time.
+// Tip: Format strings should include the UTC offset (e.g., %z, %Ez, or %E*z)
+// so that the resulting string uniquely identifies an absolute time.
//
// Example:
// cctz::time_zone lax;
@@ -316,9 +316,9 @@ inline std::string format(const std::string& fmt, const time_point<D>& tp,
// Parses an input string according to the provided format string and
// returns the corresponding time_point. Uses strftime()-like formatting
// options, with the same extensions as cctz::format(), but with the
-// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
-// and %E*z also accept the same inputs, which (along with %z) includes
-// 'z' and 'Z' as synonyms for +00:00. %ET accepts either 'T' or 't'.
+// exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
+// and %E*z also accept the same inputs, which (along with %z) includes
+// 'z' and 'Z' as synonyms for +00:00. %ET accepts either 'T' or 't'.
//
// %Y consumes as many numeric characters as it can, so the matching data
// should always be terminated with a non-numeric. %E4Y always consumes
@@ -332,8 +332,8 @@ inline std::string format(const std::string& fmt, const time_point<D>& tp,
// that represents "1970-01-01 15:45:00.0 +0000".
//
// Note that parse() returns time instants, so it makes most sense to parse
-// fully-specified date/time strings that include a UTC offset (%z, %Ez, or
-// %E*z).
+// fully-specified date/time strings that include a UTC offset (%z, %Ez, or
+// %E*z).
//
// Note also that parse() only heeds the fields year, month, day, hour,
// minute, (fractional) second, and UTC offset. Other fields, like weekday (%a
@@ -362,7 +362,7 @@ inline std::string format(const std::string& fmt, const time_point<D>& tp,
template <typename D>
inline bool parse(const std::string& fmt, const std::string& input,
const time_zone& tz, time_point<D>* tpp) {
- time_point<seconds> sec;
+ time_point<seconds> sec;
detail::femtoseconds fs;
const bool b = detail::parse(fmt, input, tz, &sec, &fs);
if (b) {
@@ -374,8 +374,8 @@ inline bool parse(const std::string& fmt, const std::string& input,
}
// Access to convert functions which are placed in time_zone_if.h
-time_point<seconds> UnixSecondsToTimePoint(std::int_fast64_t);
-std::int_fast64_t TimePointToUnixSeconds(const time_point<seconds>& tp);
+time_point<seconds> UnixSecondsToTimePoint(std::int_fast64_t);
+std::int_fast64_t TimePointToUnixSeconds(const time_point<seconds>& tp);
} // namespace cctz
diff --git a/contrib/libs/cctz/include/cctz/zone_info_source.h b/contrib/libs/cctz/include/cctz/zone_info_source.h
index 50c4b59bfa..08e91b3c1f 100644
--- a/contrib/libs/cctz/include/cctz/zone_info_source.h
+++ b/contrib/libs/cctz/include/cctz/zone_info_source.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,15 +25,15 @@ namespace cctz {
// A stdio-like interface for providing zoneinfo data for a particular zone.
class ZoneInfoSource {
public:
- virtual ~ZoneInfoSource();
+ virtual ~ZoneInfoSource();
virtual std::size_t Read(void* ptr, std::size_t size) = 0; // like fread()
virtual int Skip(std::size_t offset) = 0; // like fseek()
-
- // Until the zoneinfo data supports versioning information, we provide
- // a way for a ZoneInfoSource to indicate it out-of-band. The default
- // implementation returns an empty string.
- virtual std::string Version() const;
+
+ // Until the zoneinfo data supports versioning information, we provide
+ // a way for a ZoneInfoSource to indicate it out-of-band. The default
+ // implementation returns an empty string.
+ virtual std::string Version() const;
};
} // namespace cctz
diff --git a/contrib/libs/cctz/src/civil_time_detail.cc b/contrib/libs/cctz/src/civil_time_detail.cc
index d825298712..b6856b8df4 100644
--- a/contrib/libs/cctz/src/civil_time_detail.cc
+++ b/contrib/libs/cctz/src/civil_time_detail.cc
@@ -1,19 +1,19 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cctz/civil_time_detail.h"
-#include "cctz/civil_time_detail.h"
-
#include <iomanip>
#include <ostream>
#include <sstream>
diff --git a/contrib/libs/cctz/src/time_zone_fixed.cc b/contrib/libs/cctz/src/time_zone_fixed.cc
index 6f2f6d6cf5..ce79822ada 100644
--- a/contrib/libs/cctz/src/time_zone_fixed.cc
+++ b/contrib/libs/cctz/src/time_zone_fixed.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,7 +15,7 @@
#include "time_zone_fixed.h"
#include <algorithm>
-#include <cassert>
+#include <cassert>
#include <chrono>
#include <cstring>
#include <string>
@@ -25,16 +25,16 @@ namespace cctz {
namespace {
// The prefix used for the internal names of fixed-offset zones.
-const char kFixedZonePrefix[] = "Fixed/UTC";
-
-const char kDigits[] = "0123456789";
-
-char* Format02d(char* p, int v) {
- *p++ = kDigits[(v / 10) % 10];
- *p++ = kDigits[v % 10];
- return p;
-}
-
+const char kFixedZonePrefix[] = "Fixed/UTC";
+
+const char kDigits[] = "0123456789";
+
+char* Format02d(char* p, int v) {
+ *p++ = kDigits[(v / 10) % 10];
+ *p++ = kDigits[v % 10];
+ return p;
+}
+
int Parse02d(const char* p) {
if (const char* ap = std::strchr(kDigits, *p)) {
int v = static_cast<int>(ap - kDigits);
@@ -47,17 +47,17 @@ int Parse02d(const char* p) {
} // namespace
-bool FixedOffsetFromName(const std::string& name, seconds* offset) {
+bool FixedOffsetFromName(const std::string& name, seconds* offset) {
if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
- *offset = seconds::zero();
+ *offset = seconds::zero();
return true;
}
- const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
- const char* const ep = kFixedZonePrefix + prefix_len;
- if (name.size() != prefix_len + 9) // <prefix>+99:99:99
+ const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
+ const char* const ep = kFixedZonePrefix + prefix_len;
+ if (name.size() != prefix_len + 9) // <prefix>+99:99:99
return false;
- if (!std::equal(kFixedZonePrefix, ep, name.begin()))
+ if (!std::equal(kFixedZonePrefix, ep, name.begin()))
return false;
const char* np = name.data() + prefix_len;
if (np[0] != '+' && np[0] != '-')
@@ -74,57 +74,57 @@ bool FixedOffsetFromName(const std::string& name, seconds* offset) {
secs += ((hours * 60) + mins) * 60;
if (secs > 24 * 60 * 60) return false; // outside supported offset range
- *offset = seconds(secs * (np[0] == '-' ? -1 : 1)); // "-" means west
+ *offset = seconds(secs * (np[0] == '-' ? -1 : 1)); // "-" means west
return true;
}
-std::string FixedOffsetToName(const seconds& offset) {
- if (offset == seconds::zero()) return "UTC";
+std::string FixedOffsetToName(const seconds& offset) {
+ if (offset == seconds::zero()) return "UTC";
if (offset < std::chrono::hours(-24) || offset > std::chrono::hours(24)) {
// We don't support fixed-offset zones more than 24 hours
// away from UTC to avoid complications in rendering such
// offsets and to (somewhat) limit the total number of zones.
return "UTC";
}
- int offset_seconds = static_cast<int>(offset.count());
- const char sign = (offset_seconds < 0 ? '-' : '+');
- int offset_minutes = offset_seconds / 60;
- offset_seconds %= 60;
+ int offset_seconds = static_cast<int>(offset.count());
+ const char sign = (offset_seconds < 0 ? '-' : '+');
+ int offset_minutes = offset_seconds / 60;
+ offset_seconds %= 60;
if (sign == '-') {
- if (offset_seconds > 0) {
- offset_seconds -= 60;
- offset_minutes += 1;
+ if (offset_seconds > 0) {
+ offset_seconds -= 60;
+ offset_minutes += 1;
}
- offset_seconds = -offset_seconds;
- offset_minutes = -offset_minutes;
+ offset_seconds = -offset_seconds;
+ offset_minutes = -offset_minutes;
}
- int offset_hours = offset_minutes / 60;
- offset_minutes %= 60;
- const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
- char buf[prefix_len + sizeof("-24:00:00")];
- char* ep = std::copy(kFixedZonePrefix, kFixedZonePrefix + prefix_len, buf);
- *ep++ = sign;
- ep = Format02d(ep, offset_hours);
- *ep++ = ':';
- ep = Format02d(ep, offset_minutes);
- *ep++ = ':';
- ep = Format02d(ep, offset_seconds);
- *ep++ = '\0';
- assert(ep == buf + sizeof(buf));
+ int offset_hours = offset_minutes / 60;
+ offset_minutes %= 60;
+ const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
+ char buf[prefix_len + sizeof("-24:00:00")];
+ char* ep = std::copy(kFixedZonePrefix, kFixedZonePrefix + prefix_len, buf);
+ *ep++ = sign;
+ ep = Format02d(ep, offset_hours);
+ *ep++ = ':';
+ ep = Format02d(ep, offset_minutes);
+ *ep++ = ':';
+ ep = Format02d(ep, offset_seconds);
+ *ep++ = '\0';
+ assert(ep == buf + sizeof(buf));
return buf;
}
-std::string FixedOffsetToAbbr(const seconds& offset) {
+std::string FixedOffsetToAbbr(const seconds& offset) {
std::string abbr = FixedOffsetToName(offset);
- const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
- if (abbr.size() == prefix_len + 9) { // <prefix>+99:99:99
- abbr.erase(0, prefix_len); // +99:99:99
- abbr.erase(6, 1); // +99:9999
- abbr.erase(3, 1); // +999999
- if (abbr[5] == '0' && abbr[6] == '0') { // +999900
- abbr.erase(5, 2); // +9999
- if (abbr[3] == '0' && abbr[4] == '0') { // +9900
- abbr.erase(3, 2); // +99
+ const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
+ if (abbr.size() == prefix_len + 9) { // <prefix>+99:99:99
+ abbr.erase(0, prefix_len); // +99:99:99
+ abbr.erase(6, 1); // +99:9999
+ abbr.erase(3, 1); // +999999
+ if (abbr[5] == '0' && abbr[6] == '0') { // +999900
+ abbr.erase(5, 2); // +9999
+ if (abbr[3] == '0' && abbr[4] == '0') { // +9900
+ abbr.erase(3, 2); // +99
}
}
}
diff --git a/contrib/libs/cctz/src/time_zone_fixed.h b/contrib/libs/cctz/src/time_zone_fixed.h
index 01210f4788..f37226ff46 100644
--- a/contrib/libs/cctz/src/time_zone_fixed.h
+++ b/contrib/libs/cctz/src/time_zone_fixed.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -17,7 +17,7 @@
#include <string>
-#include "cctz/time_zone.h"
+#include "cctz/time_zone.h"
namespace cctz {
@@ -36,9 +36,9 @@ namespace cctz {
// Note: FixedOffsetFromName() fails on syntax errors or when the parsed
// offset exceeds 24 hours. FixedOffsetToName() and FixedOffsetToAbbr()
// both produce "UTC" when the argument offset exceeds 24 hours.
-bool FixedOffsetFromName(const std::string& name, seconds* offset);
-std::string FixedOffsetToName(const seconds& offset);
-std::string FixedOffsetToAbbr(const seconds& offset);
+bool FixedOffsetFromName(const std::string& name, seconds* offset);
+std::string FixedOffsetToName(const seconds& offset);
+std::string FixedOffsetToAbbr(const seconds& offset);
} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_format.cc b/contrib/libs/cctz/src/time_zone_format.cc
index ab3ba55974..b57371314e 100644
--- a/contrib/libs/cctz/src/time_zone_format.cc
+++ b/contrib/libs/cctz/src/time_zone_format.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,23 +13,23 @@
// limitations under the License.
#if !defined(HAS_STRPTIME)
-# if !defined(_MSC_VER) && !defined(__MINGW32__)
+# if !defined(_MSC_VER) && !defined(__MINGW32__)
# define HAS_STRPTIME 1 // assume everyone has strptime() except windows
# endif
#endif
-#if defined(HAS_STRPTIME) && HAS_STRPTIME
-# if !defined(_XOPEN_SOURCE)
-# define _XOPEN_SOURCE // Definedness suffices for strptime.
-# endif
-#endif
-
-#include "cctz/time_zone.h"
-
-// Include time.h directly since, by C++ standards, ctime doesn't have to
-// declare strptime.
-#include <time.h>
-
+#if defined(HAS_STRPTIME) && HAS_STRPTIME
+# if !defined(_XOPEN_SOURCE)
+# define _XOPEN_SOURCE // Definedness suffices for strptime.
+# endif
+#endif
+
+#include "cctz/time_zone.h"
+
+// Include time.h directly since, by C++ standards, ctime doesn't have to
+// declare strptime.
+#include <time.h>
+
#include <cctype>
#include <chrono>
#include <cstddef>
@@ -44,7 +44,7 @@
#include <sstream>
#endif
-#include "cctz/civil_time.h"
+#include "cctz/civil_time.h"
#include "time_zone_if.h"
namespace cctz {
@@ -58,53 +58,53 @@ char* strptime(const char* s, const char* fmt, std::tm* tm) {
std::istringstream input(s);
input >> std::get_time(tm, fmt);
if (input.fail()) return nullptr;
- return const_cast<char*>(s) +
- (input.eof() ? strlen(s) : static_cast<std::size_t>(input.tellg()));
+ return const_cast<char*>(s) +
+ (input.eof() ? strlen(s) : static_cast<std::size_t>(input.tellg()));
}
#endif
-// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
-int ToTmWday(weekday wd) {
- switch (wd) {
- case weekday::sunday:
- return 0;
- case weekday::monday:
- return 1;
- case weekday::tuesday:
- return 2;
- case weekday::wednesday:
- return 3;
- case weekday::thursday:
- return 4;
- case weekday::friday:
- return 5;
- case weekday::saturday:
- return 6;
- }
- return 0; /*NOTREACHED*/
-}
-
-// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday.
-weekday FromTmWday(int tm_wday) {
- switch (tm_wday) {
- case 0:
- return weekday::sunday;
- case 1:
- return weekday::monday;
- case 2:
- return weekday::tuesday;
- case 3:
- return weekday::wednesday;
- case 4:
- return weekday::thursday;
- case 5:
- return weekday::friday;
- case 6:
- return weekday::saturday;
- }
- return weekday::sunday; /*NOTREACHED*/
-}
-
+// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
+int ToTmWday(weekday wd) {
+ switch (wd) {
+ case weekday::sunday:
+ return 0;
+ case weekday::monday:
+ return 1;
+ case weekday::tuesday:
+ return 2;
+ case weekday::wednesday:
+ return 3;
+ case weekday::thursday:
+ return 4;
+ case weekday::friday:
+ return 5;
+ case weekday::saturday:
+ return 6;
+ }
+ return 0; /*NOTREACHED*/
+}
+
+// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday.
+weekday FromTmWday(int tm_wday) {
+ switch (tm_wday) {
+ case 0:
+ return weekday::sunday;
+ case 1:
+ return weekday::monday;
+ case 2:
+ return weekday::tuesday;
+ case 3:
+ return weekday::wednesday;
+ case 4:
+ return weekday::thursday;
+ case 5:
+ return weekday::friday;
+ case 6:
+ return weekday::saturday;
+ }
+ return weekday::sunday; /*NOTREACHED*/
+}
+
std::tm ToTM(const time_zone::absolute_lookup& al) {
std::tm tm{};
tm.tm_sec = al.cs.second();
@@ -122,19 +122,19 @@ std::tm ToTM(const time_zone::absolute_lookup& al) {
tm.tm_year = static_cast<int>(al.cs.year() - 1900);
}
- tm.tm_wday = ToTmWday(get_weekday(al.cs));
- tm.tm_yday = get_yearday(al.cs) - 1;
+ tm.tm_wday = ToTmWday(get_weekday(al.cs));
+ tm.tm_yday = get_yearday(al.cs) - 1;
tm.tm_isdst = al.is_dst ? 1 : 0;
return tm;
}
-// Returns the week of the year [0:53] given a civil day and the day on
-// which weeks are defined to start.
-int ToWeek(const civil_day& cd, weekday week_start) {
- const civil_day d(cd.year() % 400, cd.month(), cd.day());
- return static_cast<int>((d - prev_weekday(civil_year(d), week_start)) / 7);
-}
-
+// Returns the week of the year [0:53] given a civil day and the day on
+// which weeks are defined to start.
+int ToWeek(const civil_day& cd, weekday week_start) {
+ const civil_day d(cd.year() % 400, cd.month(), cd.day());
+ return static_cast<int>((d - prev_weekday(civil_year(d), week_start)) / 7);
+}
+
const char kDigits[] = "0123456789";
// Formats a 64-bit integer in the given field width. Note that it is up
@@ -175,34 +175,34 @@ char* Format02d(char* ep, int v) {
}
// Formats a UTC offset, like +00:00.
-char* FormatOffset(char* ep, int offset, const char* mode) {
- // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
- // generate a "negative zero" when we're formatting a zero offset
- // as the result of a failed load_time_zone().
+char* FormatOffset(char* ep, int offset, const char* mode) {
+ // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
+ // generate a "negative zero" when we're formatting a zero offset
+ // as the result of a failed load_time_zone().
char sign = '+';
- if (offset < 0) {
- offset = -offset; // bounded by 24h so no overflow
+ if (offset < 0) {
+ offset = -offset; // bounded by 24h so no overflow
sign = '-';
}
- const int seconds = offset % 60;
- const int minutes = (offset /= 60) % 60;
- const int hours = offset /= 60;
- const char sep = mode[0];
- const bool ext = (sep != '\0' && mode[1] == '*');
- const bool ccc = (ext && mode[2] == ':');
- if (ext && (!ccc || seconds != 0)) {
- ep = Format02d(ep, seconds);
- *--ep = sep;
- } else {
- // If we're not rendering seconds, sub-minute negative offsets
- // should get a positive sign (e.g., offset=-10s => "+00:00").
- if (hours == 0 && minutes == 0) sign = '+';
- }
- if (!ccc || minutes != 0 || seconds != 0) {
- ep = Format02d(ep, minutes);
- if (sep != '\0') *--ep = sep;
- }
- ep = Format02d(ep, hours);
+ const int seconds = offset % 60;
+ const int minutes = (offset /= 60) % 60;
+ const int hours = offset /= 60;
+ const char sep = mode[0];
+ const bool ext = (sep != '\0' && mode[1] == '*');
+ const bool ccc = (ext && mode[2] == ':');
+ if (ext && (!ccc || seconds != 0)) {
+ ep = Format02d(ep, seconds);
+ *--ep = sep;
+ } else {
+ // If we're not rendering seconds, sub-minute negative offsets
+ // should get a positive sign (e.g., offset=-10s => "+00:00").
+ if (hours == 0 && minutes == 0) sign = '+';
+ }
+ if (!ccc || minutes != 0 || seconds != 0) {
+ ep = Format02d(ep, minutes);
+ if (sep != '\0') *--ep = sep;
+ }
+ ep = Format02d(ep, hours);
*--ep = sign;
return ep;
}
@@ -211,7 +211,7 @@ char* FormatOffset(char* ep, int offset, const char* mode) {
void FormatTM(std::string* out, const std::string& fmt, const std::tm& tm) {
// strftime(3) returns the number of characters placed in the output
// array (which may be 0 characters). It also returns 0 to indicate
- // an error, like the array wasn't large enough. To accommodate this,
+ // an error, like the array wasn't large enough. To accommodate this,
// the following code grows the buffer size from 2x the format string
// length up to 32x.
for (std::size_t i = 2; i != 32; i *= 2) {
@@ -308,12 +308,12 @@ const std::int_fast64_t kExp10[kDigits10_64 + 1] = {
// Uses strftime(3) to format the given Time. The following extended format
// specifiers are also supported:
//
-// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
-// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
+// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
+// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
// - %E#S - Seconds with # digits of fractional precision
// - %E*S - Seconds with full fractional precision (a literal '*')
// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
-// - %ET - The RFC3339 "date-time" separator "T"
+// - %ET - The RFC3339 "date-time" separator "T"
//
// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
// handled internally for performance reasons. strftime(3) is slow due to
@@ -326,7 +326,7 @@ const std::int_fast64_t kExp10[kDigits10_64 + 1] = {
// not support the tm_gmtoff and tm_zone extensions to std::tm.
//
// Requires that zero() <= fs < seconds(1).
-std::string format(const std::string& format, const time_point<seconds>& tp,
+std::string format(const std::string& format, const time_point<seconds>& tp,
const detail::femtoseconds& fs, const time_zone& tz) {
std::string result;
result.reserve(format.size()); // A reasonable guess for the result size.
@@ -378,7 +378,7 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
if (cur == end || (cur - percent) % 2 == 0) continue;
// Simple specifiers that we handle ourselves.
- if (strchr("YmdeUuWwHMSzZs%", *cur)) {
+ if (strchr("YmdeUuWwHMSzZs%", *cur)) {
if (cur - 1 != pending) {
FormatTM(&result, std::string(pending, cur - 1), tm);
}
@@ -399,22 +399,22 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
if (*cur == 'e' && *bp == '0') *bp = ' '; // for Windows
result.append(bp, static_cast<std::size_t>(ep - bp));
break;
- case 'U':
- bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday));
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
- case 'u':
- bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7);
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
- case 'W':
- bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday));
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
- case 'w':
- bp = Format64(ep, 0, tm.tm_wday);
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
+ case 'U':
+ bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday));
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'u':
+ bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7);
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'W':
+ bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday));
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'w':
+ bp = Format64(ep, 0, tm.tm_wday);
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
case 'H':
bp = Format02d(ep, al.cs.hour());
result.append(bp, static_cast<std::size_t>(ep - bp));
@@ -428,7 +428,7 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
result.append(bp, static_cast<std::size_t>(ep - bp));
break;
case 'z':
- bp = FormatOffset(ep, al.offset, "");
+ bp = FormatOffset(ep, al.offset, "");
result.append(bp, static_cast<std::size_t>(ep - bp));
break;
case 'Z':
@@ -438,79 +438,79 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
bp = Format64(ep, 0, ToUnixSeconds(tp));
result.append(bp, static_cast<std::size_t>(ep - bp));
break;
- case '%':
- result.push_back('%');
- break;
+ case '%':
+ result.push_back('%');
+ break;
}
pending = ++cur;
continue;
}
- // More complex specifiers that we handle ourselves.
- if (*cur == ':' && cur + 1 != end) {
- if (*(cur + 1) == 'z') {
- // Formats %:z.
- if (cur - 1 != pending) {
- FormatTM(&result, std::string(pending, cur - 1), tm);
- }
- bp = FormatOffset(ep, al.offset, ":");
- result.append(bp, static_cast<std::size_t>(ep - bp));
- pending = cur += 2;
- continue;
- }
- if (*(cur + 1) == ':' && cur + 2 != end) {
- if (*(cur + 2) == 'z') {
- // Formats %::z.
- if (cur - 1 != pending) {
- FormatTM(&result, std::string(pending, cur - 1), tm);
- }
- bp = FormatOffset(ep, al.offset, ":*");
- result.append(bp, static_cast<std::size_t>(ep - bp));
- pending = cur += 3;
- continue;
- }
- if (*(cur + 2) == ':' && cur + 3 != end) {
- if (*(cur + 3) == 'z') {
- // Formats %:::z.
- if (cur - 1 != pending) {
- FormatTM(&result, std::string(pending, cur - 1), tm);
- }
- bp = FormatOffset(ep, al.offset, ":*:");
- result.append(bp, static_cast<std::size_t>(ep - bp));
- pending = cur += 4;
- continue;
- }
- }
- }
- }
-
+ // More complex specifiers that we handle ourselves.
+ if (*cur == ':' && cur + 1 != end) {
+ if (*(cur + 1) == 'z') {
+ // Formats %:z.
+ if (cur - 1 != pending) {
+ FormatTM(&result, std::string(pending, cur - 1), tm);
+ }
+ bp = FormatOffset(ep, al.offset, ":");
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 2;
+ continue;
+ }
+ if (*(cur + 1) == ':' && cur + 2 != end) {
+ if (*(cur + 2) == 'z') {
+ // Formats %::z.
+ if (cur - 1 != pending) {
+ FormatTM(&result, std::string(pending, cur - 1), tm);
+ }
+ bp = FormatOffset(ep, al.offset, ":*");
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 3;
+ continue;
+ }
+ if (*(cur + 2) == ':' && cur + 3 != end) {
+ if (*(cur + 3) == 'z') {
+ // Formats %:::z.
+ if (cur - 1 != pending) {
+ FormatTM(&result, std::string(pending, cur - 1), tm);
+ }
+ bp = FormatOffset(ep, al.offset, ":*:");
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 4;
+ continue;
+ }
+ }
+ }
+ }
+
// Loop if there is no E modifier.
if (*cur != 'E' || ++cur == end) continue;
// Format our extensions.
- if (*cur == 'T') {
- // Formats %ET.
- if (cur - 2 != pending) {
- FormatTM(&result, std::string(pending, cur - 2), tm);
- }
- result.append("T");
- pending = ++cur;
- } else if (*cur == 'z') {
+ if (*cur == 'T') {
+ // Formats %ET.
+ if (cur - 2 != pending) {
+ FormatTM(&result, std::string(pending, cur - 2), tm);
+ }
+ result.append("T");
+ pending = ++cur;
+ } else if (*cur == 'z') {
// Formats %Ez.
if (cur - 2 != pending) {
FormatTM(&result, std::string(pending, cur - 2), tm);
}
- bp = FormatOffset(ep, al.offset, ":");
+ bp = FormatOffset(ep, al.offset, ":");
result.append(bp, static_cast<std::size_t>(ep - bp));
pending = ++cur;
- } else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') {
- // Formats %E*z.
- if (cur - 2 != pending) {
- FormatTM(&result, std::string(pending, cur - 2), tm);
- }
- bp = FormatOffset(ep, al.offset, ":*");
- result.append(bp, static_cast<std::size_t>(ep - bp));
- pending = cur += 2;
+ } else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') {
+ // Formats %E*z.
+ if (cur - 2 != pending) {
+ FormatTM(&result, std::string(pending, cur - 2), tm);
+ }
+ bp = FormatOffset(ep, al.offset, ":*");
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 2;
} else if (*cur == '*' && cur + 1 != end &&
(*(cur + 1) == 'S' || *(cur + 1) == 'f')) {
// Formats %E*S or %E*F.
@@ -573,32 +573,32 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
namespace {
-const char* ParseOffset(const char* dp, const char* mode, int* offset) {
+const char* ParseOffset(const char* dp, const char* mode, int* offset) {
if (dp != nullptr) {
- const char first = *dp++;
- if (first == '+' || first == '-') {
- char sep = mode[0];
+ const char first = *dp++;
+ if (first == '+' || first == '-') {
+ char sep = mode[0];
int hours = 0;
- int minutes = 0;
- int seconds = 0;
+ int minutes = 0;
+ int seconds = 0;
const char* ap = ParseInt(dp, 2, 0, 23, &hours);
if (ap != nullptr && ap - dp == 2) {
dp = ap;
if (sep != '\0' && *ap == sep) ++ap;
const char* bp = ParseInt(ap, 2, 0, 59, &minutes);
- if (bp != nullptr && bp - ap == 2) {
- dp = bp;
- if (sep != '\0' && *bp == sep) ++bp;
- const char* cp = ParseInt(bp, 2, 0, 59, &seconds);
- if (cp != nullptr && cp - bp == 2) dp = cp;
- }
- *offset = ((hours * 60 + minutes) * 60) + seconds;
- if (first == '-') *offset = -*offset;
+ if (bp != nullptr && bp - ap == 2) {
+ dp = bp;
+ if (sep != '\0' && *bp == sep) ++bp;
+ const char* cp = ParseInt(bp, 2, 0, 59, &seconds);
+ if (cp != nullptr && cp - bp == 2) dp = cp;
+ }
+ *offset = ((hours * 60 + minutes) * 60) + seconds;
+ if (first == '-') *offset = -*offset;
} else {
dp = nullptr;
}
- } else if (first == 'Z' || first == 'z') { // Zulu
- *offset = 0;
+ } else if (first == 'Z' || first == 'z') { // Zulu
+ *offset = 0;
} else {
dp = nullptr;
}
@@ -648,32 +648,32 @@ const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
return dp;
}
-// Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday,
-// and the day on which weeks are defined to start. Returns false if year
-// would need to move outside its bounds.
-bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
- const civil_year y(*year % 400);
- civil_day cd = prev_weekday(y, week_start); // week 0
- cd = next_weekday(cd - 1, FromTmWday(tm->tm_wday)) + (week_num * 7);
- if (const year_t shift = cd.year() - y.year()) {
- if (shift > 0) {
- if (*year > std::numeric_limits<year_t>::max() - shift) return false;
- } else {
- if (*year < std::numeric_limits<year_t>::min() - shift) return false;
- }
- *year += shift;
- }
- tm->tm_mon = cd.month() - 1;
- tm->tm_mday = cd.day();
- return true;
-}
-
+// Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday,
+// and the day on which weeks are defined to start. Returns false if year
+// would need to move outside its bounds.
+bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
+ const civil_year y(*year % 400);
+ civil_day cd = prev_weekday(y, week_start); // week 0
+ cd = next_weekday(cd - 1, FromTmWday(tm->tm_wday)) + (week_num * 7);
+ if (const year_t shift = cd.year() - y.year()) {
+ if (shift > 0) {
+ if (*year > std::numeric_limits<year_t>::max() - shift) return false;
+ } else {
+ if (*year < std::numeric_limits<year_t>::min() - shift) return false;
+ }
+ *year += shift;
+ }
+ tm->tm_mon = cd.month() - 1;
+ tm->tm_mday = cd.day();
+ return true;
+}
+
} // namespace
// Uses strptime(3) to parse the given input. Supports the same extended
// format specifiers as format(), although %E#S and %E*S are treated
-// identically (and similarly for %E#f and %E*f). %Ez and %E*z also accept
-// the same inputs. %ET accepts either 'T' or 't'.
+// identically (and similarly for %E#f and %E*f). %Ez and %E*z also accept
+// the same inputs. %ET accepts either 'T' or 't'.
//
// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
// handled internally so that we can normally avoid strptime() altogether
@@ -685,7 +685,7 @@ bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
// We also handle the %z specifier to accommodate platforms that do not
// support the tm_gmtoff extension to std::tm. %Z is parsed but ignored.
bool parse(const std::string& format, const std::string& input,
- const time_zone& tz, time_point<seconds>* sec,
+ const time_zone& tz, time_point<seconds>* sec,
detail::femtoseconds* fs, std::string* err) {
// The unparsed input.
const char* data = input.c_str(); // NUL terminated
@@ -717,8 +717,8 @@ bool parse(const std::string& format, const std::string& input,
const char* fmt = format.c_str(); // NUL terminated
bool twelve_hour = false;
bool afternoon = false;
- int week_num = -1;
- weekday week_start = weekday::sunday;
+ int week_num = -1;
+ weekday week_start = weekday::sunday;
bool saw_percent_s = false;
std::int_fast64_t percent_s = 0;
@@ -757,28 +757,28 @@ bool parse(const std::string& format, const std::string& input,
case 'm':
data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
if (data != nullptr) tm.tm_mon -= 1;
- week_num = -1;
+ week_num = -1;
continue;
case 'd':
- case 'e':
+ case 'e':
data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
- week_num = -1;
+ week_num = -1;
+ continue;
+ case 'U':
+ data = ParseInt(data, 0, 0, 53, &week_num);
+ week_start = weekday::sunday;
+ continue;
+ case 'W':
+ data = ParseInt(data, 0, 0, 53, &week_num);
+ week_start = weekday::monday;
+ continue;
+ case 'u':
+ data = ParseInt(data, 0, 1, 7, &tm.tm_wday);
+ if (data != nullptr) tm.tm_wday %= 7;
+ continue;
+ case 'w':
+ data = ParseInt(data, 0, 0, 6, &tm.tm_wday);
continue;
- case 'U':
- data = ParseInt(data, 0, 0, 53, &week_num);
- week_start = weekday::sunday;
- continue;
- case 'W':
- data = ParseInt(data, 0, 0, 53, &week_num);
- week_start = weekday::monday;
- continue;
- case 'u':
- data = ParseInt(data, 0, 1, 7, &tm.tm_wday);
- if (data != nullptr) tm.tm_wday %= 7;
- continue;
- case 'w':
- data = ParseInt(data, 0, 0, 6, &tm.tm_wday);
- continue;
case 'H':
data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
twelve_hour = false;
@@ -801,7 +801,7 @@ bool parse(const std::string& format, const std::string& input,
twelve_hour = false;
break;
case 'z':
- data = ParseOffset(data, "", &offset);
+ data = ParseOffset(data, "", &offset);
if (data != nullptr) saw_offset = true;
continue;
case 'Z': // ignored; zone abbreviations are ambiguous
@@ -814,36 +814,36 @@ bool parse(const std::string& format, const std::string& input,
&percent_s);
if (data != nullptr) saw_percent_s = true;
continue;
- case ':':
- if (fmt[0] == 'z' ||
- (fmt[0] == ':' &&
- (fmt[1] == 'z' || (fmt[1] == ':' && fmt[2] == 'z')))) {
- data = ParseOffset(data, ":", &offset);
- if (data != nullptr) saw_offset = true;
- fmt += (fmt[0] == 'z') ? 1 : (fmt[1] == 'z') ? 2 : 3;
- continue;
- }
- break;
- case '%':
- data = (*data == '%' ? data + 1 : nullptr);
- continue;
+ case ':':
+ if (fmt[0] == 'z' ||
+ (fmt[0] == ':' &&
+ (fmt[1] == 'z' || (fmt[1] == ':' && fmt[2] == 'z')))) {
+ data = ParseOffset(data, ":", &offset);
+ if (data != nullptr) saw_offset = true;
+ fmt += (fmt[0] == 'z') ? 1 : (fmt[1] == 'z') ? 2 : 3;
+ continue;
+ }
+ break;
+ case '%':
+ data = (*data == '%' ? data + 1 : nullptr);
+ continue;
case 'E':
- if (fmt[0] == 'T') {
- if (*data == 'T' || *data == 't') {
- ++data;
- ++fmt;
+ if (fmt[0] == 'T') {
+ if (*data == 'T' || *data == 't') {
+ ++data;
+ ++fmt;
} else {
- data = nullptr;
+ data = nullptr;
}
- continue;
- }
- if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
- data = ParseOffset(data, ":", &offset);
+ continue;
+ }
+ if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
+ data = ParseOffset(data, ":", &offset);
if (data != nullptr) saw_offset = true;
- fmt += (fmt[0] == 'z') ? 1 : 2;
+ fmt += (fmt[0] == 'z') ? 1 : 2;
continue;
}
- if (fmt[0] == '*' && fmt[1] == 'S') {
+ if (fmt[0] == '*' && fmt[1] == 'S') {
data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
if (data != nullptr && *data == '.') {
data = ParseSubSeconds(data + 1, &subseconds);
@@ -851,14 +851,14 @@ bool parse(const std::string& format, const std::string& input,
fmt += 2;
continue;
}
- if (fmt[0] == '*' && fmt[1] == 'f') {
+ if (fmt[0] == '*' && fmt[1] == 'f') {
if (data != nullptr && std::isdigit(*data)) {
data = ParseSubSeconds(data, &subseconds);
}
fmt += 2;
continue;
}
- if (fmt[0] == '4' && fmt[1] == 'Y') {
+ if (fmt[0] == '4' && fmt[1] == 'Y') {
const char* bp = data;
data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year);
if (data != nullptr) {
@@ -908,7 +908,7 @@ bool parse(const std::string& format, const std::string& input,
data = ParseTM(data, spec.c_str(), &tm);
// If we successfully parsed %p we need to remember whether the result
- // was AM or PM so that we can adjust tm_hour before time_zone::lookup().
+ // was AM or PM so that we can adjust tm_hour before time_zone::lookup().
// So reparse the input with a known AM hour, and check if it is shifted
// to a PM hour.
if (spec == "%p" && data != nullptr) {
@@ -947,8 +947,8 @@ bool parse(const std::string& format, const std::string& input,
return true;
}
- // If we saw %z, %Ez, or %E*z then we want to interpret the parsed fields
- // in UTC and then shift by that offset. Otherwise we want to interpret
+ // If we saw %z, %Ez, or %E*z then we want to interpret the parsed fields
+ // in UTC and then shift by that offset. Otherwise we want to interpret
// the fields directly in the passed time_zone.
time_zone ptz = saw_offset ? utc_time_zone() : tz;
@@ -969,14 +969,14 @@ bool parse(const std::string& format, const std::string& input,
year += 1900;
}
- // Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
- if (week_num != -1) {
- if (!FromWeek(week_num, week_start, &year, &tm)) {
- if (err != nullptr) *err = "Out-of-range field";
- return false;
- }
- }
-
+ // Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
+ if (week_num != -1) {
+ if (!FromWeek(week_num, week_start, &year, &tm)) {
+ if (err != nullptr) *err = "Out-of-range field";
+ return false;
+ }
+ }
+
const int month = tm.tm_mon + 1;
civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
@@ -998,15 +998,15 @@ bool parse(const std::string& format, const std::string& input,
const auto tp = ptz.lookup(cs).pre;
// Checks for overflow/underflow and returns an error as necessary.
- if (tp == time_point<seconds>::max()) {
- const auto al = ptz.lookup(time_point<seconds>::max());
+ if (tp == time_point<seconds>::max()) {
+ const auto al = ptz.lookup(time_point<seconds>::max());
if (cs > al.cs) {
if (err != nullptr) *err = "Out-of-range field";
return false;
}
}
- if (tp == time_point<seconds>::min()) {
- const auto al = ptz.lookup(time_point<seconds>::min());
+ if (tp == time_point<seconds>::min()) {
+ const auto al = ptz.lookup(time_point<seconds>::min());
if (cs < al.cs) {
if (err != nullptr) *err = "Out-of-range field";
return false;
diff --git a/contrib/libs/cctz/src/time_zone_if.cc b/contrib/libs/cctz/src/time_zone_if.cc
index fcf0c1e9f2..a80dbcd60d 100644
--- a/contrib/libs/cctz/src/time_zone_if.cc
+++ b/contrib/libs/cctz/src/time_zone_if.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -31,14 +31,14 @@ std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) {
return std::unique_ptr<TimeZoneIf>(tz.release());
}
-// Defined out-of-line to avoid emitting a weak vtable in all TUs.
-TimeZoneIf::~TimeZoneIf() {}
-
-time_point<seconds> UnixSecondsToTimePoint(std::int_fast64_t seconds) {
+// Defined out-of-line to avoid emitting a weak vtable in all TUs.
+TimeZoneIf::~TimeZoneIf() {}
+
+time_point<seconds> UnixSecondsToTimePoint(std::int_fast64_t seconds) {
return FromUnixSeconds(seconds);
}
-std::int_fast64_t TimePointToUnixSeconds(const time_point<seconds>& tp) {
+std::int_fast64_t TimePointToUnixSeconds(const time_point<seconds>& tp) {
return ToUnixSeconds(tp);
}
diff --git a/contrib/libs/cctz/src/time_zone_if.h b/contrib/libs/cctz/src/time_zone_if.h
index 19129cd50c..f925c6c55a 100644
--- a/contrib/libs/cctz/src/time_zone_if.h
+++ b/contrib/libs/cctz/src/time_zone_if.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,8 +20,8 @@
#include <memory>
#include <string>
-#include "cctz/civil_time.h"
-#include "cctz/time_zone.h"
+#include "cctz/civil_time.h"
+#include "cctz/time_zone.h"
namespace cctz {
@@ -32,35 +32,35 @@ class TimeZoneIf {
// A factory function for TimeZoneIf implementations.
static std::unique_ptr<TimeZoneIf> Load(const std::string& name);
- virtual ~TimeZoneIf();
+ virtual ~TimeZoneIf();
virtual time_zone::absolute_lookup BreakTime(
- const time_point<seconds>& tp) const = 0;
+ const time_point<seconds>& tp) const = 0;
virtual time_zone::civil_lookup MakeTime(
const civil_second& cs) const = 0;
- virtual bool NextTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const = 0;
- virtual bool PrevTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const = 0;
-
- virtual std::string Version() const = 0;
+ virtual bool NextTransition(const time_point<seconds>& tp,
+ time_zone::civil_transition* trans) const = 0;
+ virtual bool PrevTransition(const time_point<seconds>& tp,
+ time_zone::civil_transition* trans) const = 0;
+
+ virtual std::string Version() const = 0;
virtual std::string Description() const = 0;
protected:
TimeZoneIf() {}
};
-// Convert between time_point<seconds> and a count of seconds since the
-// Unix epoch. We assume that the std::chrono::system_clock and the
+// Convert between time_point<seconds> and a count of seconds since the
+// Unix epoch. We assume that the std::chrono::system_clock and the
// Unix clock are second aligned, but not that they share an epoch.
-inline std::int_fast64_t ToUnixSeconds(const time_point<seconds>& tp) {
- return (tp - std::chrono::time_point_cast<seconds>(
- std::chrono::system_clock::from_time_t(0))).count();
+inline std::int_fast64_t ToUnixSeconds(const time_point<seconds>& tp) {
+ return (tp - std::chrono::time_point_cast<seconds>(
+ std::chrono::system_clock::from_time_t(0))).count();
}
-inline time_point<seconds> FromUnixSeconds(std::int_fast64_t t) {
- return std::chrono::time_point_cast<seconds>(
- std::chrono::system_clock::from_time_t(0)) + seconds(t);
+inline time_point<seconds> FromUnixSeconds(std::int_fast64_t t) {
+ return std::chrono::time_point_cast<seconds>(
+ std::chrono::system_clock::from_time_t(0)) + seconds(t);
}
} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_impl.cc b/contrib/libs/cctz/src/time_zone_impl.cc
index d799de39c9..6e077505c1 100644
--- a/contrib/libs/cctz/src/time_zone_impl.cc
+++ b/contrib/libs/cctz/src/time_zone_impl.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,8 +14,8 @@
#include "time_zone_impl.h"
-#include <deque>
-#include <memory>
+#include <deque>
+#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
@@ -33,12 +33,12 @@ using TimeZoneImplByName =
TimeZoneImplByName* time_zone_map = nullptr;
// Mutual exclusion for time_zone_map.
-std::mutex& TimeZoneMutex() {
- // This mutex is intentionally "leaked" to avoid the static deinitialization
- // order fiasco (std::mutex's destructor is not trivial on many platforms).
- static std::mutex* time_zone_mutex = new std::mutex;
- return *time_zone_mutex;
-}
+std::mutex& TimeZoneMutex() {
+ // This mutex is intentionally "leaked" to avoid the static deinitialization
+ // order fiasco (std::mutex's destructor is not trivial on many platforms).
+ static std::mutex* time_zone_mutex = new std::mutex;
+ return *time_zone_mutex;
+}
} // namespace
@@ -47,18 +47,18 @@ time_zone time_zone::Impl::UTC() {
}
bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
- const Impl* const utc_impl = UTCImpl();
+ const Impl* const utc_impl = UTCImpl();
- // Check for UTC (which is never a key in time_zone_map).
- auto offset = seconds::zero();
- if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) {
+ // Check for UTC (which is never a key in time_zone_map).
+ auto offset = seconds::zero();
+ if (FixedOffsetFromName(name, &offset) && offset == seconds::zero()) {
*tz = time_zone(utc_impl);
return true;
}
- // Check whether the time zone has already been loaded.
+ // Check whether the time zone has already been loaded.
{
- std::lock_guard<std::mutex> lock(TimeZoneMutex());
+ std::lock_guard<std::mutex> lock(TimeZoneMutex());
if (time_zone_map != nullptr) {
TimeZoneImplByName::const_iterator itr = time_zone_map->find(name);
if (itr != time_zone_map->end()) {
@@ -68,40 +68,40 @@ bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
}
}
- // Load the new time zone (outside the lock).
- std::unique_ptr<const Impl> new_impl(new Impl(name));
-
- // Add the new time zone to the map.
- std::lock_guard<std::mutex> lock(TimeZoneMutex());
+ // Load the new time zone (outside the lock).
+ std::unique_ptr<const Impl> new_impl(new Impl(name));
+
+ // Add the new time zone to the map.
+ std::lock_guard<std::mutex> lock(TimeZoneMutex());
if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
const Impl*& impl = (*time_zone_map)[name];
- if (impl == nullptr) { // this thread won any load race
- impl = new_impl->zone_ ? new_impl.release() : utc_impl;
+ if (impl == nullptr) { // this thread won any load race
+ impl = new_impl->zone_ ? new_impl.release() : utc_impl;
}
*tz = time_zone(impl);
return impl != utc_impl;
}
void time_zone::Impl::ClearTimeZoneMapTestOnly() {
- std::lock_guard<std::mutex> lock(TimeZoneMutex());
+ std::lock_guard<std::mutex> lock(TimeZoneMutex());
if (time_zone_map != nullptr) {
- // Existing time_zone::Impl* entries are in the wild, so we can't delete
- // them. Instead, we move them to a private container, where they are
- // logically unreachable but not "leaked". Future requests will result
- // in reloading the data.
- static auto* cleared = new std::deque<const time_zone::Impl*>;
- for (const auto& element : *time_zone_map) {
- cleared->push_back(element.second);
- }
+ // Existing time_zone::Impl* entries are in the wild, so we can't delete
+ // them. Instead, we move them to a private container, where they are
+ // logically unreachable but not "leaked". Future requests will result
+ // in reloading the data.
+ static auto* cleared = new std::deque<const time_zone::Impl*>;
+ for (const auto& element : *time_zone_map) {
+ cleared->push_back(element.second);
+ }
time_zone_map->clear();
}
}
-time_zone::Impl::Impl(const std::string& name)
- : name_(name), zone_(TimeZoneIf::Load(name_)) {}
+time_zone::Impl::Impl(const std::string& name)
+ : name_(name), zone_(TimeZoneIf::Load(name_)) {}
const time_zone::Impl* time_zone::Impl::UTCImpl() {
- static const Impl* utc_impl = new Impl("UTC"); // never fails
+ static const Impl* utc_impl = new Impl("UTC"); // never fails
return utc_impl;
}
diff --git a/contrib/libs/cctz/src/time_zone_impl.h b/contrib/libs/cctz/src/time_zone_impl.h
index 0a9a8af36f..23fcddb690 100644
--- a/contrib/libs/cctz/src/time_zone_impl.h
+++ b/contrib/libs/cctz/src/time_zone_impl.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -18,8 +18,8 @@
#include <memory>
#include <string>
-#include "cctz/civil_time.h"
-#include "cctz/time_zone.h"
+#include "cctz/civil_time.h"
+#include "cctz/time_zone.h"
#include "time_zone_if.h"
#include "time_zone_info.h"
@@ -40,13 +40,13 @@ class time_zone::Impl {
static void ClearTimeZoneMapTestOnly();
// The primary key is the time-zone ID (e.g., "America/New_York").
- const std::string& Name() const {
- // TODO: It would nice if the zoneinfo data included the zone name.
- return name_;
- }
+ const std::string& Name() const {
+ // TODO: It would nice if the zoneinfo data included the zone name.
+ return name_;
+ }
// Breaks a time_point down to civil-time components in this time zone.
- time_zone::absolute_lookup BreakTime(const time_point<seconds>& tp) const {
+ time_zone::absolute_lookup BreakTime(const time_point<seconds>& tp) const {
return zone_->BreakTime(tp);
}
@@ -58,21 +58,21 @@ class time_zone::Impl {
}
// Finds the time of the next/previous offset change in this time zone.
- bool NextTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const {
- return zone_->NextTransition(tp, trans);
+ bool NextTransition(const time_point<seconds>& tp,
+ time_zone::civil_transition* trans) const {
+ return zone_->NextTransition(tp, trans);
}
- bool PrevTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const {
- return zone_->PrevTransition(tp, trans);
+ bool PrevTransition(const time_point<seconds>& tp,
+ time_zone::civil_transition* trans) const {
+ return zone_->PrevTransition(tp, trans);
}
- // Returns an implementation-defined version string for this time zone.
- std::string Version() const { return zone_->Version(); }
-
- // Returns an implementation-defined description of this time zone.
- std::string Description() const { return zone_->Description(); }
-
+ // Returns an implementation-defined version string for this time zone.
+ std::string Version() const { return zone_->Version(); }
+
+ // Returns an implementation-defined description of this time zone.
+ std::string Description() const { return zone_->Description(); }
+
private:
explicit Impl(const std::string& name);
static const Impl* UTCImpl();
diff --git a/contrib/libs/cctz/src/time_zone_info.cc b/contrib/libs/cctz/src/time_zone_info.cc
index 4f8c242e6c..1b3dc15cf1 100644
--- a/contrib/libs/cctz/src/time_zone_info.cc
+++ b/contrib/libs/cctz/src/time_zone_info.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -25,7 +25,7 @@
// a grain of salt.
//
// For more information see tzfile(5), http://www.iana.org/time-zones, or
-// https://en.wikipedia.org/wiki/Zoneinfo.
+// https://en.wikipedia.org/wiki/Zoneinfo.
//
// Note that we assume the proleptic Gregorian calendar and 60-second
// minutes throughout.
@@ -44,7 +44,7 @@
#include <sstream>
#include <string>
-#include "cctz/civil_time.h"
+#include "cctz/civil_time.h"
#include "time_zone_fixed.h"
#include "time_zone_posix.h"
@@ -52,7 +52,7 @@ namespace cctz {
namespace {
-inline bool IsLeap(year_t year) {
+inline bool IsLeap(year_t year) {
return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
}
@@ -78,27 +78,27 @@ const std::int_least32_t kSecsPerYear[2] = {
366 * kSecsPerDay,
};
-// Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat).
-inline int ToPosixWeekday(weekday wd) {
- switch (wd) {
- case weekday::sunday:
- return 0;
- case weekday::monday:
- return 1;
- case weekday::tuesday:
- return 2;
- case weekday::wednesday:
- return 3;
- case weekday::thursday:
- return 4;
- case weekday::friday:
- return 5;
- case weekday::saturday:
- return 6;
- }
- return 0; /*NOTREACHED*/
-}
-
+// Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat).
+inline int ToPosixWeekday(weekday wd) {
+ switch (wd) {
+ case weekday::sunday:
+ return 0;
+ case weekday::monday:
+ return 1;
+ case weekday::tuesday:
+ return 2;
+ case weekday::wednesday:
+ return 3;
+ case weekday::thursday:
+ return 4;
+ case weekday::friday:
+ return 5;
+ case weekday::saturday:
+ return 6;
+ }
+ return 0; /*NOTREACHED*/
+}
+
// Single-byte, unsigned numeric values are encoded directly.
inline std::uint_fast8_t Decode8(const char* cp) {
return static_cast<std::uint_fast8_t>(*cp) & 0xff;
@@ -158,7 +158,7 @@ std::int_fast64_t TransOffset(bool leap_year, int jan1_weekday,
return (days * kSecsPerDay) + pt.time.offset;
}
-inline time_zone::civil_lookup MakeUnique(const time_point<seconds>& tp) {
+inline time_zone::civil_lookup MakeUnique(const time_point<seconds>& tp) {
time_zone::civil_lookup cl;
cl.kind = time_zone::civil_lookup::UNIQUE;
cl.pre = cl.trans = cl.post = tp;
@@ -189,7 +189,7 @@ inline time_zone::civil_lookup MakeRepeated(const Transition& tr,
return cl;
}
-inline civil_second YearShift(const civil_second& cs, year_t shift) {
+inline civil_second YearShift(const civil_second& cs, year_t shift) {
return civil_second(cs.year() + shift, cs.month(), cs.day(),
cs.hour(), cs.minute(), cs.second());
}
@@ -197,20 +197,20 @@ inline civil_second YearShift(const civil_second& cs, year_t shift) {
} // namespace
// What (no leap-seconds) UTC+seconds zoneinfo would look like.
-bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
+bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
transition_types_.resize(1);
TransitionType& tt(transition_types_.back());
tt.utc_offset = static_cast<std::int_least32_t>(offset.count());
tt.is_dst = false;
tt.abbr_index = 0;
- // We temporarily add some redundant, contemporary (2015 through 2025)
+ // We temporarily add some redundant, contemporary (2015 through 2025)
// transitions for performance reasons. See TimeZoneInfo::LocalTime().
// TODO: Fix the performance issue and remove the extra transitions.
transitions_.clear();
transitions_.reserve(12);
for (const std::int_fast64_t unix_time : {
- -(1LL << 59), // a "first half" transition
+ -(1LL << 59), // a "first half" transition
1420070400LL, // 2015-01-01T00:00:00+00:00
1451606400LL, // 2016-01-01T00:00:00+00:00
1483228800LL, // 2017-01-01T00:00:00+00:00
@@ -218,10 +218,10 @@ bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
1546300800LL, // 2019-01-01T00:00:00+00:00
1577836800LL, // 2020-01-01T00:00:00+00:00
1609459200LL, // 2021-01-01T00:00:00+00:00
- 1640995200LL, // 2022-01-01T00:00:00+00:00
- 1672531200LL, // 2023-01-01T00:00:00+00:00
- 1704067200LL, // 2024-01-01T00:00:00+00:00
- 1735689600LL, // 2025-01-01T00:00:00+00:00
+ 1640995200LL, // 2022-01-01T00:00:00+00:00
+ 1672531200LL, // 2023-01-01T00:00:00+00:00
+ 1704067200LL, // 2024-01-01T00:00:00+00:00
+ 1735689600LL, // 2025-01-01T00:00:00+00:00
}) {
Transition& tr(*transitions_.emplace(transitions_.end()));
tr.unix_time = unix_time;
@@ -232,12 +232,12 @@ bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) {
default_transition_type_ = 0;
abbreviations_ = FixedOffsetToAbbr(offset);
- abbreviations_.append(1, '\0');
+ abbreviations_.append(1, '\0');
future_spec_.clear(); // never needed for a fixed-offset zone
extended_ = false;
- tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
- tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
+ tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
+ tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
transitions_.shrink_to_fit();
return true;
@@ -256,8 +256,8 @@ bool TimeZoneInfo::Header::Build(const tzhead& tzh) {
leapcnt = static_cast<std::size_t>(v);
if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false;
ttisstdcnt = static_cast<std::size_t>(v);
- if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false;
- ttisutcnt = static_cast<std::size_t>(v);
+ if ((v = Decode32(tzh.tzh_ttisutcnt)) < 0) return false;
+ ttisutcnt = static_cast<std::size_t>(v);
return true;
}
@@ -270,7 +270,7 @@ std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const {
len += 1 * charcnt; // abbreviations
len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC
len += 1 * ttisstdcnt; // UTC/local indicators
- len += 1 * ttisutcnt; // standard/wall indicators
+ len += 1 * ttisutcnt; // standard/wall indicators
return len;
}
@@ -282,108 +282,108 @@ bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index,
if (tt1_index == tt2_index) return true;
const TransitionType& tt1(transition_types_[tt1_index]);
const TransitionType& tt2(transition_types_[tt2_index]);
- if (tt1.utc_offset != tt2.utc_offset) return false;
+ if (tt1.utc_offset != tt2.utc_offset) return false;
if (tt1.is_dst != tt2.is_dst) return false;
if (tt1.abbr_index != tt2.abbr_index) return false;
return true;
}
-// Find/make a transition type with these attributes.
-bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
- const std::string& abbr,
- std::uint_least8_t* index) {
- std::size_t type_index = 0;
- std::size_t abbr_index = abbreviations_.size();
- for (; type_index != transition_types_.size(); ++type_index) {
- const TransitionType& tt(transition_types_[type_index]);
- const char* tt_abbr = &abbreviations_[tt.abbr_index];
- if (tt_abbr == abbr) abbr_index = tt.abbr_index;
- if (tt.utc_offset == utc_offset && tt.is_dst == is_dst) {
- if (abbr_index == tt.abbr_index) break; // reuse
- }
- }
- if (type_index > 255 || abbr_index > 255) {
- // No index space (8 bits) available for a new type or abbreviation.
- return false;
- }
- if (type_index == transition_types_.size()) {
- TransitionType& tt(*transition_types_.emplace(transition_types_.end()));
- tt.utc_offset = static_cast<std::int_least32_t>(utc_offset);
- tt.is_dst = is_dst;
- if (abbr_index == abbreviations_.size()) {
- abbreviations_.append(abbr);
- abbreviations_.append(1, '\0');
- }
- tt.abbr_index = static_cast<std::uint_least8_t>(abbr_index);
- }
- *index = static_cast<std::uint_least8_t>(type_index);
- return true;
-}
-
+// Find/make a transition type with these attributes.
+bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
+ const std::string& abbr,
+ std::uint_least8_t* index) {
+ std::size_t type_index = 0;
+ std::size_t abbr_index = abbreviations_.size();
+ for (; type_index != transition_types_.size(); ++type_index) {
+ const TransitionType& tt(transition_types_[type_index]);
+ const char* tt_abbr = &abbreviations_[tt.abbr_index];
+ if (tt_abbr == abbr) abbr_index = tt.abbr_index;
+ if (tt.utc_offset == utc_offset && tt.is_dst == is_dst) {
+ if (abbr_index == tt.abbr_index) break; // reuse
+ }
+ }
+ if (type_index > 255 || abbr_index > 255) {
+ // No index space (8 bits) available for a new type or abbreviation.
+ return false;
+ }
+ if (type_index == transition_types_.size()) {
+ TransitionType& tt(*transition_types_.emplace(transition_types_.end()));
+ tt.utc_offset = static_cast<std::int_least32_t>(utc_offset);
+ tt.is_dst = is_dst;
+ if (abbr_index == abbreviations_.size()) {
+ abbreviations_.append(abbr);
+ abbreviations_.append(1, '\0');
+ }
+ tt.abbr_index = static_cast<std::uint_least8_t>(abbr_index);
+ }
+ *index = static_cast<std::uint_least8_t>(type_index);
+ return true;
+}
+
// Use the POSIX-TZ-environment-variable-style string to handle times
// in years after the last transition stored in the zoneinfo data.
-bool TimeZoneInfo::ExtendTransitions() {
+bool TimeZoneInfo::ExtendTransitions() {
extended_ = false;
- if (future_spec_.empty()) return true; // last transition prevails
+ if (future_spec_.empty()) return true; // last transition prevails
PosixTimeZone posix;
- if (!ParsePosixSpec(future_spec_, &posix)) return false;
+ if (!ParsePosixSpec(future_spec_, &posix)) return false;
- // Find transition type for the future std specification.
- std::uint_least8_t std_ti;
- if (!GetTransitionType(posix.std_offset, false, posix.std_abbr, &std_ti))
- return false;
+ // Find transition type for the future std specification.
+ std::uint_least8_t std_ti;
+ if (!GetTransitionType(posix.std_offset, false, posix.std_abbr, &std_ti))
+ return false;
- if (posix.dst_abbr.empty()) { // std only
- // The future specification should match the last transition, and
- // that means that handling the future will fall out naturally.
- return EquivTransitions(transitions_.back().type_index, std_ti);
+ if (posix.dst_abbr.empty()) { // std only
+ // The future specification should match the last transition, and
+ // that means that handling the future will fall out naturally.
+ return EquivTransitions(transitions_.back().type_index, std_ti);
}
- // Find transition type for the future dst specification.
- std::uint_least8_t dst_ti;
- if (!GetTransitionType(posix.dst_offset, true, posix.dst_abbr, &dst_ti))
- return false;
+ // Find transition type for the future dst specification.
+ std::uint_least8_t dst_ti;
+ if (!GetTransitionType(posix.dst_offset, true, posix.dst_abbr, &dst_ti))
+ return false;
// Extend the transitions for an additional 400 years using the
// future specification. Years beyond those can be handled by
// mapping back to a cycle-equivalent year within that range.
- // We may need two additional transitions for the current year.
- transitions_.reserve(transitions_.size() + 400 * 2 + 2);
+ // We may need two additional transitions for the current year.
+ transitions_.reserve(transitions_.size() + 400 * 2 + 2);
extended_ = true;
- const Transition& last(transitions_.back());
- const std::int_fast64_t last_time = last.unix_time;
- const TransitionType& last_tt(transition_types_[last.type_index]);
- last_year_ = LocalTime(last_time, last_tt).cs.year();
- bool leap_year = IsLeap(last_year_);
- const civil_second jan1(last_year_);
- std::int_fast64_t jan1_time = jan1 - civil_second();
- int jan1_weekday = ToPosixWeekday(get_weekday(jan1));
-
- Transition dst = {0, dst_ti, civil_second(), civil_second()};
- Transition std = {0, std_ti, civil_second(), civil_second()};
- for (const year_t limit = last_year_ + 400;; ++last_year_) {
- auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start);
- auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end);
- dst.unix_time = jan1_time + dst_trans_off - posix.std_offset;
- std.unix_time = jan1_time + std_trans_off - posix.dst_offset;
- const auto* ta = dst.unix_time < std.unix_time ? &dst : &std;
- const auto* tb = dst.unix_time < std.unix_time ? &std : &dst;
- if (last_time < tb->unix_time) {
- if (last_time < ta->unix_time) transitions_.push_back(*ta);
- transitions_.push_back(*tb);
- }
- if (last_year_ == limit) break;
+ const Transition& last(transitions_.back());
+ const std::int_fast64_t last_time = last.unix_time;
+ const TransitionType& last_tt(transition_types_[last.type_index]);
+ last_year_ = LocalTime(last_time, last_tt).cs.year();
+ bool leap_year = IsLeap(last_year_);
+ const civil_second jan1(last_year_);
+ std::int_fast64_t jan1_time = jan1 - civil_second();
+ int jan1_weekday = ToPosixWeekday(get_weekday(jan1));
+
+ Transition dst = {0, dst_ti, civil_second(), civil_second()};
+ Transition std = {0, std_ti, civil_second(), civil_second()};
+ for (const year_t limit = last_year_ + 400;; ++last_year_) {
+ auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start);
+ auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end);
+ dst.unix_time = jan1_time + dst_trans_off - posix.std_offset;
+ std.unix_time = jan1_time + std_trans_off - posix.dst_offset;
+ const auto* ta = dst.unix_time < std.unix_time ? &dst : &std;
+ const auto* tb = dst.unix_time < std.unix_time ? &std : &dst;
+ if (last_time < tb->unix_time) {
+ if (last_time < ta->unix_time) transitions_.push_back(*ta);
+ transitions_.push_back(*tb);
+ }
+ if (last_year_ == limit) break;
jan1_time += kSecsPerYear[leap_year];
jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
- leap_year = !leap_year && IsLeap(last_year_ + 1);
+ leap_year = !leap_year && IsLeap(last_year_ + 1);
}
-
- return true;
+
+ return true;
}
-bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
+bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
// Read and validate the header.
tzhead tzh;
if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
@@ -420,7 +420,7 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
}
if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt)
return false;
- if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt)
+ if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt)
return false;
// Read the data into a local buffer.
@@ -431,7 +431,7 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
const char* bp = tbuf.data();
// Decode and validate the transitions.
- transitions_.reserve(hdr.timecnt + 2);
+ transitions_.reserve(hdr.timecnt + 2);
transitions_.resize(hdr.timecnt);
for (std::size_t i = 0; i != hdr.timecnt; ++i) {
transitions_[i].unix_time = (time_len == 4) ? Decode32(bp) : Decode64(bp);
@@ -452,7 +452,7 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
}
// Decode and validate the transition types.
- transition_types_.reserve(hdr.typecnt + 2);
+ transition_types_.reserve(hdr.typecnt + 2);
transition_types_.resize(hdr.typecnt);
for (std::size_t i = 0; i != hdr.typecnt; ++i) {
transition_types_[i].utc_offset =
@@ -483,7 +483,7 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
}
// Copy all the abbreviations.
- abbreviations_.reserve(hdr.charcnt + 10);
+ abbreviations_.reserve(hdr.charcnt + 10);
abbreviations_.assign(bp, hdr.charcnt);
bp += hdr.charcnt;
@@ -493,16 +493,16 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
// that isn't the case here (see "zic -p").
bp += (8 + 4) * hdr.leapcnt; // leap-time + TAI-UTC
bp += 1 * hdr.ttisstdcnt; // UTC/local indicators
- bp += 1 * hdr.ttisutcnt; // standard/wall indicators
+ bp += 1 * hdr.ttisutcnt; // standard/wall indicators
assert(bp == tbuf.data() + tbuf.size());
future_spec_.clear();
if (tzh.tzh_version[0] != '\0') {
// Snarf up the NL-enclosed future POSIX spec. Note
// that version '3' files utilize an extended format.
- auto get_char = [](ZoneInfoSource* azip) -> int {
+ auto get_char = [](ZoneInfoSource* azip) -> int {
unsigned char ch; // all non-EOF results are positive
- return (azip->Read(&ch, 1) == 1) ? ch : EOF;
+ return (azip->Read(&ch, 1) == 1) ? ch : EOF;
};
if (get_char(zip) != '\n')
return false;
@@ -515,13 +515,13 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
// We don't check for EOF so that we're forwards compatible.
- // If we did not find version information during the standard loading
- // process (as of tzh_version '3' that is unsupported), then ask the
- // ZoneInfoSource for any out-of-bound version string it may be privy to.
- if (version_.empty()) {
- version_ = zip->Version();
- }
-
+ // If we did not find version information during the standard loading
+ // process (as of tzh_version '3' that is unsupported), then ask the
+ // ZoneInfoSource for any out-of-bound version string it may be privy to.
+ if (version_.empty()) {
+ version_ = zip->Version();
+ }
+
// Trim redundant transitions. zic may have added these to work around
// differences between the glibc and reference implementations (see
// zic.c:dontmerge) and the Qt library (see zic.c:WORK_AROUND_QTBUG_53071).
@@ -536,31 +536,31 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
transitions_.resize(hdr.timecnt);
// Ensure that there is always a transition in the first half of the
- // time line (the second half is handled below) so that the signed
- // difference between a civil_second and the civil_second of its
- // previous transition is always representable, without overflow.
+ // time line (the second half is handled below) so that the signed
+ // difference between a civil_second and the civil_second of its
+ // previous transition is always representable, without overflow.
if (transitions_.empty() || transitions_.front().unix_time >= 0) {
Transition& tr(*transitions_.emplace(transitions_.begin()));
- tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00
+ tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00
tr.type_index = default_transition_type_;
}
// Extend the transitions using the future specification.
- if (!ExtendTransitions()) return false;
-
- // Ensure that there is always a transition in the second half of the
- // time line (the first half is handled above) so that the signed
- // difference between a civil_second and the civil_second of its
- // previous transition is always representable, without overflow.
- const Transition& last(transitions_.back());
- if (last.unix_time < 0) {
- const std::uint_fast8_t type_index = last.type_index;
- Transition& tr(*transitions_.emplace(transitions_.end()));
- tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00
- tr.type_index = type_index;
- }
-
- // Compute the local civil time for each transition and the preceding
+ if (!ExtendTransitions()) return false;
+
+ // Ensure that there is always a transition in the second half of the
+ // time line (the first half is handled above) so that the signed
+ // difference between a civil_second and the civil_second of its
+ // previous transition is always representable, without overflow.
+ const Transition& last(transitions_.back());
+ if (last.unix_time < 0) {
+ const std::uint_fast8_t type_index = last.type_index;
+ Transition& tr(*transitions_.emplace(transitions_.end()));
+ tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00
+ tr.type_index = type_index;
+ }
+
+ // Compute the local civil time for each transition and the preceding
// second. These will be used for reverse conversions in MakeTime().
const TransitionType* ttp = &transition_types_[default_transition_type_];
for (std::size_t i = 0; i != transitions_.size(); ++i) {
@@ -578,10 +578,10 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
}
// Compute the maximum/minimum civil times that can be converted to a
- // time_point<seconds> for each of the zone's transition types.
+ // time_point<seconds> for each of the zone's transition types.
for (auto& tt : transition_types_) {
- tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
- tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
+ tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
+ tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
}
transitions_.shrink_to_fit();
@@ -590,57 +590,57 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
namespace {
-// fopen(3) adaptor.
-inline FILE* FOpen(const char* path, const char* mode) {
-#if defined(_MSC_VER)
- FILE* fp;
- if (fopen_s(&fp, path, mode) != 0) fp = nullptr;
- return fp;
-#else
- return fopen(path, mode); // TODO: Enable the close-on-exec flag.
-#endif
-}
-
+// fopen(3) adaptor.
+inline FILE* FOpen(const char* path, const char* mode) {
+#if defined(_MSC_VER)
+ FILE* fp;
+ if (fopen_s(&fp, path, mode) != 0) fp = nullptr;
+ return fp;
+#else
+ return fopen(path, mode); // TODO: Enable the close-on-exec flag.
+#endif
+}
+
// A stdio(3)-backed implementation of ZoneInfoSource.
class FileZoneInfoSource : public ZoneInfoSource {
public:
static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
std::size_t Read(void* ptr, std::size_t size) override {
- size = std::min(size, len_);
- std::size_t nread = fread(ptr, 1, size, fp_.get());
- len_ -= nread;
- return nread;
+ size = std::min(size, len_);
+ std::size_t nread = fread(ptr, 1, size, fp_.get());
+ len_ -= nread;
+ return nread;
}
int Skip(std::size_t offset) override {
- offset = std::min(offset, len_);
- int rc = fseek(fp_.get(), static_cast<long>(offset), SEEK_CUR);
- if (rc == 0) len_ -= offset;
- return rc;
- }
- std::string Version() const override {
- // TODO: It would nice if the zoneinfo data included the tzdb version.
- return std::string();
- }
-
- protected:
- explicit FileZoneInfoSource(
- FILE* fp, std::size_t len = std::numeric_limits<std::size_t>::max())
- : fp_(fp, fclose), len_(len) {}
-
+ offset = std::min(offset, len_);
+ int rc = fseek(fp_.get(), static_cast<long>(offset), SEEK_CUR);
+ if (rc == 0) len_ -= offset;
+ return rc;
+ }
+ std::string Version() const override {
+ // TODO: It would nice if the zoneinfo data included the tzdb version.
+ return std::string();
+ }
+
+ protected:
+ explicit FileZoneInfoSource(
+ FILE* fp, std::size_t len = std::numeric_limits<std::size_t>::max())
+ : fp_(fp, fclose), len_(len) {}
+
private:
- std::unique_ptr<FILE, int(*)(FILE*)> fp_;
- std::size_t len_;
+ std::unique_ptr<FILE, int(*)(FILE*)> fp_;
+ std::size_t len_;
};
std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open(
const std::string& name) {
// Use of the "file:" prefix is intended for testing purposes only.
- const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
+ const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
// Map the time-zone name to a path name.
std::string path;
- if (pos == name.size() || name[pos] != '/') {
+ if (pos == name.size() || name[pos] != '/') {
const char* tzdir = "/usr/share/zoneinfo";
char* tzdir_env = nullptr;
#if defined(_MSC_VER)
@@ -655,76 +655,76 @@ std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open(
free(tzdir_env);
#endif
}
- path.append(name, pos, std::string::npos);
+ path.append(name, pos, std::string::npos);
// Open the zoneinfo file.
- FILE* fp = FOpen(path.c_str(), "rb");
+ FILE* fp = FOpen(path.c_str(), "rb");
if (fp == nullptr) return nullptr;
- std::size_t length = 0;
- if (fseek(fp, 0, SEEK_END) == 0) {
- long offset = ftell(fp);
- if (offset >= 0) {
- length = static_cast<std::size_t>(offset);
- }
- rewind(fp);
- }
- return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(fp, length));
+ std::size_t length = 0;
+ if (fseek(fp, 0, SEEK_END) == 0) {
+ long offset = ftell(fp);
+ if (offset >= 0) {
+ length = static_cast<std::size_t>(offset);
+ }
+ rewind(fp);
+ }
+ return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(fp, length));
+}
+
+class AndroidZoneInfoSource : public FileZoneInfoSource {
+ public:
+ static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
+ std::string Version() const override { return version_; }
+
+ private:
+ explicit AndroidZoneInfoSource(FILE* fp, std::size_t len, const char* vers)
+ : FileZoneInfoSource(fp, len), version_(vers) {}
+ std::string version_;
+};
+
+std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
+ const std::string& name) {
+ // Use of the "file:" prefix is intended for testing purposes only.
+ const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
+
+ // See Android's libc/tzcode/bionic.cpp for additional information.
+ for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
+ "/system/usr/share/zoneinfo/tzdata"}) {
+ std::unique_ptr<FILE, int (*)(FILE*)> fp(FOpen(tzdata, "rb"), fclose);
+ if (fp.get() == nullptr) continue;
+
+ char hbuf[24]; // covers header.zonetab_offset too
+ if (fread(hbuf, 1, sizeof(hbuf), fp.get()) != sizeof(hbuf)) continue;
+ if (strncmp(hbuf, "tzdata", 6) != 0) continue;
+ const char* vers = (hbuf[11] == '\0') ? hbuf + 6 : "";
+ const std::int_fast32_t index_offset = Decode32(hbuf + 12);
+ const std::int_fast32_t data_offset = Decode32(hbuf + 16);
+ if (index_offset < 0 || data_offset < index_offset) continue;
+ if (fseek(fp.get(), static_cast<long>(index_offset), SEEK_SET) != 0)
+ continue;
+
+ char ebuf[52]; // covers entry.unused too
+ const std::size_t index_size =
+ static_cast<std::size_t>(data_offset - index_offset);
+ const std::size_t zonecnt = index_size / sizeof(ebuf);
+ if (zonecnt * sizeof(ebuf) != index_size) continue;
+ for (std::size_t i = 0; i != zonecnt; ++i) {
+ if (fread(ebuf, 1, sizeof(ebuf), fp.get()) != sizeof(ebuf)) break;
+ const std::int_fast32_t start = data_offset + Decode32(ebuf + 40);
+ const std::int_fast32_t length = Decode32(ebuf + 44);
+ if (start < 0 || length < 0) break;
+ ebuf[40] = '\0'; // ensure zone name is NUL terminated
+ if (strcmp(name.c_str() + pos, ebuf) == 0) {
+ if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break;
+ return std::unique_ptr<ZoneInfoSource>(new AndroidZoneInfoSource(
+ fp.release(), static_cast<std::size_t>(length), vers));
+ }
+ }
+ }
+
+ return nullptr;
}
-class AndroidZoneInfoSource : public FileZoneInfoSource {
- public:
- static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
- std::string Version() const override { return version_; }
-
- private:
- explicit AndroidZoneInfoSource(FILE* fp, std::size_t len, const char* vers)
- : FileZoneInfoSource(fp, len), version_(vers) {}
- std::string version_;
-};
-
-std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
- const std::string& name) {
- // Use of the "file:" prefix is intended for testing purposes only.
- const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
-
- // See Android's libc/tzcode/bionic.cpp for additional information.
- for (const char* tzdata : {"/data/misc/zoneinfo/current/tzdata",
- "/system/usr/share/zoneinfo/tzdata"}) {
- std::unique_ptr<FILE, int (*)(FILE*)> fp(FOpen(tzdata, "rb"), fclose);
- if (fp.get() == nullptr) continue;
-
- char hbuf[24]; // covers header.zonetab_offset too
- if (fread(hbuf, 1, sizeof(hbuf), fp.get()) != sizeof(hbuf)) continue;
- if (strncmp(hbuf, "tzdata", 6) != 0) continue;
- const char* vers = (hbuf[11] == '\0') ? hbuf + 6 : "";
- const std::int_fast32_t index_offset = Decode32(hbuf + 12);
- const std::int_fast32_t data_offset = Decode32(hbuf + 16);
- if (index_offset < 0 || data_offset < index_offset) continue;
- if (fseek(fp.get(), static_cast<long>(index_offset), SEEK_SET) != 0)
- continue;
-
- char ebuf[52]; // covers entry.unused too
- const std::size_t index_size =
- static_cast<std::size_t>(data_offset - index_offset);
- const std::size_t zonecnt = index_size / sizeof(ebuf);
- if (zonecnt * sizeof(ebuf) != index_size) continue;
- for (std::size_t i = 0; i != zonecnt; ++i) {
- if (fread(ebuf, 1, sizeof(ebuf), fp.get()) != sizeof(ebuf)) break;
- const std::int_fast32_t start = data_offset + Decode32(ebuf + 40);
- const std::int_fast32_t length = Decode32(ebuf + 44);
- if (start < 0 || length < 0) break;
- ebuf[40] = '\0'; // ensure zone name is NUL terminated
- if (strcmp(name.c_str() + pos, ebuf) == 0) {
- if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break;
- return std::unique_ptr<ZoneInfoSource>(new AndroidZoneInfoSource(
- fp.release(), static_cast<std::size_t>(length), vers));
- }
- }
- }
-
- return nullptr;
-}
-
} // namespace
bool TimeZoneInfo::Load(const std::string& name) {
@@ -732,19 +732,19 @@ bool TimeZoneInfo::Load(const std::string& name) {
// zone never fails because the simple, fixed-offset state can be
// internally generated. Note that this depends on our choice to not
// accept leap-second encoded ("right") zoneinfo.
- auto offset = seconds::zero();
+ auto offset = seconds::zero();
if (FixedOffsetFromName(name, &offset)) {
return ResetToBuiltinUTC(offset);
}
// Find and use a ZoneInfoSource to load the named zone.
auto zip = cctz_extension::zone_info_source_factory(
- name, [](const std::string& n) -> std::unique_ptr<ZoneInfoSource> {
- if (auto z = FileZoneInfoSource::Open(n)) return z;
- if (auto z = AndroidZoneInfoSource::Open(n)) return z;
- return nullptr;
+ name, [](const std::string& n) -> std::unique_ptr<ZoneInfoSource> {
+ if (auto z = FileZoneInfoSource::Open(n)) return z;
+ if (auto z = AndroidZoneInfoSource::Open(n)) return z;
+ return nullptr;
});
- return zip != nullptr && Load(zip.get());
+ return zip != nullptr && Load(zip.get());
}
// BreakTime() translation for a particular transition type.
@@ -769,17 +769,17 @@ time_zone::absolute_lookup TimeZoneInfo::LocalTime(
// MakeTime() translation with a conversion-preserving +N * 400-year shift.
time_zone::civil_lookup TimeZoneInfo::TimeLocal(const civil_second& cs,
- year_t c4_shift) const {
+ year_t c4_shift) const {
assert(last_year_ - 400 < cs.year() && cs.year() <= last_year_);
time_zone::civil_lookup cl = MakeTime(cs);
- if (c4_shift > seconds::max().count() / kSecsPer400Years) {
- cl.pre = cl.trans = cl.post = time_point<seconds>::max();
+ if (c4_shift > seconds::max().count() / kSecsPer400Years) {
+ cl.pre = cl.trans = cl.post = time_point<seconds>::max();
} else {
- const auto offset = seconds(c4_shift * kSecsPer400Years);
- const auto limit = time_point<seconds>::max() - offset;
+ const auto offset = seconds(c4_shift * kSecsPer400Years);
+ const auto limit = time_point<seconds>::max() - offset;
for (auto* tp : {&cl.pre, &cl.trans, &cl.post}) {
if (*tp > limit) {
- *tp = time_point<seconds>::max();
+ *tp = time_point<seconds>::max();
} else {
*tp += offset;
}
@@ -789,7 +789,7 @@ time_zone::civil_lookup TimeZoneInfo::TimeLocal(const civil_second& cs,
}
time_zone::absolute_lookup TimeZoneInfo::BreakTime(
- const time_point<seconds>& tp) const {
+ const time_point<seconds>& tp) const {
std::int_fast64_t unix_time = ToUnixSeconds(tp);
const std::size_t timecnt = transitions_.size();
assert(timecnt != 0); // We always add a transition.
@@ -804,8 +804,8 @@ time_zone::absolute_lookup TimeZoneInfo::BreakTime(
if (extended_) {
const std::int_fast64_t diff =
unix_time - transitions_[timecnt - 1].unix_time;
- const year_t shift = diff / kSecsPer400Years + 1;
- const auto d = seconds(shift * kSecsPer400Years);
+ const year_t shift = diff / kSecsPer400Years + 1;
+ const auto d = seconds(shift * kSecsPer400Years);
time_zone::absolute_lookup al = BreakTime(tp - d);
al.cs = YearShift(al.cs, shift * 400);
return al;
@@ -864,7 +864,7 @@ time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const {
if (tr->prev_civil_sec >= cs) {
// Before first transition, so use the default offset.
const TransitionType& tt(transition_types_[default_transition_type_]);
- if (cs < tt.civil_min) return MakeUnique(time_point<seconds>::min());
+ if (cs < tt.civil_min) return MakeUnique(time_point<seconds>::min());
return MakeUnique(cs - (civil_second() + tt.utc_offset));
}
// tr->prev_civil_sec < cs < tr->civil_sec
@@ -877,11 +877,11 @@ time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const {
// future_spec_, shift back to a supported year using the 400-year
// cycle of calendaric equivalence and then compensate accordingly.
if (extended_ && cs.year() > last_year_) {
- const year_t shift = (cs.year() - last_year_ - 1) / 400 + 1;
+ const year_t shift = (cs.year() - last_year_ - 1) / 400 + 1;
return TimeLocal(YearShift(cs, shift * -400), shift);
}
const TransitionType& tt(transition_types_[tr->type_index]);
- if (cs > tt.civil_max) return MakeUnique(time_point<seconds>::max());
+ if (cs > tt.civil_max) return MakeUnique(time_point<seconds>::max());
return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
}
// tr->civil_sec <= cs <= tr->prev_civil_sec
@@ -902,10 +902,10 @@ time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const {
return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
}
-std::string TimeZoneInfo::Version() const {
- return version_;
-}
-
+std::string TimeZoneInfo::Version() const {
+ return version_;
+}
+
std::string TimeZoneInfo::Description() const {
std::ostringstream oss;
oss << "#trans=" << transitions_.size();
@@ -914,64 +914,64 @@ std::string TimeZoneInfo::Description() const {
return oss.str();
}
-bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const {
+bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
+ time_zone::civil_transition* trans) const {
if (transitions_.empty()) return false;
const Transition* begin = &transitions_[0];
const Transition* end = begin + transitions_.size();
if (begin->unix_time <= -(1LL << 59)) {
- // Do not report the BIG_BANG found in some zoneinfo data as it is
- // really a sentinel, not a transition. See pre-2018f tz/zic.c.
+ // Do not report the BIG_BANG found in some zoneinfo data as it is
+ // really a sentinel, not a transition. See pre-2018f tz/zic.c.
++begin;
}
- std::int_fast64_t unix_time = ToUnixSeconds(tp);
- const Transition target = {unix_time, 0, civil_second(), civil_second()};
+ std::int_fast64_t unix_time = ToUnixSeconds(tp);
+ const Transition target = {unix_time, 0, civil_second(), civil_second()};
const Transition* tr = std::upper_bound(begin, end, target,
Transition::ByUnixTime());
- for (; tr != end; ++tr) { // skip no-op transitions
- std::uint_fast8_t prev_type_index =
- (tr == begin) ? default_transition_type_ : tr[-1].type_index;
- if (!EquivTransitions(prev_type_index, tr[0].type_index)) break;
+ for (; tr != end; ++tr) { // skip no-op transitions
+ std::uint_fast8_t prev_type_index =
+ (tr == begin) ? default_transition_type_ : tr[-1].type_index;
+ if (!EquivTransitions(prev_type_index, tr[0].type_index)) break;
}
// When tr == end we return false, ignoring future_spec_.
if (tr == end) return false;
- trans->from = tr->prev_civil_sec + 1;
- trans->to = tr->civil_sec;
+ trans->from = tr->prev_civil_sec + 1;
+ trans->to = tr->civil_sec;
return true;
}
-bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const {
+bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp,
+ time_zone::civil_transition* trans) const {
if (transitions_.empty()) return false;
const Transition* begin = &transitions_[0];
const Transition* end = begin + transitions_.size();
if (begin->unix_time <= -(1LL << 59)) {
- // Do not report the BIG_BANG found in some zoneinfo data as it is
- // really a sentinel, not a transition. See pre-2018f tz/zic.c.
+ // Do not report the BIG_BANG found in some zoneinfo data as it is
+ // really a sentinel, not a transition. See pre-2018f tz/zic.c.
++begin;
}
- std::int_fast64_t unix_time = ToUnixSeconds(tp);
- if (FromUnixSeconds(unix_time) != tp) {
+ std::int_fast64_t unix_time = ToUnixSeconds(tp);
+ if (FromUnixSeconds(unix_time) != tp) {
if (unix_time == std::numeric_limits<std::int_fast64_t>::max()) {
if (end == begin) return false; // Ignore future_spec_.
- trans->from = (--end)->prev_civil_sec + 1;
- trans->to = end->civil_sec;
+ trans->from = (--end)->prev_civil_sec + 1;
+ trans->to = end->civil_sec;
return true;
}
unix_time += 1; // ceils
}
- const Transition target = {unix_time, 0, civil_second(), civil_second()};
+ const Transition target = {unix_time, 0, civil_second(), civil_second()};
const Transition* tr = std::lower_bound(begin, end, target,
Transition::ByUnixTime());
- for (; tr != begin; --tr) { // skip no-op transitions
- std::uint_fast8_t prev_type_index =
- (tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index;
- if (!EquivTransitions(prev_type_index, tr[-1].type_index)) break;
+ for (; tr != begin; --tr) { // skip no-op transitions
+ std::uint_fast8_t prev_type_index =
+ (tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index;
+ if (!EquivTransitions(prev_type_index, tr[-1].type_index)) break;
}
// When tr == end we return the "last" transition, ignoring future_spec_.
if (tr == begin) return false;
- trans->from = (--tr)->prev_civil_sec + 1;
- trans->to = tr->civil_sec;
+ trans->from = (--tr)->prev_civil_sec + 1;
+ trans->to = tr->civil_sec;
return true;
}
diff --git a/contrib/libs/cctz/src/time_zone_info.h b/contrib/libs/cctz/src/time_zone_info.h
index c8d1c789f9..431dc5b71b 100644
--- a/contrib/libs/cctz/src/time_zone_info.h
+++ b/contrib/libs/cctz/src/time_zone_info.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,9 +21,9 @@
#include <string>
#include <vector>
-#include "cctz/civil_time.h"
-#include "cctz/time_zone.h"
-#include "cctz/zone_info_source.h"
+#include "cctz/civil_time.h"
+#include "cctz/time_zone.h"
+#include "cctz/zone_info_source.h"
#include "time_zone_if.h"
#include "tzfile.h"
@@ -69,14 +69,14 @@ class TimeZoneInfo : public TimeZoneIf {
// TimeZoneIf implementations.
time_zone::absolute_lookup BreakTime(
- const time_point<seconds>& tp) const override;
+ const time_point<seconds>& tp) const override;
time_zone::civil_lookup MakeTime(
const civil_second& cs) const override;
- bool NextTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const override;
- bool PrevTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const override;
- std::string Version() const override;
+ bool NextTransition(const time_point<seconds>& tp,
+ time_zone::civil_transition* trans) const override;
+ bool PrevTransition(const time_point<seconds>& tp,
+ time_zone::civil_transition* trans) const override;
+ std::string Version() const override;
std::string Description() const override;
private:
@@ -86,20 +86,20 @@ class TimeZoneInfo : public TimeZoneIf {
std::size_t charcnt; // zone abbreviation characters
std::size_t leapcnt; // leap seconds (we expect none)
std::size_t ttisstdcnt; // UTC/local indicators (unused)
- std::size_t ttisutcnt; // standard/wall indicators (unused)
+ std::size_t ttisutcnt; // standard/wall indicators (unused)
bool Build(const tzhead& tzh);
std::size_t DataLength(std::size_t time_len) const;
};
- bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
- const std::string& abbr, std::uint_least8_t* index);
+ bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
+ const std::string& abbr, std::uint_least8_t* index);
bool EquivTransitions(std::uint_fast8_t tt1_index,
std::uint_fast8_t tt2_index) const;
- bool ExtendTransitions();
+ bool ExtendTransitions();
- bool ResetToBuiltinUTC(const seconds& offset);
- bool Load(ZoneInfoSource* zip);
+ bool ResetToBuiltinUTC(const seconds& offset);
+ bool Load(ZoneInfoSource* zip);
// Helpers for BreakTime() and MakeTime().
time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
@@ -107,17 +107,17 @@ class TimeZoneInfo : public TimeZoneIf {
time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
const Transition& tr) const;
time_zone::civil_lookup TimeLocal(const civil_second& cs,
- year_t c4_shift) const;
+ year_t c4_shift) const;
std::vector<Transition> transitions_; // ordered by unix_time and civil_sec
std::vector<TransitionType> transition_types_; // distinct transition types
std::uint_fast8_t default_transition_type_; // for before first transition
std::string abbreviations_; // all the NUL-terminated abbreviations
- std::string version_; // the tzdata version if available
+ std::string version_; // the tzdata version if available
std::string future_spec_; // for after the last zic transition
bool extended_; // future_spec_ was used to generate transitions
- year_t last_year_; // the final year of the generated transitions
+ year_t last_year_; // the final year of the generated transitions
// We remember the transitions found during the last BreakTime() and
// MakeTime() calls. If the next request is for the same transition we
diff --git a/contrib/libs/cctz/src/time_zone_libc.cc b/contrib/libs/cctz/src/time_zone_libc.cc
index 43affa984a..f185b957b6 100644
--- a/contrib/libs/cctz/src/time_zone_libc.cc
+++ b/contrib/libs/cctz/src/time_zone_libc.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,299 +13,299 @@
// limitations under the License.
#if defined(_WIN32) || defined(_WIN64)
-#define _CRT_SECURE_NO_WARNINGS 1
+#define _CRT_SECURE_NO_WARNINGS 1
#endif
#include "time_zone_libc.h"
#include <chrono>
#include <ctime>
-#include <limits>
+#include <limits>
#include <utility>
-#include "cctz/civil_time.h"
-#include "cctz/time_zone.h"
+#include "cctz/civil_time.h"
+#include "cctz/time_zone.h"
+
+#if defined(_AIX)
+extern "C" {
+ extern long altzone;
+}
+#endif
-#if defined(_AIX)
-extern "C" {
- extern long altzone;
-}
-#endif
-
namespace cctz {
namespace {
#if defined(_WIN32) || defined(_WIN64)
// Uses the globals: '_timezone', '_dstbias' and '_tzname'.
-auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + _dstbias) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + _dstbias) {
const bool is_dst = tm.tm_isdst > 0;
- return _timezone + (is_dst ? _dstbias : 0);
+ return _timezone + (is_dst ? _dstbias : 0);
}
-auto tm_zone(const std::tm& tm) -> decltype(_tzname[0]) {
- const bool is_dst = tm.tm_isdst > 0;
- return _tzname[is_dst];
-}
-#elif defined(__sun) || defined(_AIX)
+auto tm_zone(const std::tm& tm) -> decltype(_tzname[0]) {
+ const bool is_dst = tm.tm_isdst > 0;
+ return _tzname[is_dst];
+}
+#elif defined(__sun) || defined(_AIX)
// Uses the globals: 'timezone', 'altzone' and 'tzname'.
-auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
+ const bool is_dst = tm.tm_isdst > 0;
+ return is_dst ? altzone : timezone;
+}
+auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
const bool is_dst = tm.tm_isdst > 0;
- return is_dst ? altzone : timezone;
+ return tzname[is_dst];
}
-auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
- const bool is_dst = tm.tm_isdst > 0;
- return tzname[is_dst];
-}
-#elif defined(__native_client__) || defined(__myriad2__) || \
- defined(__EMSCRIPTEN__)
+#elif defined(__native_client__) || defined(__myriad2__) || \
+ defined(__EMSCRIPTEN__)
// Uses the globals: 'timezone' and 'tzname'.
-auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) {
+auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) {
const bool is_dst = tm.tm_isdst > 0;
- return _timezone + (is_dst ? 60 * 60 : 0);
+ return _timezone + (is_dst ? 60 * 60 : 0);
+}
+auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
+ const bool is_dst = tm.tm_isdst > 0;
+ return tzname[is_dst];
+}
+#else
+// Adapt to different spellings of the struct std::tm extension fields.
+#if defined(tm_gmtoff)
+auto tm_gmtoff(const std::tm& tm) -> decltype(tm.tm_gmtoff) {
+ return tm.tm_gmtoff;
+}
+#elif defined(__tm_gmtoff)
+auto tm_gmtoff(const std::tm& tm) -> decltype(tm.__tm_gmtoff) {
+ return tm.__tm_gmtoff;
+}
+#else
+template <typename T>
+auto tm_gmtoff(const T& tm) -> decltype(tm.tm_gmtoff) {
+ return tm.tm_gmtoff;
+}
+template <typename T>
+auto tm_gmtoff(const T& tm) -> decltype(tm.__tm_gmtoff) {
+ return tm.__tm_gmtoff;
+}
+#endif // tm_gmtoff
+#if defined(tm_zone)
+auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) {
+ return tm.tm_zone;
+}
+#elif defined(__tm_zone)
+auto tm_zone(const std::tm& tm) -> decltype(tm.__tm_zone) {
+ return tm.__tm_zone;
}
-auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
- const bool is_dst = tm.tm_isdst > 0;
- return tzname[is_dst];
-}
#else
-// Adapt to different spellings of the struct std::tm extension fields.
-#if defined(tm_gmtoff)
-auto tm_gmtoff(const std::tm& tm) -> decltype(tm.tm_gmtoff) {
- return tm.tm_gmtoff;
-}
-#elif defined(__tm_gmtoff)
-auto tm_gmtoff(const std::tm& tm) -> decltype(tm.__tm_gmtoff) {
- return tm.__tm_gmtoff;
-}
-#else
template <typename T>
-auto tm_gmtoff(const T& tm) -> decltype(tm.tm_gmtoff) {
- return tm.tm_gmtoff;
+auto tm_zone(const T& tm) -> decltype(tm.tm_zone) {
+ return tm.tm_zone;
}
template <typename T>
-auto tm_gmtoff(const T& tm) -> decltype(tm.__tm_gmtoff) {
- return tm.__tm_gmtoff;
+auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) {
+ return tm.__tm_zone;
}
-#endif // tm_gmtoff
-#if defined(tm_zone)
-auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) {
- return tm.tm_zone;
-}
-#elif defined(__tm_zone)
-auto tm_zone(const std::tm& tm) -> decltype(tm.__tm_zone) {
- return tm.__tm_zone;
-}
-#else
-template <typename T>
-auto tm_zone(const T& tm) -> decltype(tm.tm_zone) {
- return tm.tm_zone;
-}
-template <typename T>
-auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) {
- return tm.__tm_zone;
-}
-#endif // tm_zone
+#endif // tm_zone
+#endif
+
+inline std::tm* gm_time(const std::time_t *timep, std::tm *result) {
+#if defined(_WIN32) || defined(_WIN64)
+ return gmtime_s(result, timep) ? nullptr : result;
+#else
+ return gmtime_r(timep, result);
#endif
+}
+
+inline std::tm* local_time(const std::time_t *timep, std::tm *result) {
+#if defined(_WIN32) || defined(_WIN64)
+ return localtime_s(result, timep) ? nullptr : result;
+#else
+ return localtime_r(timep, result);
+#endif
+}
+
+// Converts a civil second and "dst" flag into a time_t and UTC offset.
+// Returns false if time_t cannot represent the requested civil second.
+// Caller must have already checked that cs.year() will fit into a tm_year.
+bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
+ std::tm tm;
+ tm.tm_year = static_cast<int>(cs.year() - year_t{1900});
+ tm.tm_mon = cs.month() - 1;
+ tm.tm_mday = cs.day();
+ tm.tm_hour = cs.hour();
+ tm.tm_min = cs.minute();
+ tm.tm_sec = cs.second();
+ tm.tm_isdst = is_dst;
+ *t = std::mktime(&tm);
+ if (*t == std::time_t{-1}) {
+ std::tm tm2;
+ const std::tm* tmp = local_time(t, &tm2);
+ if (tmp == nullptr || tmp->tm_year != tm.tm_year ||
+ tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday ||
+ tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min ||
+ tmp->tm_sec != tm.tm_sec) {
+ // A true error (not just one second before the epoch).
+ return false;
+ }
+ }
+ *off = static_cast<int>(tm_gmtoff(tm));
+ return true;
+}
+
+// Find the least time_t in [lo:hi] where local time matches offset, given:
+// (1) lo doesn't match, (2) hi does, and (3) there is only one transition.
+std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
+ std::tm tm;
+ while (lo + 1 != hi) {
+ const std::time_t mid = lo + (hi - lo) / 2;
+ std::tm* tmp = local_time(&mid, &tm);
+ if (tmp != nullptr) {
+ if (tm_gmtoff(*tmp) == offset) {
+ hi = mid;
+ } else {
+ lo = mid;
+ }
+ } else {
+ // If std::tm cannot hold some result we resort to a linear search,
+ // ignoring all failed conversions. Slow, but never really happens.
+ while (++lo != hi) {
+ tmp = local_time(&lo, &tm);
+ if (tmp != nullptr) {
+ if (tm_gmtoff(*tmp) == offset) break;
+ }
+ }
+ return lo;
+ }
+ }
+ return hi;
+}
-inline std::tm* gm_time(const std::time_t *timep, std::tm *result) {
-#if defined(_WIN32) || defined(_WIN64)
- return gmtime_s(result, timep) ? nullptr : result;
-#else
- return gmtime_r(timep, result);
-#endif
-}
-
-inline std::tm* local_time(const std::time_t *timep, std::tm *result) {
-#if defined(_WIN32) || defined(_WIN64)
- return localtime_s(result, timep) ? nullptr : result;
-#else
- return localtime_r(timep, result);
-#endif
-}
-
-// Converts a civil second and "dst" flag into a time_t and UTC offset.
-// Returns false if time_t cannot represent the requested civil second.
-// Caller must have already checked that cs.year() will fit into a tm_year.
-bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
- std::tm tm;
- tm.tm_year = static_cast<int>(cs.year() - year_t{1900});
- tm.tm_mon = cs.month() - 1;
- tm.tm_mday = cs.day();
- tm.tm_hour = cs.hour();
- tm.tm_min = cs.minute();
- tm.tm_sec = cs.second();
- tm.tm_isdst = is_dst;
- *t = std::mktime(&tm);
- if (*t == std::time_t{-1}) {
- std::tm tm2;
- const std::tm* tmp = local_time(t, &tm2);
- if (tmp == nullptr || tmp->tm_year != tm.tm_year ||
- tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday ||
- tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min ||
- tmp->tm_sec != tm.tm_sec) {
- // A true error (not just one second before the epoch).
- return false;
- }
- }
- *off = static_cast<int>(tm_gmtoff(tm));
- return true;
-}
-
-// Find the least time_t in [lo:hi] where local time matches offset, given:
-// (1) lo doesn't match, (2) hi does, and (3) there is only one transition.
-std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
- std::tm tm;
- while (lo + 1 != hi) {
- const std::time_t mid = lo + (hi - lo) / 2;
- std::tm* tmp = local_time(&mid, &tm);
- if (tmp != nullptr) {
- if (tm_gmtoff(*tmp) == offset) {
- hi = mid;
- } else {
- lo = mid;
- }
- } else {
- // If std::tm cannot hold some result we resort to a linear search,
- // ignoring all failed conversions. Slow, but never really happens.
- while (++lo != hi) {
- tmp = local_time(&lo, &tm);
- if (tmp != nullptr) {
- if (tm_gmtoff(*tmp) == offset) break;
- }
- }
- return lo;
- }
- }
- return hi;
-}
-
} // namespace
TimeZoneLibC::TimeZoneLibC(const std::string& name)
: local_(name == "localtime") {}
time_zone::absolute_lookup TimeZoneLibC::BreakTime(
- const time_point<seconds>& tp) const {
+ const time_point<seconds>& tp) const {
time_zone::absolute_lookup al;
- al.offset = 0;
- al.is_dst = false;
- al.abbr = "-00";
-
- const std::int_fast64_t s = ToUnixSeconds(tp);
-
- // If std::time_t cannot hold the input we saturate the output.
- if (s < std::numeric_limits<std::time_t>::min()) {
- al.cs = civil_second::min();
- return al;
- }
- if (s > std::numeric_limits<std::time_t>::max()) {
- al.cs = civil_second::max();
- return al;
- }
-
- const std::time_t t = static_cast<std::time_t>(s);
+ al.offset = 0;
+ al.is_dst = false;
+ al.abbr = "-00";
+
+ const std::int_fast64_t s = ToUnixSeconds(tp);
+
+ // If std::time_t cannot hold the input we saturate the output.
+ if (s < std::numeric_limits<std::time_t>::min()) {
+ al.cs = civil_second::min();
+ return al;
+ }
+ if (s > std::numeric_limits<std::time_t>::max()) {
+ al.cs = civil_second::max();
+ return al;
+ }
+
+ const std::time_t t = static_cast<std::time_t>(s);
std::tm tm;
- std::tm* tmp = local_ ? local_time(&t, &tm) : gm_time(&t, &tm);
-
- // If std::tm cannot hold the result we saturate the output.
- if (tmp == nullptr) {
- al.cs = (s < 0) ? civil_second::min() : civil_second::max();
- return al;
+ std::tm* tmp = local_ ? local_time(&t, &tm) : gm_time(&t, &tm);
+
+ // If std::tm cannot hold the result we saturate the output.
+ if (tmp == nullptr) {
+ al.cs = (s < 0) ? civil_second::min() : civil_second::max();
+ return al;
}
-
- const year_t year = tmp->tm_year + year_t{1900};
- al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
- tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
- al.offset = static_cast<int>(tm_gmtoff(*tmp));
- al.abbr = local_ ? tm_zone(*tmp) : "UTC"; // as expected by cctz
- al.is_dst = tmp->tm_isdst > 0;
+
+ const year_t year = tmp->tm_year + year_t{1900};
+ al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
+ tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+ al.offset = static_cast<int>(tm_gmtoff(*tmp));
+ al.abbr = local_ ? tm_zone(*tmp) : "UTC"; // as expected by cctz
+ al.is_dst = tmp->tm_isdst > 0;
return al;
}
time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
- if (!local_) {
- // If time_point<seconds> cannot hold the result we saturate.
- static const civil_second min_tp_cs =
- civil_second() + ToUnixSeconds(time_point<seconds>::min());
- static const civil_second max_tp_cs =
- civil_second() + ToUnixSeconds(time_point<seconds>::max());
- const time_point<seconds> tp =
- (cs < min_tp_cs)
- ? time_point<seconds>::min()
- : (cs > max_tp_cs) ? time_point<seconds>::max()
- : FromUnixSeconds(cs - civil_second());
- return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
- }
-
- // If tm_year cannot hold the requested year we saturate the result.
- if (cs.year() < 0) {
- if (cs.year() < std::numeric_limits<int>::min() + year_t{1900}) {
- const time_point<seconds> tp = time_point<seconds>::min();
- return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
- }
+ if (!local_) {
+ // If time_point<seconds> cannot hold the result we saturate.
+ static const civil_second min_tp_cs =
+ civil_second() + ToUnixSeconds(time_point<seconds>::min());
+ static const civil_second max_tp_cs =
+ civil_second() + ToUnixSeconds(time_point<seconds>::max());
+ const time_point<seconds> tp =
+ (cs < min_tp_cs)
+ ? time_point<seconds>::min()
+ : (cs > max_tp_cs) ? time_point<seconds>::max()
+ : FromUnixSeconds(cs - civil_second());
+ return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+ }
+
+ // If tm_year cannot hold the requested year we saturate the result.
+ if (cs.year() < 0) {
+ if (cs.year() < std::numeric_limits<int>::min() + year_t{1900}) {
+ const time_point<seconds> tp = time_point<seconds>::min();
+ return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+ }
} else {
- if (cs.year() - year_t{1900} > std::numeric_limits<int>::max()) {
- const time_point<seconds> tp = time_point<seconds>::max();
- return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
- }
+ if (cs.year() - year_t{1900} > std::numeric_limits<int>::max()) {
+ const time_point<seconds> tp = time_point<seconds>::max();
+ return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+ }
}
- // We probe with "is_dst" values of 0 and 1 to try to distinguish unique
- // civil seconds from skipped or repeated ones. This is not always possible
- // however, as the "dst" flag does not change over some offset transitions.
- // We are also subject to the vagaries of mktime() implementations.
- std::time_t t0, t1;
- int offset0, offset1;
- if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) {
- if (t0 == t1) {
- // The civil time was singular (pre == trans == post).
- const time_point<seconds> tp = FromUnixSeconds(t0);
- return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
- }
-
- if (t0 > t1) {
- std::swap(t0, t1);
- std::swap(offset0, offset1);
- }
- const std::time_t tt = find_trans(t0, t1, offset1);
- const time_point<seconds> trans = FromUnixSeconds(tt);
-
- if (offset0 < offset1) {
- // The civil time did not exist (pre >= trans > post).
- const time_point<seconds> pre = FromUnixSeconds(t1);
- const time_point<seconds> post = FromUnixSeconds(t0);
- return {time_zone::civil_lookup::SKIPPED, pre, trans, post};
- }
-
- // The civil time was ambiguous (pre < trans <= post).
- const time_point<seconds> pre = FromUnixSeconds(t0);
- const time_point<seconds> post = FromUnixSeconds(t1);
- return {time_zone::civil_lookup::REPEATED, pre, trans, post};
- }
-
- // make_time() failed somehow so we saturate the result.
- const time_point<seconds> tp = (cs < civil_second())
- ? time_point<seconds>::min()
- : time_point<seconds>::max();
- return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+ // We probe with "is_dst" values of 0 and 1 to try to distinguish unique
+ // civil seconds from skipped or repeated ones. This is not always possible
+ // however, as the "dst" flag does not change over some offset transitions.
+ // We are also subject to the vagaries of mktime() implementations.
+ std::time_t t0, t1;
+ int offset0, offset1;
+ if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) {
+ if (t0 == t1) {
+ // The civil time was singular (pre == trans == post).
+ const time_point<seconds> tp = FromUnixSeconds(t0);
+ return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
+ }
+
+ if (t0 > t1) {
+ std::swap(t0, t1);
+ std::swap(offset0, offset1);
+ }
+ const std::time_t tt = find_trans(t0, t1, offset1);
+ const time_point<seconds> trans = FromUnixSeconds(tt);
+
+ if (offset0 < offset1) {
+ // The civil time did not exist (pre >= trans > post).
+ const time_point<seconds> pre = FromUnixSeconds(t1);
+ const time_point<seconds> post = FromUnixSeconds(t0);
+ return {time_zone::civil_lookup::SKIPPED, pre, trans, post};
+ }
+
+ // The civil time was ambiguous (pre < trans <= post).
+ const time_point<seconds> pre = FromUnixSeconds(t0);
+ const time_point<seconds> post = FromUnixSeconds(t1);
+ return {time_zone::civil_lookup::REPEATED, pre, trans, post};
+ }
+
+ // make_time() failed somehow so we saturate the result.
+ const time_point<seconds> tp = (cs < civil_second())
+ ? time_point<seconds>::min()
+ : time_point<seconds>::max();
+ return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
}
-bool TimeZoneLibC::NextTransition(const time_point<seconds>&,
- time_zone::civil_transition*) const {
+bool TimeZoneLibC::NextTransition(const time_point<seconds>&,
+ time_zone::civil_transition*) const {
return false;
}
-bool TimeZoneLibC::PrevTransition(const time_point<seconds>&,
- time_zone::civil_transition*) const {
+bool TimeZoneLibC::PrevTransition(const time_point<seconds>&,
+ time_zone::civil_transition*) const {
return false;
}
-std::string TimeZoneLibC::Version() const {
- return std::string(); // unknown
-}
-
-std::string TimeZoneLibC::Description() const {
- return local_ ? "localtime" : "UTC";
-}
-
+std::string TimeZoneLibC::Version() const {
+ return std::string(); // unknown
+}
+
+std::string TimeZoneLibC::Description() const {
+ return local_ ? "localtime" : "UTC";
+}
+
} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_libc.h b/contrib/libs/cctz/src/time_zone_libc.h
index 7723c4289b..4cfe6dae31 100644
--- a/contrib/libs/cctz/src/time_zone_libc.h
+++ b/contrib/libs/cctz/src/time_zone_libc.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -30,14 +30,14 @@ class TimeZoneLibC : public TimeZoneIf {
// TimeZoneIf implementations.
time_zone::absolute_lookup BreakTime(
- const time_point<seconds>& tp) const override;
+ const time_point<seconds>& tp) const override;
time_zone::civil_lookup MakeTime(
const civil_second& cs) const override;
- bool NextTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const override;
- bool PrevTransition(const time_point<seconds>& tp,
- time_zone::civil_transition* trans) const override;
- std::string Version() const override;
+ bool NextTransition(const time_point<seconds>& tp,
+ time_zone::civil_transition* trans) const override;
+ bool PrevTransition(const time_point<seconds>& tp,
+ time_zone::civil_transition* trans) const override;
+ std::string Version() const override;
std::string Description() const override;
private:
diff --git a/contrib/libs/cctz/src/time_zone_lookup.cc b/contrib/libs/cctz/src/time_zone_lookup.cc
index b1c7f922d1..92eb2ae763 100644
--- a/contrib/libs/cctz/src/time_zone_lookup.cc
+++ b/contrib/libs/cctz/src/time_zone_lookup.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -12,20 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "cctz/time_zone.h"
-
-#if defined(__ANDROID__)
-#include <sys/system_properties.h>
-#if defined(__ANDROID_API__) && __ANDROID_API__ >= 21
-#include <dlfcn.h>
-#endif
-#endif
-
-#if defined(__APPLE__)
-#include <CoreFoundation/CFTimeZone.h>
-#include <vector>
-#endif
-
+#include "cctz/time_zone.h"
+
+#if defined(__ANDROID__)
+#include <sys/system_properties.h>
+#if defined(__ANDROID_API__) && __ANDROID_API__ >= 21
+#include <dlfcn.h>
+#endif
+#endif
+
+#if defined(__APPLE__)
+#include <CoreFoundation/CFTimeZone.h>
+#include <vector>
+#endif
+
#include <cstdlib>
#include <cstring>
#include <string>
@@ -35,75 +35,75 @@
namespace cctz {
-#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21
-namespace {
-// Android 'L' removes __system_property_get() from the NDK, however
-// it is still a hidden symbol in libc so we use dlsym() to access it.
-// See Chromium's base/sys_info_android.cc for a similar example.
-
-using property_get_func = int (*)(const char*, char*);
-
-property_get_func LoadSystemPropertyGet() {
- int flag = RTLD_LAZY | RTLD_GLOBAL;
-#if defined(RTLD_NOLOAD)
- flag |= RTLD_NOLOAD; // libc.so should already be resident
-#endif
- if (void* handle = dlopen("libc.so", flag)) {
- void* sym = dlsym(handle, "__system_property_get");
- dlclose(handle);
- return reinterpret_cast<property_get_func>(sym);
- }
- return nullptr;
-}
-
-int __system_property_get(const char* name, char* value) {
- static property_get_func system_property_get = LoadSystemPropertyGet();
- return system_property_get ? system_property_get(name, value) : -1;
-}
-
-} // namespace
-#endif
-
+#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21
+namespace {
+// Android 'L' removes __system_property_get() from the NDK, however
+// it is still a hidden symbol in libc so we use dlsym() to access it.
+// See Chromium's base/sys_info_android.cc for a similar example.
+
+using property_get_func = int (*)(const char*, char*);
+
+property_get_func LoadSystemPropertyGet() {
+ int flag = RTLD_LAZY | RTLD_GLOBAL;
+#if defined(RTLD_NOLOAD)
+ flag |= RTLD_NOLOAD; // libc.so should already be resident
+#endif
+ if (void* handle = dlopen("libc.so", flag)) {
+ void* sym = dlsym(handle, "__system_property_get");
+ dlclose(handle);
+ return reinterpret_cast<property_get_func>(sym);
+ }
+ return nullptr;
+}
+
+int __system_property_get(const char* name, char* value) {
+ static property_get_func system_property_get = LoadSystemPropertyGet();
+ return system_property_get ? system_property_get(name, value) : -1;
+}
+
+} // namespace
+#endif
+
std::string time_zone::name() const {
- return effective_impl().Name();
+ return effective_impl().Name();
}
time_zone::absolute_lookup time_zone::lookup(
- const time_point<seconds>& tp) const {
- return effective_impl().BreakTime(tp);
+ const time_point<seconds>& tp) const {
+ return effective_impl().BreakTime(tp);
}
time_zone::civil_lookup time_zone::lookup(const civil_second& cs) const {
- return effective_impl().MakeTime(cs);
+ return effective_impl().MakeTime(cs);
+}
+
+bool time_zone::next_transition(const time_point<seconds>& tp,
+ civil_transition* trans) const {
+ return effective_impl().NextTransition(tp, trans);
+}
+
+bool time_zone::prev_transition(const time_point<seconds>& tp,
+ civil_transition* trans) const {
+ return effective_impl().PrevTransition(tp, trans);
+}
+
+std::string time_zone::version() const {
+ return effective_impl().Version();
}
-bool time_zone::next_transition(const time_point<seconds>& tp,
- civil_transition* trans) const {
- return effective_impl().NextTransition(tp, trans);
+std::string time_zone::description() const {
+ return effective_impl().Description();
+}
+
+const time_zone::Impl& time_zone::effective_impl() const {
+ if (impl_ == nullptr) {
+ // Dereferencing an implicit-UTC time_zone is expected to be
+ // rare, so we don't mind paying a small synchronization cost.
+ return *time_zone::Impl::UTC().impl_;
+ }
+ return *impl_;
}
-bool time_zone::prev_transition(const time_point<seconds>& tp,
- civil_transition* trans) const {
- return effective_impl().PrevTransition(tp, trans);
-}
-
-std::string time_zone::version() const {
- return effective_impl().Version();
-}
-
-std::string time_zone::description() const {
- return effective_impl().Description();
-}
-
-const time_zone::Impl& time_zone::effective_impl() const {
- if (impl_ == nullptr) {
- // Dereferencing an implicit-UTC time_zone is expected to be
- // rare, so we don't mind paying a small synchronization cost.
- return *time_zone::Impl::UTC().impl_;
- }
- return *impl_;
-}
-
bool load_time_zone(const std::string& name, time_zone* tz) {
return time_zone::Impl::LoadTimeZone(name, tz);
}
@@ -112,7 +112,7 @@ time_zone utc_time_zone() {
return time_zone::Impl::UTC(); // avoid name lookup
}
-time_zone fixed_time_zone(const seconds& offset) {
+time_zone fixed_time_zone(const seconds& offset) {
time_zone tz;
load_time_zone(FixedOffsetToName(offset), &tz);
return tz;
@@ -120,25 +120,25 @@ time_zone fixed_time_zone(const seconds& offset) {
time_zone local_time_zone() {
const char* zone = ":localtime";
-#if defined(__ANDROID__)
- char sysprop[PROP_VALUE_MAX];
- if (__system_property_get("persist.sys.timezone", sysprop) > 0) {
- zone = sysprop;
- }
-#endif
-#if defined(__APPLE__)
- std::vector<char> buffer;
- CFTimeZoneRef tz_default = CFTimeZoneCopyDefault();
- if (CFStringRef tz_name = CFTimeZoneGetName(tz_default)) {
- CFStringEncoding encoding = kCFStringEncodingUTF8;
- CFIndex length = CFStringGetLength(tz_name);
- buffer.resize(CFStringGetMaximumSizeForEncoding(length, encoding) + 1);
- if (CFStringGetCString(tz_name, &buffer[0], buffer.size(), encoding)) {
- zone = &buffer[0];
- }
- }
- CFRelease(tz_default);
-#endif
+#if defined(__ANDROID__)
+ char sysprop[PROP_VALUE_MAX];
+ if (__system_property_get("persist.sys.timezone", sysprop) > 0) {
+ zone = sysprop;
+ }
+#endif
+#if defined(__APPLE__)
+ std::vector<char> buffer;
+ CFTimeZoneRef tz_default = CFTimeZoneCopyDefault();
+ if (CFStringRef tz_name = CFTimeZoneGetName(tz_default)) {
+ CFStringEncoding encoding = kCFStringEncodingUTF8;
+ CFIndex length = CFStringGetLength(tz_name);
+ buffer.resize(CFStringGetMaximumSizeForEncoding(length, encoding) + 1);
+ if (CFStringGetCString(tz_name, &buffer[0], buffer.size(), encoding)) {
+ zone = &buffer[0];
+ }
+ }
+ CFRelease(tz_default);
+#endif
// Allow ${TZ} to override to default zone.
char* tz_env = nullptr;
@@ -174,9 +174,9 @@ time_zone local_time_zone() {
time_zone tz;
load_time_zone(name, &tz); // Falls back to UTC.
- // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
- // arrange for %z to generate "-0000" when we don't know the local
- // offset because the load_time_zone() failed and we're using UTC.
+ // TODO: Follow the RFC3339 "Unknown Local Offset Convention" and
+ // arrange for %z to generate "-0000" when we don't know the local
+ // offset because the load_time_zone() failed and we're using UTC.
return tz;
}
diff --git a/contrib/libs/cctz/src/time_zone_posix.cc b/contrib/libs/cctz/src/time_zone_posix.cc
index 88790aa0a0..847db17cbc 100644
--- a/contrib/libs/cctz/src/time_zone_posix.cc
+++ b/contrib/libs/cctz/src/time_zone_posix.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -98,9 +98,9 @@ const char* ParseDateTime(const char* p, PosixTransition* res) {
int weekday = 0;
if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) {
res->date.fmt = PosixTransition::M;
- res->date.m.month = static_cast<std::int_fast8_t>(month);
- res->date.m.week = static_cast<std::int_fast8_t>(week);
- res->date.m.weekday = static_cast<std::int_fast8_t>(weekday);
+ res->date.m.month = static_cast<std::int_fast8_t>(month);
+ res->date.m.week = static_cast<std::int_fast8_t>(week);
+ res->date.m.weekday = static_cast<std::int_fast8_t>(weekday);
}
}
}
@@ -108,13 +108,13 @@ const char* ParseDateTime(const char* p, PosixTransition* res) {
int day = 0;
if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) {
res->date.fmt = PosixTransition::J;
- res->date.j.day = static_cast<std::int_fast16_t>(day);
+ res->date.j.day = static_cast<std::int_fast16_t>(day);
}
} else {
int day = 0;
if ((p = ParseInt(p, 0, 365, &day)) != nullptr) {
res->date.fmt = PosixTransition::N;
- res->date.n.day = static_cast<std::int_fast16_t>(day);
+ res->date.n.day = static_cast<std::int_fast16_t>(day);
}
}
}
diff --git a/contrib/libs/cctz/src/time_zone_posix.h b/contrib/libs/cctz/src/time_zone_posix.h
index ccf9f48e47..aea93efdff 100644
--- a/contrib/libs/cctz/src/time_zone_posix.h
+++ b/contrib/libs/cctz/src/time_zone_posix.h
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -66,35 +66,35 @@ namespace cctz {
// it would take us to another day, and perhaps week, or even month.
struct PosixTransition {
enum DateFormat { J, N, M };
-
- struct Date {
- struct NonLeapDay {
- std::int_fast16_t day; // day of non-leap year [1:365]
- };
- struct Day {
- std::int_fast16_t day; // day of year [0:365]
- };
- struct MonthWeekWeekday {
- std::int_fast8_t month; // month of year [1:12]
- std::int_fast8_t week; // week of month [1:5] (5==last)
- std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat
- };
-
+
+ struct Date {
+ struct NonLeapDay {
+ std::int_fast16_t day; // day of non-leap year [1:365]
+ };
+ struct Day {
+ std::int_fast16_t day; // day of year [0:365]
+ };
+ struct MonthWeekWeekday {
+ std::int_fast8_t month; // month of year [1:12]
+ std::int_fast8_t week; // week of month [1:5] (5==last)
+ std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat
+ };
+
DateFormat fmt;
-
+
union {
- NonLeapDay j;
- Day n;
- MonthWeekWeekday m;
+ NonLeapDay j;
+ Day n;
+ MonthWeekWeekday m;
};
- };
-
- struct Time {
+ };
+
+ struct Time {
std::int_fast32_t offset; // seconds before/after 00:00:00
- };
-
- Date date;
- Time time;
+ };
+
+ Date date;
+ Time time;
};
// The entirety of a POSIX-string specified time-zone rule. The standard
diff --git a/contrib/libs/cctz/src/tzfile.h b/contrib/libs/cctz/src/tzfile.h
index 06fb33f953..ee91104443 100644
--- a/contrib/libs/cctz/src/tzfile.h
+++ b/contrib/libs/cctz/src/tzfile.h
@@ -1,5 +1,5 @@
-/* Layout and location of TZif files. */
-
+/* Layout and location of TZif files. */
+
#ifndef TZFILE_H
#define TZFILE_H
@@ -22,20 +22,20 @@
*/
#ifndef TZDIR
-#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */
+#define TZDIR "/usr/share/zoneinfo" /* Time zone object file directory */
#endif /* !defined TZDIR */
#ifndef TZDEFAULT
-#define TZDEFAULT "/etc/localtime"
+#define TZDEFAULT "/etc/localtime"
#endif /* !defined TZDEFAULT */
#ifndef TZDEFRULES
#define TZDEFRULES "posixrules"
#endif /* !defined TZDEFRULES */
-
-/* See Internet RFC 8536 for more details about the following format. */
-
+
+/* See Internet RFC 8536 for more details about the following format. */
+
/*
** Each file begins with. . .
*/
@@ -46,7 +46,7 @@ struct tzhead {
char tzh_magic[4]; /* TZ_MAGIC */
char tzh_version[1]; /* '\0' or '2' or '3' as of 2013 */
char tzh_reserved[15]; /* reserved; must be zero */
- char tzh_ttisutcnt[4]; /* coded number of trans. time flags */
+ char tzh_ttisutcnt[4]; /* coded number of trans. time flags */
char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
char tzh_leapcnt[4]; /* coded number of leap seconds */
char tzh_timecnt[4]; /* coded number of transition times */
@@ -69,15 +69,15 @@ struct tzhead {
** one (char [4]) total correction after above
** tzh_ttisstdcnt (char)s indexed by type; if 1, transition
** time is standard time, if 0,
-** transition time is local (wall clock)
-** time; if absent, transition times are
+** transition time is local (wall clock)
+** time; if absent, transition times are
** assumed to be local time
-** tzh_ttisutcnt (char)s indexed by type; if 1, transition
-** time is UT, if 0, transition time is
-** local time; if absent, transition
-** times are assumed to be local time.
-** When this is 1, the corresponding
-** std/wall indicator must also be 1.
+** tzh_ttisutcnt (char)s indexed by type; if 1, transition
+** time is UT, if 0, transition time is
+** local time; if absent, transition
+** times are assumed to be local time.
+** When this is 1, the corresponding
+** std/wall indicator must also be 1.
*/
/*
diff --git a/contrib/libs/cctz/src/zone_info_source.cc b/contrib/libs/cctz/src/zone_info_source.cc
index e29799c665..e2491da757 100644
--- a/contrib/libs/cctz/src/zone_info_source.cc
+++ b/contrib/libs/cctz/src/zone_info_source.cc
@@ -1,73 +1,73 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cctz/zone_info_source.h"
-
-namespace cctz {
-
-// Defined out-of-line to avoid emitting a weak vtable in all TUs.
-ZoneInfoSource::~ZoneInfoSource() {}
-std::string ZoneInfoSource::Version() const { return std::string(); }
-
-} // namespace cctz
-
-namespace cctz_extension {
-
-namespace {
-
-// A default for cctz_extension::zone_info_source_factory, which simply
-// defers to the fallback factory.
-std::unique_ptr<cctz::ZoneInfoSource> DefaultFactory(
- const std::string& name,
- const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
- const std::string& name)>& fallback_factory) {
- return fallback_factory(name);
-}
-
-} // namespace
-
-// A "weak" definition for cctz_extension::zone_info_source_factory.
-// The user may override this with their own "strong" definition (see
-// zone_info_source.h).
-#if !defined(__has_attribute)
-#define __has_attribute(x) 0
-#endif
-// MinGW is GCC on Windows, so while it asserts __has_attribute(weak), the
-// Windows linker cannot handle that. Nor does the MinGW compiler know how to
-// pass "#pragma comment(linker, ...)" to the Windows linker.
-#if (__has_attribute(weak) || defined(__GNUC__)) && !defined(__MINGW32__) && !defined(_MSC_VER)
-ZoneInfoSourceFactory zone_info_source_factory
- __attribute__((weak)) = DefaultFactory;
-#elif defined(_MSC_VER) && !defined(__MINGW32__)
-extern ZoneInfoSourceFactory zone_info_source_factory;
-extern ZoneInfoSourceFactory default_factory;
-ZoneInfoSourceFactory default_factory = DefaultFactory;
-#if defined(_M_IX86)
-#pragma comment( \
- linker, \
- "/alternatename:?zone_info_source_factory@cctz_extension@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@3@@ZA=?default_factory@cctz_extension@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@3@@ZA")
-#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM) || \
- defined(_M_ARM64)
-#pragma comment( \
- linker, \
- "/alternatename:?zone_info_source_factory@cctz_extension@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@__y1@std@@@__y1@std@@AEBV?$basic_string@DU?$char_traits@D@__y1@std@@V?$allocator@D@23@@34@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@__y1@std@@@__y1@std@@AEBV?$basic_string@DU?$char_traits@D@__y1@std@@V?$allocator@D@23@@23@@Z@34@@ZEA=?default_factory@cctz_extension@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@__y1@std@@@__y1@std@@AEBV?$basic_string@DU?$char_traits@D@__y1@std@@V?$allocator@D@23@@34@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@__y1@std@@@__y1@std@@AEBV?$basic_string@DU?$char_traits@D@__y1@std@@V?$allocator@D@23@@23@@Z@34@@ZEA")
-#else
-#error Unsupported MSVC platform
-#endif // _M_<PLATFORM>
-#else
-// Make it a "strong" definition if we have no other choice.
-ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory;
-#endif
-
-} // namespace cctz_extension
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cctz/zone_info_source.h"
+
+namespace cctz {
+
+// Defined out-of-line to avoid emitting a weak vtable in all TUs.
+ZoneInfoSource::~ZoneInfoSource() {}
+std::string ZoneInfoSource::Version() const { return std::string(); }
+
+} // namespace cctz
+
+namespace cctz_extension {
+
+namespace {
+
+// A default for cctz_extension::zone_info_source_factory, which simply
+// defers to the fallback factory.
+std::unique_ptr<cctz::ZoneInfoSource> DefaultFactory(
+ const std::string& name,
+ const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
+ const std::string& name)>& fallback_factory) {
+ return fallback_factory(name);
+}
+
+} // namespace
+
+// A "weak" definition for cctz_extension::zone_info_source_factory.
+// The user may override this with their own "strong" definition (see
+// zone_info_source.h).
+#if !defined(__has_attribute)
+#define __has_attribute(x) 0
+#endif
+// MinGW is GCC on Windows, so while it asserts __has_attribute(weak), the
+// Windows linker cannot handle that. Nor does the MinGW compiler know how to
+// pass "#pragma comment(linker, ...)" to the Windows linker.
+#if (__has_attribute(weak) || defined(__GNUC__)) && !defined(__MINGW32__) && !defined(_MSC_VER)
+ZoneInfoSourceFactory zone_info_source_factory
+ __attribute__((weak)) = DefaultFactory;
+#elif defined(_MSC_VER) && !defined(__MINGW32__)
+extern ZoneInfoSourceFactory zone_info_source_factory;
+extern ZoneInfoSourceFactory default_factory;
+ZoneInfoSourceFactory default_factory = DefaultFactory;
+#if defined(_M_IX86)
+#pragma comment( \
+ linker, \
+ "/alternatename:?zone_info_source_factory@cctz_extension@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@3@@ZA=?default_factory@cctz_extension@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@3@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@3@@ZA")
+#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM) || \
+ defined(_M_ARM64)
+#pragma comment( \
+ linker, \
+ "/alternatename:?zone_info_source_factory@cctz_extension@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@__y1@std@@@__y1@std@@AEBV?$basic_string@DU?$char_traits@D@__y1@std@@V?$allocator@D@23@@34@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@__y1@std@@@__y1@std@@AEBV?$basic_string@DU?$char_traits@D@__y1@std@@V?$allocator@D@23@@23@@Z@34@@ZEA=?default_factory@cctz_extension@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@__y1@std@@@__y1@std@@AEBV?$basic_string@DU?$char_traits@D@__y1@std@@V?$allocator@D@23@@34@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@@U?$default_delete@VZoneInfoSource@cctz@@@__y1@std@@@__y1@std@@AEBV?$basic_string@DU?$char_traits@D@__y1@std@@V?$allocator@D@23@@23@@Z@34@@ZEA")
+#else
+#error Unsupported MSVC platform
+#endif // _M_<PLATFORM>
+#else
+// Make it a "strong" definition if we have no other choice.
+ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory;
+#endif
+
+} // namespace cctz_extension
diff --git a/contrib/libs/cctz/test/civil_time_test.cc b/contrib/libs/cctz/test/civil_time_test.cc
index 0b13cc1b7a..5ec0ca8d38 100644
--- a/contrib/libs/cctz/test/civil_time_test.cc
+++ b/contrib/libs/cctz/test/civil_time_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "cctz/civil_time.h"
+#include "cctz/civil_time.h"
#include <iomanip>
#include <limits>
@@ -20,7 +20,7 @@
#include <string>
#include <type_traits>
-#include "gtest/gtest.h"
+#include "gtest/gtest.h"
namespace cctz {
@@ -35,7 +35,7 @@ std::string Format(const T& t) {
} // namespace
-#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
+#if __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
// Construction constexpr tests
TEST(CivilTime, Normal) {
@@ -223,7 +223,7 @@ TEST(CivilTime, Subtraction) {
static_assert(cs2.second() == 22, "Subtraction.second");
}
-TEST(CivilTime, Difference) {
+TEST(CivilTime, Difference) {
constexpr civil_day cd1(2016, 1, 28);
constexpr civil_day cd2(2015, 1, 28);
constexpr int diff = cd1 - cd2;
@@ -231,16 +231,16 @@ TEST(CivilTime, Difference) {
}
// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
-TEST(CivilTime, ConstructionWithHugeYear) {
- constexpr civil_hour h(-9223372036854775807, 1, 1, -1);
- static_assert(h.year() == -9223372036854775807 - 1,
- "ConstructionWithHugeYear");
- static_assert(h.month() == 12, "ConstructionWithHugeYear");
- static_assert(h.day() == 31, "ConstructionWithHugeYear");
- static_assert(h.hour() == 23, "ConstructionWithHugeYear");
-}
-
-// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
+TEST(CivilTime, ConstructionWithHugeYear) {
+ constexpr civil_hour h(-9223372036854775807, 1, 1, -1);
+ static_assert(h.year() == -9223372036854775807 - 1,
+ "ConstructionWithHugeYear");
+ static_assert(h.month() == 12, "ConstructionWithHugeYear");
+ static_assert(h.day() == 31, "ConstructionWithHugeYear");
+ static_assert(h.hour() == 23, "ConstructionWithHugeYear");
+}
+
+// NOTE: Run this with --copt=-ftrapv to detect overflow problems.
TEST(CivilTime, DifferenceWithHugeYear) {
{
constexpr civil_day d1(9223372036854775807, 1, 1);
@@ -327,7 +327,7 @@ TEST(CivilTime, YearDay) {
constexpr int yd = get_yearday(cd);
static_assert(yd == 28, "YearDay");
}
-#endif // __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
+#endif // __cpp_constexpr >= 201304 || (defined(_MSC_VER) && _MSC_VER >= 1910)
// The remaining tests do not use constexpr.
@@ -628,7 +628,7 @@ TEST(CivilTime, Relational) {
TEST_RELATIONAL(civil_second(2014, 1, 1, 1, 1, 0),
civil_second(2014, 1, 1, 1, 1, 1));
- // Tests the relational operators of two different civil-time types.
+ // Tests the relational operators of two different civil-time types.
TEST_RELATIONAL(civil_day(2014, 1, 1), civil_minute(2014, 1, 1, 1, 1));
TEST_RELATIONAL(civil_day(2014, 1, 1), civil_month(2014, 2));
@@ -768,7 +768,7 @@ TEST(CivilTime, ArithmeticLimits) {
EXPECT_EQ("0", Format(year));
}
-TEST(CivilTime, ArithmeticDifference) {
+TEST(CivilTime, ArithmeticDifference) {
civil_second second(2015, 1, 2, 3, 4, 5);
EXPECT_EQ(0, second - second);
EXPECT_EQ(10, (second + 10) - second);
@@ -829,8 +829,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, ss.hour());
EXPECT_EQ(5, ss.minute());
EXPECT_EQ(6, ss.second());
- EXPECT_EQ(weekday::tuesday, get_weekday(ss));
- EXPECT_EQ(34, get_yearday(ss));
+ EXPECT_EQ(weekday::tuesday, get_weekday(ss));
+ EXPECT_EQ(34, get_yearday(ss));
civil_minute mm(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, mm.year());
@@ -839,8 +839,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, mm.hour());
EXPECT_EQ(5, mm.minute());
EXPECT_EQ(0, mm.second());
- EXPECT_EQ(weekday::tuesday, get_weekday(mm));
- EXPECT_EQ(34, get_yearday(mm));
+ EXPECT_EQ(weekday::tuesday, get_weekday(mm));
+ EXPECT_EQ(34, get_yearday(mm));
civil_hour hh(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, hh.year());
@@ -849,8 +849,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(4, hh.hour());
EXPECT_EQ(0, hh.minute());
EXPECT_EQ(0, hh.second());
- EXPECT_EQ(weekday::tuesday, get_weekday(hh));
- EXPECT_EQ(34, get_yearday(hh));
+ EXPECT_EQ(weekday::tuesday, get_weekday(hh));
+ EXPECT_EQ(34, get_yearday(hh));
civil_day d(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, d.year());
@@ -869,8 +869,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(0, m.hour());
EXPECT_EQ(0, m.minute());
EXPECT_EQ(0, m.second());
- EXPECT_EQ(weekday::sunday, get_weekday(m));
- EXPECT_EQ(32, get_yearday(m));
+ EXPECT_EQ(weekday::sunday, get_weekday(m));
+ EXPECT_EQ(32, get_yearday(m));
civil_year y(2015, 2, 3, 4, 5, 6);
EXPECT_EQ(2015, y.year());
@@ -879,8 +879,8 @@ TEST(CivilTime, Properties) {
EXPECT_EQ(0, y.hour());
EXPECT_EQ(0, y.minute());
EXPECT_EQ(0, y.second());
- EXPECT_EQ(weekday::thursday, get_weekday(y));
- EXPECT_EQ(1, get_yearday(y));
+ EXPECT_EQ(weekday::thursday, get_weekday(y));
+ EXPECT_EQ(1, get_yearday(y));
}
TEST(CivilTime, OutputStream) {
@@ -966,37 +966,37 @@ TEST(CivilTime, NextPrevWeekday) {
// Thursday -> Thursday
civil_day d = next_weekday(thursday, weekday::thursday);
- EXPECT_EQ(7, d - thursday) << Format(d);
+ EXPECT_EQ(7, d - thursday) << Format(d);
EXPECT_EQ(d - 14, prev_weekday(thursday, weekday::thursday));
// Thursday -> Friday
d = next_weekday(thursday, weekday::friday);
- EXPECT_EQ(1, d - thursday) << Format(d);
+ EXPECT_EQ(1, d - thursday) << Format(d);
EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::friday));
// Thursday -> Saturday
d = next_weekday(thursday, weekday::saturday);
- EXPECT_EQ(2, d - thursday) << Format(d);
+ EXPECT_EQ(2, d - thursday) << Format(d);
EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::saturday));
// Thursday -> Sunday
d = next_weekday(thursday, weekday::sunday);
- EXPECT_EQ(3, d - thursday) << Format(d);
+ EXPECT_EQ(3, d - thursday) << Format(d);
EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::sunday));
// Thursday -> Monday
d = next_weekday(thursday, weekday::monday);
- EXPECT_EQ(4, d - thursday) << Format(d);
+ EXPECT_EQ(4, d - thursday) << Format(d);
EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::monday));
// Thursday -> Tuesday
d = next_weekday(thursday, weekday::tuesday);
- EXPECT_EQ(5, d - thursday) << Format(d);
+ EXPECT_EQ(5, d - thursday) << Format(d);
EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::tuesday));
// Thursday -> Wednesday
d = next_weekday(thursday, weekday::wednesday);
- EXPECT_EQ(6, d - thursday) << Format(d);
+ EXPECT_EQ(6, d - thursday) << Format(d);
EXPECT_EQ(d - 7, prev_weekday(thursday, weekday::wednesday));
}
@@ -1053,7 +1053,7 @@ TEST(CivilTime, LeapYears) {
TEST(CivilTime, FirstThursdayInMonth) {
const civil_day nov1(2014, 11, 1);
- const civil_day thursday = next_weekday(nov1 - 1, weekday::thursday);
+ const civil_day thursday = next_weekday(nov1 - 1, weekday::thursday);
EXPECT_EQ("2014-11-06", Format(thursday));
// Bonus: Date of Thanksgiving in the United States
diff --git a/contrib/libs/cctz/test/time_zone_format_test.cc b/contrib/libs/cctz/test/time_zone_format_test.cc
index 724836fa14..0d07dad5c0 100644
--- a/contrib/libs/cctz/test/time_zone_format_test.cc
+++ b/contrib/libs/cctz/test/time_zone_format_test.cc
@@ -1,1588 +1,1588 @@
-// Copyright 2016 Google Inc. All Rights Reserved.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// https://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "cctz/time_zone.h"
-
-#include <chrono>
-#include <iomanip>
-#include <sstream>
-#include <string>
-
-#include "cctz/civil_time.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-namespace chrono = std::chrono;
-
-namespace cctz {
-
-namespace {
-
-// This helper is a macro so that failed expectations show up with the
-// correct line numbers.
-#define ExpectTime(tp, tz, y, m, d, hh, mm, ss, off, isdst, zone) \
- do { \
- time_zone::absolute_lookup al = tz.lookup(tp); \
- EXPECT_EQ(y, al.cs.year()); \
- EXPECT_EQ(m, al.cs.month()); \
- EXPECT_EQ(d, al.cs.day()); \
- EXPECT_EQ(hh, al.cs.hour()); \
- EXPECT_EQ(mm, al.cs.minute()); \
- EXPECT_EQ(ss, al.cs.second()); \
- EXPECT_EQ(off, al.offset); \
- EXPECT_TRUE(isdst == al.is_dst); \
- EXPECT_STREQ(zone, al.abbr); \
- } while (0)
-
-const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
-const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
-
-const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
-const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
-
-// A helper that tests the given format specifier by itself, and with leading
-// and trailing characters. For example: TestFormatSpecifier(tp, "%a", "Thu").
-template <typename D>
-void TestFormatSpecifier(time_point<D> tp, time_zone tz, const std::string& fmt,
- const std::string& ans) {
- EXPECT_EQ(ans, format(fmt, tp, tz)) << fmt;
- EXPECT_EQ("xxx " + ans, format("xxx " + fmt, tp, tz));
- EXPECT_EQ(ans + " yyy", format(fmt + " yyy", tp, tz));
- EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz));
-}
-
-} // namespace
-
-//
-// Testing format()
-//
-
-TEST(Format, TimePointResolution) {
- const char kFmt[] = "%H:%M:%E*S";
- const time_zone utc = utc_time_zone();
- const time_point<chrono::nanoseconds> t0 =
- chrono::system_clock::from_time_t(1420167845) +
- chrono::milliseconds(123) + chrono::microseconds(456) +
- chrono::nanoseconds(789);
- EXPECT_EQ(
- "03:04:05.123456789",
- format(kFmt, chrono::time_point_cast<chrono::nanoseconds>(t0), utc));
- EXPECT_EQ(
- "03:04:05.123456",
- format(kFmt, chrono::time_point_cast<chrono::microseconds>(t0), utc));
- EXPECT_EQ(
- "03:04:05.123",
- format(kFmt, chrono::time_point_cast<chrono::milliseconds>(t0), utc));
- EXPECT_EQ("03:04:05",
- format(kFmt, chrono::time_point_cast<chrono::seconds>(t0), utc));
- EXPECT_EQ("03:04:05",
- format(kFmt, chrono::time_point_cast<cctz::seconds>(t0), utc));
- EXPECT_EQ("03:04:00",
- format(kFmt, chrono::time_point_cast<chrono::minutes>(t0), utc));
- EXPECT_EQ("03:00:00",
- format(kFmt, chrono::time_point_cast<chrono::hours>(t0), utc));
-}
-
-TEST(Format, TimePointExtendedResolution) {
- const char kFmt[] = "%H:%M:%E*S";
- const time_zone utc = utc_time_zone();
- const time_point<cctz::seconds> tp =
- chrono::time_point_cast<cctz::seconds>(
- chrono::system_clock::from_time_t(0)) +
- chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56);
-
- EXPECT_EQ(
- "12:34:56.123456789012345",
- detail::format(kFmt, tp, detail::femtoseconds(123456789012345), utc));
- EXPECT_EQ(
- "12:34:56.012345678901234",
- detail::format(kFmt, tp, detail::femtoseconds(12345678901234), utc));
- EXPECT_EQ(
- "12:34:56.001234567890123",
- detail::format(kFmt, tp, detail::femtoseconds(1234567890123), utc));
- EXPECT_EQ(
- "12:34:56.000123456789012",
- detail::format(kFmt, tp, detail::femtoseconds(123456789012), utc));
-
- EXPECT_EQ("12:34:56.000000000000123",
- detail::format(kFmt, tp, detail::femtoseconds(123), utc));
- EXPECT_EQ("12:34:56.000000000000012",
- detail::format(kFmt, tp, detail::femtoseconds(12), utc));
- EXPECT_EQ("12:34:56.000000000000001",
- detail::format(kFmt, tp, detail::femtoseconds(1), utc));
-}
-
-TEST(Format, Basics) {
- time_zone tz = utc_time_zone();
- time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
-
- // Starts with a couple basic edge cases.
- EXPECT_EQ("", format("", tp, tz));
- EXPECT_EQ(" ", format(" ", tp, tz));
- EXPECT_EQ(" ", format(" ", tp, tz));
- EXPECT_EQ("xxx", format("xxx", tp, tz));
- std::string big(128, 'x');
- EXPECT_EQ(big, format(big, tp, tz));
- // Cause the 1024-byte buffer to grow.
- std::string bigger(100000, 'x');
- EXPECT_EQ(bigger, format(bigger, tp, tz));
-
- tp += chrono::hours(13) + chrono::minutes(4) + chrono::seconds(5);
- tp += chrono::milliseconds(6) + chrono::microseconds(7) +
- chrono::nanoseconds(8);
- EXPECT_EQ("1970-01-01", format("%Y-%m-%d", tp, tz));
- EXPECT_EQ("13:04:05", format("%H:%M:%S", tp, tz));
- EXPECT_EQ("13:04:05.006", format("%H:%M:%E3S", tp, tz));
- EXPECT_EQ("13:04:05.006007", format("%H:%M:%E6S", tp, tz));
- EXPECT_EQ("13:04:05.006007008", format("%H:%M:%E9S", tp, tz));
-}
-
-TEST(Format, PosixConversions) {
- const time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
-
- TestFormatSpecifier(tp, tz, "%d", "01");
- TestFormatSpecifier(tp, tz, "%e", " 1"); // extension but internal support
- TestFormatSpecifier(tp, tz, "%H", "00");
- TestFormatSpecifier(tp, tz, "%I", "12");
- TestFormatSpecifier(tp, tz, "%j", "001");
- TestFormatSpecifier(tp, tz, "%m", "01");
- TestFormatSpecifier(tp, tz, "%M", "00");
- TestFormatSpecifier(tp, tz, "%S", "00");
- TestFormatSpecifier(tp, tz, "%U", "00");
- TestFormatSpecifier(tp, tz, "%w", "4"); // 4=Thursday
- TestFormatSpecifier(tp, tz, "%W", "00");
- TestFormatSpecifier(tp, tz, "%y", "70");
- TestFormatSpecifier(tp, tz, "%Y", "1970");
- TestFormatSpecifier(tp, tz, "%z", "+0000");
- TestFormatSpecifier(tp, tz, "%Z", "UTC");
- TestFormatSpecifier(tp, tz, "%%", "%");
-
-#if defined(__linux__)
- // SU/C99/TZ extensions
- TestFormatSpecifier(tp, tz, "%C", "19");
- TestFormatSpecifier(tp, tz, "%D", "01/01/70");
- TestFormatSpecifier(tp, tz, "%F", "1970-01-01");
- TestFormatSpecifier(tp, tz, "%g", "70");
- TestFormatSpecifier(tp, tz, "%G", "1970");
- TestFormatSpecifier(tp, tz, "%k", " 0");
- TestFormatSpecifier(tp, tz, "%l", "12");
- TestFormatSpecifier(tp, tz, "%n", "\n");
- TestFormatSpecifier(tp, tz, "%R", "00:00");
- TestFormatSpecifier(tp, tz, "%t", "\t");
- TestFormatSpecifier(tp, tz, "%T", "00:00:00");
- TestFormatSpecifier(tp, tz, "%u", "4"); // 4=Thursday
- TestFormatSpecifier(tp, tz, "%V", "01");
- TestFormatSpecifier(tp, tz, "%s", "0");
-#endif
-}
-
-TEST(Format, LocaleSpecific) {
- const time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
-
- TestFormatSpecifier(tp, tz, "%a", "Thu");
- TestFormatSpecifier(tp, tz, "%A", "Thursday");
- TestFormatSpecifier(tp, tz, "%b", "Jan");
- TestFormatSpecifier(tp, tz, "%B", "January");
-
- // %c should at least produce the numeric year and time-of-day.
- const std::string s = format("%c", tp, utc_time_zone());
- EXPECT_THAT(s, testing::HasSubstr("1970"));
- EXPECT_THAT(s, testing::HasSubstr("00:00:00"));
-
- TestFormatSpecifier(tp, tz, "%p", "AM");
- TestFormatSpecifier(tp, tz, "%x", "01/01/70");
- TestFormatSpecifier(tp, tz, "%X", "00:00:00");
-
-#if defined(__linux__)
- // SU/C99/TZ extensions
- TestFormatSpecifier(tp, tz, "%h", "Jan"); // Same as %b
- TestFormatSpecifier(tp, tz, "%P", "am");
- TestFormatSpecifier(tp, tz, "%r", "12:00:00 AM");
-
- // Modified conversion specifiers %E_
- TestFormatSpecifier(tp, tz, "%Ec", "Thu Jan 1 00:00:00 1970");
- TestFormatSpecifier(tp, tz, "%EC", "19");
- TestFormatSpecifier(tp, tz, "%Ex", "01/01/70");
- TestFormatSpecifier(tp, tz, "%EX", "00:00:00");
- TestFormatSpecifier(tp, tz, "%Ey", "70");
- TestFormatSpecifier(tp, tz, "%EY", "1970");
-
- // Modified conversion specifiers %O_
- TestFormatSpecifier(tp, tz, "%Od", "01");
- TestFormatSpecifier(tp, tz, "%Oe", " 1");
- TestFormatSpecifier(tp, tz, "%OH", "00");
- TestFormatSpecifier(tp, tz, "%OI", "12");
- TestFormatSpecifier(tp, tz, "%Om", "01");
- TestFormatSpecifier(tp, tz, "%OM", "00");
- TestFormatSpecifier(tp, tz, "%OS", "00");
- TestFormatSpecifier(tp, tz, "%Ou", "4"); // 4=Thursday
- TestFormatSpecifier(tp, tz, "%OU", "00");
- TestFormatSpecifier(tp, tz, "%OV", "01");
- TestFormatSpecifier(tp, tz, "%Ow", "4"); // 4=Thursday
- TestFormatSpecifier(tp, tz, "%OW", "00");
- TestFormatSpecifier(tp, tz, "%Oy", "70");
-#endif
-}
-
-TEST(Format, Escaping) {
- const time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
-
- TestFormatSpecifier(tp, tz, "%%", "%");
- TestFormatSpecifier(tp, tz, "%%a", "%a");
- TestFormatSpecifier(tp, tz, "%%b", "%b");
- TestFormatSpecifier(tp, tz, "%%Ea", "%Ea");
- TestFormatSpecifier(tp, tz, "%%Es", "%Es");
- TestFormatSpecifier(tp, tz, "%%E3S", "%E3S");
- TestFormatSpecifier(tp, tz, "%%OS", "%OS");
- TestFormatSpecifier(tp, tz, "%%O3S", "%O3S");
-
- // Multiple levels of escaping.
- TestFormatSpecifier(tp, tz, "%%%Y", "%1970");
- TestFormatSpecifier(tp, tz, "%%%E3S", "%00.000");
- TestFormatSpecifier(tp, tz, "%%%%E3S", "%%E3S");
-}
-
-TEST(Format, ExtendedSeconds) {
- const time_zone tz = utc_time_zone();
-
- // No subseconds.
- time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
- tp += chrono::seconds(5);
- EXPECT_EQ("05", format("%E*S", tp, tz));
- EXPECT_EQ("05", format("%E0S", tp, tz));
- EXPECT_EQ("05.0", format("%E1S", tp, tz));
- EXPECT_EQ("05.00", format("%E2S", tp, tz));
- EXPECT_EQ("05.000", format("%E3S", tp, tz));
- EXPECT_EQ("05.0000", format("%E4S", tp, tz));
- EXPECT_EQ("05.00000", format("%E5S", tp, tz));
- EXPECT_EQ("05.000000", format("%E6S", tp, tz));
- EXPECT_EQ("05.0000000", format("%E7S", tp, tz));
- EXPECT_EQ("05.00000000", format("%E8S", tp, tz));
- EXPECT_EQ("05.000000000", format("%E9S", tp, tz));
- EXPECT_EQ("05.0000000000", format("%E10S", tp, tz));
- EXPECT_EQ("05.00000000000", format("%E11S", tp, tz));
- EXPECT_EQ("05.000000000000", format("%E12S", tp, tz));
- EXPECT_EQ("05.0000000000000", format("%E13S", tp, tz));
- EXPECT_EQ("05.00000000000000", format("%E14S", tp, tz));
- EXPECT_EQ("05.000000000000000", format("%E15S", tp, tz));
-
- // With subseconds.
- tp += chrono::milliseconds(6) + chrono::microseconds(7) +
- chrono::nanoseconds(8);
- EXPECT_EQ("05.006007008", format("%E*S", tp, tz));
- EXPECT_EQ("05", format("%E0S", tp, tz));
- EXPECT_EQ("05.0", format("%E1S", tp, tz));
- EXPECT_EQ("05.00", format("%E2S", tp, tz));
- EXPECT_EQ("05.006", format("%E3S", tp, tz));
- EXPECT_EQ("05.0060", format("%E4S", tp, tz));
- EXPECT_EQ("05.00600", format("%E5S", tp, tz));
- EXPECT_EQ("05.006007", format("%E6S", tp, tz));
- EXPECT_EQ("05.0060070", format("%E7S", tp, tz));
- EXPECT_EQ("05.00600700", format("%E8S", tp, tz));
- EXPECT_EQ("05.006007008", format("%E9S", tp, tz));
- EXPECT_EQ("05.0060070080", format("%E10S", tp, tz));
- EXPECT_EQ("05.00600700800", format("%E11S", tp, tz));
- EXPECT_EQ("05.006007008000", format("%E12S", tp, tz));
- EXPECT_EQ("05.0060070080000", format("%E13S", tp, tz));
- EXPECT_EQ("05.00600700800000", format("%E14S", tp, tz));
- EXPECT_EQ("05.006007008000000", format("%E15S", tp, tz));
-
- // Times before the Unix epoch.
- tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1);
- EXPECT_EQ("1969-12-31 23:59:59.999999",
- format("%Y-%m-%d %H:%M:%E*S", tp, tz));
-
- // Here is a "%E*S" case we got wrong for a while. While the first
- // instant below is correctly rendered as "...:07.333304", the second
- // one used to appear as "...:07.33330499999999999".
- tp = chrono::system_clock::from_time_t(0) +
- chrono::microseconds(1395024427333304);
- EXPECT_EQ("2014-03-17 02:47:07.333304",
- format("%Y-%m-%d %H:%M:%E*S", tp, tz));
- tp += chrono::microseconds(1);
- EXPECT_EQ("2014-03-17 02:47:07.333305",
- format("%Y-%m-%d %H:%M:%E*S", tp, tz));
-}
-
-TEST(Format, ExtendedSubeconds) {
- const time_zone tz = utc_time_zone();
-
- // No subseconds.
- time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
- tp += chrono::seconds(5);
- EXPECT_EQ("0", format("%E*f", tp, tz));
- EXPECT_EQ("", format("%E0f", tp, tz));
- EXPECT_EQ("0", format("%E1f", tp, tz));
- EXPECT_EQ("00", format("%E2f", tp, tz));
- EXPECT_EQ("000", format("%E3f", tp, tz));
- EXPECT_EQ("0000", format("%E4f", tp, tz));
- EXPECT_EQ("00000", format("%E5f", tp, tz));
- EXPECT_EQ("000000", format("%E6f", tp, tz));
- EXPECT_EQ("0000000", format("%E7f", tp, tz));
- EXPECT_EQ("00000000", format("%E8f", tp, tz));
- EXPECT_EQ("000000000", format("%E9f", tp, tz));
- EXPECT_EQ("0000000000", format("%E10f", tp, tz));
- EXPECT_EQ("00000000000", format("%E11f", tp, tz));
- EXPECT_EQ("000000000000", format("%E12f", tp, tz));
- EXPECT_EQ("0000000000000", format("%E13f", tp, tz));
- EXPECT_EQ("00000000000000", format("%E14f", tp, tz));
- EXPECT_EQ("000000000000000", format("%E15f", tp, tz));
-
- // With subseconds.
- tp += chrono::milliseconds(6) + chrono::microseconds(7) +
- chrono::nanoseconds(8);
- EXPECT_EQ("006007008", format("%E*f", tp, tz));
- EXPECT_EQ("", format("%E0f", tp, tz));
- EXPECT_EQ("0", format("%E1f", tp, tz));
- EXPECT_EQ("00", format("%E2f", tp, tz));
- EXPECT_EQ("006", format("%E3f", tp, tz));
- EXPECT_EQ("0060", format("%E4f", tp, tz));
- EXPECT_EQ("00600", format("%E5f", tp, tz));
- EXPECT_EQ("006007", format("%E6f", tp, tz));
- EXPECT_EQ("0060070", format("%E7f", tp, tz));
- EXPECT_EQ("00600700", format("%E8f", tp, tz));
- EXPECT_EQ("006007008", format("%E9f", tp, tz));
- EXPECT_EQ("0060070080", format("%E10f", tp, tz));
- EXPECT_EQ("00600700800", format("%E11f", tp, tz));
- EXPECT_EQ("006007008000", format("%E12f", tp, tz));
- EXPECT_EQ("0060070080000", format("%E13f", tp, tz));
- EXPECT_EQ("00600700800000", format("%E14f", tp, tz));
- EXPECT_EQ("006007008000000", format("%E15f", tp, tz));
-
- // Times before the Unix epoch.
- tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1);
- EXPECT_EQ("1969-12-31 23:59:59.999999",
- format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
-
- // Here is a "%E*S" case we got wrong for a while. While the first
- // instant below is correctly rendered as "...:07.333304", the second
- // one used to appear as "...:07.33330499999999999".
- tp = chrono::system_clock::from_time_t(0) +
- chrono::microseconds(1395024427333304);
- EXPECT_EQ("2014-03-17 02:47:07.333304",
- format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
- tp += chrono::microseconds(1);
- EXPECT_EQ("2014-03-17 02:47:07.333305",
- format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
-}
-
-TEST(Format, CompareExtendSecondsVsSubseconds) {
- const time_zone tz = utc_time_zone();
-
- // This test case illustrates the differences/similarities between:
- // fmt_A: %E<prec>S
- // fmt_B: %S.%E<prec>f
- auto fmt_A = [](const std::string& prec) { return "%E" + prec + "S"; };
- auto fmt_B = [](const std::string& prec) { return "%S.%E" + prec + "f"; };
-
- // No subseconds:
- time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
- tp += chrono::seconds(5);
- // ... %E*S and %S.%E*f are different.
- EXPECT_EQ("05", format(fmt_A("*"), tp, tz));
- EXPECT_EQ("05.0", format(fmt_B("*"), tp, tz));
- // ... %E0S and %S.%E0f are different.
- EXPECT_EQ("05", format(fmt_A("0"), tp, tz));
- EXPECT_EQ("05.", format(fmt_B("0"), tp, tz));
- // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15].
- for (int prec = 1; prec <= 15; ++prec) {
- const std::string a = format(fmt_A(std::to_string(prec)), tp, tz);
- const std::string b = format(fmt_B(std::to_string(prec)), tp, tz);
- EXPECT_EQ(a, b) << "prec=" << prec;
- }
-
- // With subseconds:
- // ... %E*S and %S.%E*f are the same.
- tp += chrono::milliseconds(6) + chrono::microseconds(7) +
- chrono::nanoseconds(8);
- EXPECT_EQ("05.006007008", format(fmt_A("*"), tp, tz));
- EXPECT_EQ("05.006007008", format(fmt_B("*"), tp, tz));
- // ... %E0S and %S.%E0f are different.
- EXPECT_EQ("05", format(fmt_A("0"), tp, tz));
- EXPECT_EQ("05.", format(fmt_B("0"), tp, tz));
- // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15].
- for (int prec = 1; prec <= 15; ++prec) {
- const std::string a = format(fmt_A(std::to_string(prec)), tp, tz);
- const std::string b = format(fmt_B(std::to_string(prec)), tp, tz);
- EXPECT_EQ(a, b) << "prec=" << prec;
- }
-}
-
-TEST(Format, ExtendedOffset) {
- const auto tp = chrono::system_clock::from_time_t(0);
-
- auto tz = fixed_time_zone(cctz::seconds::zero());
- TestFormatSpecifier(tp, tz, "%z", "+0000");
- TestFormatSpecifier(tp, tz, "%:z", "+00:00");
- TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
-
- tz = fixed_time_zone(chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "+0000");
- TestFormatSpecifier(tp, tz, "%:z", "+00:00");
- TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
-
- tz = fixed_time_zone(-chrono::seconds(56)); // NOTE: +00:00
- TestFormatSpecifier(tp, tz, "%z", "+0000");
- TestFormatSpecifier(tp, tz, "%:z", "+00:00");
- TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
-
- tz = fixed_time_zone(chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%z", "+0034");
- TestFormatSpecifier(tp, tz, "%:z", "+00:34");
- TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
-
- tz = fixed_time_zone(-chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%z", "-0034");
- TestFormatSpecifier(tp, tz, "%:z", "-00:34");
- TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
-
- tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "+0034");
- TestFormatSpecifier(tp, tz, "%:z", "+00:34");
- TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
-
- tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "-0034");
- TestFormatSpecifier(tp, tz, "%:z", "-00:34");
- TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
-
- tz = fixed_time_zone(chrono::hours(12));
- TestFormatSpecifier(tp, tz, "%z", "+1200");
- TestFormatSpecifier(tp, tz, "%:z", "+12:00");
- TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
-
- tz = fixed_time_zone(-chrono::hours(12));
- TestFormatSpecifier(tp, tz, "%z", "-1200");
- TestFormatSpecifier(tp, tz, "%:z", "-12:00");
- TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "+1200");
- TestFormatSpecifier(tp, tz, "%:z", "+12:00");
- TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "-1200");
- TestFormatSpecifier(tp, tz, "%:z", "-12:00");
- TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%z", "+1234");
- TestFormatSpecifier(tp, tz, "%:z", "+12:34");
- TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%z", "-1234");
- TestFormatSpecifier(tp, tz, "%:z", "-12:34");
- TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
- chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "+1234");
- TestFormatSpecifier(tp, tz, "%:z", "+12:34");
- TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
- chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%z", "-1234");
- TestFormatSpecifier(tp, tz, "%:z", "-12:34");
- TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
-}
-
-TEST(Format, ExtendedSecondOffset) {
- const auto tp = chrono::system_clock::from_time_t(0);
-
- auto tz = fixed_time_zone(cctz::seconds::zero());
- TestFormatSpecifier(tp, tz, "%E*z", "+00:00:00");
- TestFormatSpecifier(tp, tz, "%::z", "+00:00:00");
- TestFormatSpecifier(tp, tz, "%:::z", "+00");
-
- tz = fixed_time_zone(chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "+00:00:56");
- TestFormatSpecifier(tp, tz, "%::z", "+00:00:56");
- TestFormatSpecifier(tp, tz, "%:::z", "+00:00:56");
-
- tz = fixed_time_zone(-chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "-00:00:56");
- TestFormatSpecifier(tp, tz, "%::z", "-00:00:56");
- TestFormatSpecifier(tp, tz, "%:::z", "-00:00:56");
-
- tz = fixed_time_zone(chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%E*z", "+00:34:00");
- TestFormatSpecifier(tp, tz, "%::z", "+00:34:00");
- TestFormatSpecifier(tp, tz, "%:::z", "+00:34");
-
- tz = fixed_time_zone(-chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%E*z", "-00:34:00");
- TestFormatSpecifier(tp, tz, "%::z", "-00:34:00");
- TestFormatSpecifier(tp, tz, "%:::z", "-00:34");
-
- tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "+00:34:56");
- TestFormatSpecifier(tp, tz, "%::z", "+00:34:56");
- TestFormatSpecifier(tp, tz, "%:::z", "+00:34:56");
-
- tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "-00:34:56");
- TestFormatSpecifier(tp, tz, "%::z", "-00:34:56");
- TestFormatSpecifier(tp, tz, "%:::z", "-00:34:56");
-
- tz = fixed_time_zone(chrono::hours(12));
- TestFormatSpecifier(tp, tz, "%E*z", "+12:00:00");
- TestFormatSpecifier(tp, tz, "%::z", "+12:00:00");
- TestFormatSpecifier(tp, tz, "%:::z", "+12");
-
- tz = fixed_time_zone(-chrono::hours(12));
- TestFormatSpecifier(tp, tz, "%E*z", "-12:00:00");
- TestFormatSpecifier(tp, tz, "%::z", "-12:00:00");
- TestFormatSpecifier(tp, tz, "%:::z", "-12");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "+12:00:56");
- TestFormatSpecifier(tp, tz, "%::z", "+12:00:56");
- TestFormatSpecifier(tp, tz, "%:::z", "+12:00:56");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "-12:00:56");
- TestFormatSpecifier(tp, tz, "%::z", "-12:00:56");
- TestFormatSpecifier(tp, tz, "%:::z", "-12:00:56");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%E*z", "+12:34:00");
- TestFormatSpecifier(tp, tz, "%::z", "+12:34:00");
- TestFormatSpecifier(tp, tz, "%:::z", "+12:34");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
- TestFormatSpecifier(tp, tz, "%E*z", "-12:34:00");
- TestFormatSpecifier(tp, tz, "%::z", "-12:34:00");
- TestFormatSpecifier(tp, tz, "%:::z", "-12:34");
-
- tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
- chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "+12:34:56");
- TestFormatSpecifier(tp, tz, "%::z", "+12:34:56");
- TestFormatSpecifier(tp, tz, "%:::z", "+12:34:56");
-
- tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
- chrono::seconds(56));
- TestFormatSpecifier(tp, tz, "%E*z", "-12:34:56");
- TestFormatSpecifier(tp, tz, "%::z", "-12:34:56");
- TestFormatSpecifier(tp, tz, "%:::z", "-12:34:56");
-}
-
-TEST(Format, ExtendedYears) {
- const time_zone utc = utc_time_zone();
- const char e4y_fmt[] = "%E4Y%m%d"; // no separators
-
- // %E4Y zero-pads the year to produce at least 4 chars, including the sign.
- auto tp = convert(civil_second(-999, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("-9991127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(-99, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("-0991127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(-9, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("-0091127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(-1, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("-0011127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(0, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("00001127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(1, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("00011127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(9, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("00091127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(99, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("00991127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(999, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("09991127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(9999, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("99991127", format(e4y_fmt, tp, utc));
-
- // When the year is outside [-999:9999], more than 4 chars are produced.
- tp = convert(civil_second(-1000, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("-10001127", format(e4y_fmt, tp, utc));
- tp = convert(civil_second(10000, 11, 27, 0, 0, 0), utc);
- EXPECT_EQ("100001127", format(e4y_fmt, tp, utc));
-}
-
-TEST(Format, RFC3339Format) {
- time_zone tz;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
-
- time_point<chrono::nanoseconds> tp =
- convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::milliseconds(100);
- EXPECT_EQ("1977-06-28T09:08:07.1-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::milliseconds(20);
- EXPECT_EQ("1977-06-28T09:08:07.12-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::milliseconds(3);
- EXPECT_EQ("1977-06-28T09:08:07.123-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::microseconds(400);
- EXPECT_EQ("1977-06-28T09:08:07.1234-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::microseconds(50);
- EXPECT_EQ("1977-06-28T09:08:07.12345-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::microseconds(6);
- EXPECT_EQ("1977-06-28T09:08:07.123456-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::nanoseconds(700);
- EXPECT_EQ("1977-06-28T09:08:07.1234567-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::nanoseconds(80);
- EXPECT_EQ("1977-06-28T09:08:07.12345678-07:00", format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-
- tp += chrono::nanoseconds(9);
- EXPECT_EQ("1977-06-28T09:08:07.123456789-07:00",
- format(RFC3339_full, tp, tz));
- EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
-}
-
-TEST(Format, RFC1123Format) { // locale specific
- time_zone tz;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
-
- auto tp = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
- EXPECT_EQ("Tue, 28 Jun 1977 09:08:07 -0700", format(RFC1123_full, tp, tz));
- EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz));
-}
-
-TEST(Format, Week) {
- const time_zone utc = utc_time_zone();
-
- auto tp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
- EXPECT_EQ("2017-01-7", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2017-00-0", format("%Y-%W-%w", tp, utc));
-
- tp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
- EXPECT_EQ("2017-53-7", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2017-52-0", format("%Y-%W-%w", tp, utc));
-
- tp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
- EXPECT_EQ("2018-00-1", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2018-01-1", format("%Y-%W-%w", tp, utc));
-
- tp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
- EXPECT_EQ("2018-52-1", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2018-53-1", format("%Y-%W-%w", tp, utc));
-
- tp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
- EXPECT_EQ("2019-00-2", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2019-00-2", format("%Y-%W-%w", tp, utc));
-
- tp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
- EXPECT_EQ("2019-52-2", format("%Y-%U-%u", tp, utc));
- EXPECT_EQ("2019-52-2", format("%Y-%W-%w", tp, utc));
-}
-
-//
-// Testing parse()
-//
-
-TEST(Parse, TimePointResolution) {
- const char kFmt[] = "%H:%M:%E*S";
- const time_zone utc = utc_time_zone();
-
- time_point<chrono::nanoseconds> tp_ns;
- EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_ns));
- EXPECT_EQ("03:04:05.123456789", format(kFmt, tp_ns, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ns));
- EXPECT_EQ("03:04:05.123456", format(kFmt, tp_ns, utc));
-
- time_point<chrono::microseconds> tp_us;
- EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_us));
- EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_us));
- EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_us));
- EXPECT_EQ("03:04:05.123", format(kFmt, tp_us, utc));
-
- time_point<chrono::milliseconds> tp_ms;
- EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ms));
- EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_ms));
- EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_ms));
- EXPECT_EQ("03:04:05", format(kFmt, tp_ms, utc));
-
- time_point<chrono::seconds> tp_s;
- EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_s));
- EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc));
- EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_s));
- EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc));
-
- time_point<chrono::minutes> tp_m;
- EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_m));
- EXPECT_EQ("03:04:00", format(kFmt, tp_m, utc));
-
- time_point<chrono::hours> tp_h;
- EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_h));
- EXPECT_EQ("03:00:00", format(kFmt, tp_h, utc));
-}
-
-TEST(Parse, TimePointExtendedResolution) {
- const char kFmt[] = "%H:%M:%E*S";
- const time_zone utc = utc_time_zone();
-
- time_point<cctz::seconds> tp;
- detail::femtoseconds fs;
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.123456789012345", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.123456789012345", detail::format(kFmt, tp, fs, utc));
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.012345678901234", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.012345678901234", detail::format(kFmt, tp, fs, utc));
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.001234567890123", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.001234567890123", detail::format(kFmt, tp, fs, utc));
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000123", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.000000000000123", detail::format(kFmt, tp, fs, utc));
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000012", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.000000000000012", detail::format(kFmt, tp, fs, utc));
- EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000001", utc, &tp, &fs));
- EXPECT_EQ("12:34:56.000000000000001", detail::format(kFmt, tp, fs, utc));
-}
-
-TEST(Parse, Basics) {
- time_zone tz = utc_time_zone();
- time_point<chrono::nanoseconds> tp =
- chrono::system_clock::from_time_t(1234567890);
-
- // Simple edge cases.
- EXPECT_TRUE(parse("", "", tz, &tp));
- EXPECT_EQ(chrono::system_clock::from_time_t(0), tp); // everything defaulted
- EXPECT_TRUE(parse(" ", " ", tz, &tp));
- EXPECT_TRUE(parse(" ", " ", tz, &tp));
- EXPECT_TRUE(parse("x", "x", tz, &tp));
- EXPECT_TRUE(parse("xxx", "xxx", tz, &tp));
-
- EXPECT_TRUE(
- parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 -0800", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 29, 3, 8, 9, 0, false, "UTC");
-}
-
-TEST(Parse, WithTimeZone) {
- time_zone tz;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
- time_point<chrono::nanoseconds> tp;
-
- // We can parse a string without a UTC offset if we supply a timezone.
- EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true, "PDT");
-
- // But the timezone is ignored when a UTC offset is present.
- EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 +0800",
- utc_time_zone(), &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 19 - 8 - 7, 8, 9, -7 * 60 * 60, true, "PDT");
-
- // Check a skipped time (a Spring DST transition). parse() uses the
- // pre-transition offset.
- EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-03-13 02:15:00", tz, &tp));
- ExpectTime(tp, tz, 2011, 3, 13, 3, 15, 0, -7 * 60 * 60, true, "PDT");
-
- // Check a repeated time (a Fall DST transition). parse() uses the
- // pre-transition offset.
- EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-11-06 01:15:00", tz, &tp));
- ExpectTime(tp, tz, 2011, 11, 6, 1, 15, 0, -7 * 60 * 60, true, "PDT");
-}
-
-TEST(Parse, LeapSecond) {
- time_zone tz;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
- time_point<chrono::nanoseconds> tp;
-
- // ":59" -> ":59"
- EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59-08:00", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT");
-
- // ":59.5" -> ":59.5"
- EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59.5-08:00", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT");
-
- // ":60" -> ":00"
- EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60-08:00", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT");
-
- // ":60.5" -> ":00.0"
- EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60.5-08:00", tz, &tp));
- ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT");
-
- // ":61" -> error
- EXPECT_FALSE(parse(RFC3339_full, "2013-06-28T07:08:61-08:00", tz, &tp));
-}
-
-TEST(Parse, ErrorCases) {
- const time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
-
- // Illegal trailing data.
- EXPECT_FALSE(parse("%S", "123", tz, &tp));
-
- // Can't parse an illegal format specifier.
- EXPECT_FALSE(parse("%Q", "x", tz, &tp));
-
- // Fails because of trailing, unparsed data "blah".
- EXPECT_FALSE(parse("%m-%d", "2-3 blah", tz, &tp));
-
- // Trailing whitespace is allowed.
- EXPECT_TRUE(parse("%m-%d", "2-3 ", tz, &tp));
- EXPECT_EQ(2, convert(tp, utc_time_zone()).month());
- EXPECT_EQ(3, convert(tp, utc_time_zone()).day());
-
- // Feb 31 requires normalization.
- EXPECT_FALSE(parse("%m-%d", "2-31", tz, &tp));
-
- // Check that we cannot have spaces in UTC offsets.
- EXPECT_TRUE(parse("%z", "-0203", tz, &tp));
- EXPECT_FALSE(parse("%z", "- 2 3", tz, &tp));
- EXPECT_TRUE(parse("%Ez", "-02:03", tz, &tp));
- EXPECT_FALSE(parse("%Ez", "- 2: 3", tz, &tp));
-
- // Check that we reject other malformed UTC offsets.
- EXPECT_FALSE(parse("%Ez", "+-08:00", tz, &tp));
- EXPECT_FALSE(parse("%Ez", "-+08:00", tz, &tp));
-
- // Check that we do not accept "-0" in fields that allow zero.
- EXPECT_FALSE(parse("%Y", "-0", tz, &tp));
- EXPECT_FALSE(parse("%E4Y", "-0", tz, &tp));
- EXPECT_FALSE(parse("%H", "-0", tz, &tp));
- EXPECT_FALSE(parse("%M", "-0", tz, &tp));
- EXPECT_FALSE(parse("%S", "-0", tz, &tp));
- EXPECT_FALSE(parse("%z", "+-000", tz, &tp));
- EXPECT_FALSE(parse("%Ez", "+-0:00", tz, &tp));
- EXPECT_FALSE(parse("%z", "-00-0", tz, &tp));
- EXPECT_FALSE(parse("%Ez", "-00:-0", tz, &tp));
-}
-
-TEST(Parse, PosixConversions) {
- time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
- const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
-
- tp = reset;
- EXPECT_TRUE(parse("%d", "15", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).day());
-
- // %e is an extension, but is supported internally.
- tp = reset;
- EXPECT_TRUE(parse("%e", "15", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d
-
- tp = reset;
- EXPECT_TRUE(parse("%H", "17", tz, &tp));
- EXPECT_EQ(17, convert(tp, tz).hour());
-
- tp = reset;
- EXPECT_TRUE(parse("%I", "5", tz, &tp));
- EXPECT_EQ(5, convert(tp, tz).hour());
-
- // %j is parsed but ignored.
- EXPECT_TRUE(parse("%j", "32", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%m", "11", tz, &tp));
- EXPECT_EQ(11, convert(tp, tz).month());
-
- tp = reset;
- EXPECT_TRUE(parse("%M", "33", tz, &tp));
- EXPECT_EQ(33, convert(tp, tz).minute());
-
- tp = reset;
- EXPECT_TRUE(parse("%S", "55", tz, &tp));
- EXPECT_EQ(55, convert(tp, tz).second());
-
- // %U is parsed but ignored.
- EXPECT_TRUE(parse("%U", "15", tz, &tp));
-
- // %w is parsed but ignored.
- EXPECT_TRUE(parse("%w", "2", tz, &tp));
-
- // %W is parsed but ignored.
- EXPECT_TRUE(parse("%W", "22", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%y", "04", tz, &tp));
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- tp = reset;
- EXPECT_TRUE(parse("%Y", "2004", tz, &tp));
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- EXPECT_TRUE(parse("%%", "%", tz, &tp));
-
-#if defined(__linux__)
- // SU/C99/TZ extensions
-
- // Because we handle each (non-internal) specifier in a separate call
- // to strptime(), there is no way to group %C and %y together. So we
- // just skip the %C/%y case.
-#if 0
- tp = reset;
- EXPECT_TRUE(parse("%C %y", "20 04", tz, &tp));
- EXPECT_EQ(2004, convert(tp, tz).year());
-#endif
-
- tp = reset;
- EXPECT_TRUE(parse("%D", "02/03/04", tz, &tp));
- EXPECT_EQ(2, convert(tp, tz).month());
- EXPECT_EQ(3, convert(tp, tz).day());
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- EXPECT_TRUE(parse("%n", "\n", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%R", "03:44", tz, &tp));
- EXPECT_EQ(3, convert(tp, tz).hour());
- EXPECT_EQ(44, convert(tp, tz).minute());
-
- EXPECT_TRUE(parse("%t", "\t\v\f\n\r ", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%T", "03:44:55", tz, &tp));
- EXPECT_EQ(3, convert(tp, tz).hour());
- EXPECT_EQ(44, convert(tp, tz).minute());
- EXPECT_EQ(55, convert(tp, tz).second());
-
- tp = reset;
- EXPECT_TRUE(parse("%s", "1234567890", tz, &tp));
- EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
-
- // %s conversion, like %z/%Ez, pays no heed to the optional zone.
- time_zone lax;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax));
- tp = reset;
- EXPECT_TRUE(parse("%s", "1234567890", lax, &tp));
- EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
-
- // This is most important when the time has the same YMDhms
- // breakdown in the zone as some other time. For example, ...
- // 1414917000 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PDT)
- // 1414920600 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PST)
- tp = reset;
- EXPECT_TRUE(parse("%s", "1414917000", lax, &tp));
- EXPECT_EQ(chrono::system_clock::from_time_t(1414917000), tp);
- tp = reset;
- EXPECT_TRUE(parse("%s", "1414920600", lax, &tp));
- EXPECT_EQ(chrono::system_clock::from_time_t(1414920600), tp);
-#endif
-}
-
-TEST(Parse, LocaleSpecific) {
- time_zone tz = utc_time_zone();
- auto tp = chrono::system_clock::from_time_t(0);
- const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
-
- // %a is parsed but ignored.
- EXPECT_TRUE(parse("%a", "Mon", tz, &tp));
-
- // %A is parsed but ignored.
- EXPECT_TRUE(parse("%A", "Monday", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%b", "Feb", tz, &tp));
- EXPECT_EQ(2, convert(tp, tz).month());
-
- tp = reset;
- EXPECT_TRUE(parse("%B", "February", tz, &tp));
- EXPECT_EQ(2, convert(tp, tz).month());
-
- // %p is parsed but ignored if it's alone. But it's used with %I.
- EXPECT_TRUE(parse("%p", "AM", tz, &tp));
- tp = reset;
- EXPECT_TRUE(parse("%I %p", "5 PM", tz, &tp));
- EXPECT_EQ(17, convert(tp, tz).hour());
-
- tp = reset;
- EXPECT_TRUE(parse("%x", "02/03/04", tz, &tp));
- if (convert(tp, tz).month() == 2) {
- EXPECT_EQ(3, convert(tp, tz).day());
- } else {
- EXPECT_EQ(2, convert(tp, tz).day());
- EXPECT_EQ(3, convert(tp, tz).month());
- }
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- tp = reset;
- EXPECT_TRUE(parse("%X", "15:44:55", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).hour());
- EXPECT_EQ(44, convert(tp, tz).minute());
- EXPECT_EQ(55, convert(tp, tz).second());
-
-#if defined(__linux__)
- // SU/C99/TZ extensions
-
- tp = reset;
- EXPECT_TRUE(parse("%h", "Feb", tz, &tp));
- EXPECT_EQ(2, convert(tp, tz).month()); // Equivalent to %b
-
- tp = reset;
- EXPECT_TRUE(parse("%l %p", "5 PM", tz, &tp));
- EXPECT_EQ(17, convert(tp, tz).hour());
-
- tp = reset;
- EXPECT_TRUE(parse("%r", "03:44:55 PM", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).hour());
- EXPECT_EQ(44, convert(tp, tz).minute());
- EXPECT_EQ(55, convert(tp, tz).second());
-
- tp = reset;
- EXPECT_TRUE(parse("%Ec", "Tue Nov 19 05:06:07 2013", tz, &tp));
- EXPECT_EQ(convert(civil_second(2013, 11, 19, 5, 6, 7), tz), tp);
-
- // Modified conversion specifiers %E_
-
- tp = reset;
- EXPECT_TRUE(parse("%Ex", "02/03/04", tz, &tp));
- EXPECT_EQ(2, convert(tp, tz).month());
- EXPECT_EQ(3, convert(tp, tz).day());
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- tp = reset;
- EXPECT_TRUE(parse("%EX", "15:44:55", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).hour());
- EXPECT_EQ(44, convert(tp, tz).minute());
- EXPECT_EQ(55, convert(tp, tz).second());
-
- // %Ey, the year offset from %EC, doesn't really make sense alone as there
- // is no way to represent it in tm_year (%EC is not simply the century).
- // Yet, because we handle each (non-internal) specifier in a separate call
- // to strptime(), there is no way to group %EC and %Ey either. So we just
- // skip the %EC and %Ey cases.
-
- tp = reset;
- EXPECT_TRUE(parse("%EY", "2004", tz, &tp));
- EXPECT_EQ(2004, convert(tp, tz).year());
-
- // Modified conversion specifiers %O_
-
- tp = reset;
- EXPECT_TRUE(parse("%Od", "15", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).day());
-
- tp = reset;
- EXPECT_TRUE(parse("%Oe", "15", tz, &tp));
- EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d
-
- tp = reset;
- EXPECT_TRUE(parse("%OH", "17", tz, &tp));
- EXPECT_EQ(17, convert(tp, tz).hour());
-
- tp = reset;
- EXPECT_TRUE(parse("%OI", "5", tz, &tp));
- EXPECT_EQ(5, convert(tp, tz).hour());
-
- tp = reset;
- EXPECT_TRUE(parse("%Om", "11", tz, &tp));
- EXPECT_EQ(11, convert(tp, tz).month());
-
- tp = reset;
- EXPECT_TRUE(parse("%OM", "33", tz, &tp));
- EXPECT_EQ(33, convert(tp, tz).minute());
-
- tp = reset;
- EXPECT_TRUE(parse("%OS", "55", tz, &tp));
- EXPECT_EQ(55, convert(tp, tz).second());
-
- // %OU is parsed but ignored.
- EXPECT_TRUE(parse("%OU", "15", tz, &tp));
-
- // %Ow is parsed but ignored.
- EXPECT_TRUE(parse("%Ow", "2", tz, &tp));
-
- // %OW is parsed but ignored.
- EXPECT_TRUE(parse("%OW", "22", tz, &tp));
-
- tp = reset;
- EXPECT_TRUE(parse("%Oy", "04", tz, &tp));
- EXPECT_EQ(2004, convert(tp, tz).year());
-#endif
-}
-
-TEST(Parse, ExtendedSeconds) {
- const time_zone tz = utc_time_zone();
- const time_point<chrono::nanoseconds> unix_epoch =
- chrono::system_clock::from_time_t(0);
-
- // All %E<prec>S cases are treated the same as %E*S on input.
- auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", "10", "11", "12", "13", "14", "15"};
- for (const std::string& prec : precisions) {
- const std::string fmt = "%E" + prec + "S";
- SCOPED_TRACE(fmt);
- time_point<chrono::nanoseconds> tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "5", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.0", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.00", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.6", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.60", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.600", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.67", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.670", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "05.678", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(678), tp);
- }
-
- // Here is a "%E*S" case we got wrong for a while. The fractional
- // part of the first instant is less than 2^31 and was correctly
- // parsed, while the second (and any subsecond field >=2^31) failed.
- time_point<chrono::nanoseconds> tp = unix_epoch;
- EXPECT_TRUE(parse("%E*S", "0.2147483647", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse("%E*S", "0.2147483648", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
-
- // We should also be able to specify long strings of digits far
- // beyond the current resolution and have them convert the same way.
- tp = unix_epoch;
- EXPECT_TRUE(parse(
- "%E*S", "0.214748364801234567890123456789012345678901234567890123456789",
- tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
-}
-
-TEST(Parse, ExtendedSecondsScan) {
- const time_zone tz = utc_time_zone();
- time_point<chrono::nanoseconds> tp;
- for (int ms = 0; ms < 1000; ms += 111) {
- for (int us = 0; us < 1000; us += 27) {
- const int micros = ms * 1000 + us;
- for (int ns = 0; ns < 1000; ns += 9) {
- const auto expected = chrono::system_clock::from_time_t(0) +
- chrono::nanoseconds(micros * 1000 + ns);
- std::ostringstream oss;
- oss << "0." << std::setfill('0') << std::setw(3);
- oss << ms << std::setw(3) << us << std::setw(3) << ns;
- const std::string input = oss.str();
- EXPECT_TRUE(parse("%E*S", input, tz, &tp));
- EXPECT_EQ(expected, tp) << input;
- }
- }
- }
-}
-
-TEST(Parse, ExtendedSubeconds) {
- const time_zone tz = utc_time_zone();
- const time_point<chrono::nanoseconds> unix_epoch =
- chrono::system_clock::from_time_t(0);
-
- // All %E<prec>f cases are treated the same as %E*f on input.
- auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", "10", "11", "12", "13", "14", "15"};
- for (const std::string& prec : precisions) {
- const std::string fmt = "%E" + prec + "f";
- SCOPED_TRACE(fmt);
- time_point<chrono::nanoseconds> tp = unix_epoch - chrono::seconds(1);
- EXPECT_TRUE(parse(fmt, "", tz, &tp));
- EXPECT_EQ(unix_epoch, tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "6", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "60", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "600", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "67", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "670", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "678", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::milliseconds(678), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse(fmt, "6789", tz, &tp));
- EXPECT_EQ(
- unix_epoch + chrono::milliseconds(678) + chrono::microseconds(900), tp);
- }
-
- // Here is a "%E*f" case we got wrong for a while. The fractional
- // part of the first instant is less than 2^31 and was correctly
- // parsed, while the second (and any subsecond field >=2^31) failed.
- time_point<chrono::nanoseconds> tp = unix_epoch;
- EXPECT_TRUE(parse("%E*f", "2147483647", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
- tp = unix_epoch;
- EXPECT_TRUE(parse("%E*f", "2147483648", tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
-
- // We should also be able to specify long strings of digits far
- // beyond the current resolution and have them convert the same way.
- tp = unix_epoch;
- EXPECT_TRUE(parse(
- "%E*f", "214748364801234567890123456789012345678901234567890123456789",
- tz, &tp));
- EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
-}
-
-TEST(Parse, ExtendedSubecondsScan) {
- time_point<chrono::nanoseconds> tp;
- const time_zone tz = utc_time_zone();
- for (int ms = 0; ms < 1000; ms += 111) {
- for (int us = 0; us < 1000; us += 27) {
- const int micros = ms * 1000 + us;
- for (int ns = 0; ns < 1000; ns += 9) {
- std::ostringstream oss;
- oss << std::setfill('0') << std::setw(3) << ms;
- oss << std::setw(3) << us << std::setw(3) << ns;
- const std::string nanos = oss.str();
- const auto expected = chrono::system_clock::from_time_t(0) +
- chrono::nanoseconds(micros * 1000 + ns);
- for (int ps = 0; ps < 1000; ps += 250) {
- std::ostringstream ps_oss;
- oss << std::setfill('0') << std::setw(3) << ps;
- const std::string input = nanos + ps_oss.str() + "999";
- EXPECT_TRUE(parse("%E*f", input, tz, &tp));
- EXPECT_EQ(expected + chrono::nanoseconds(ps) / 1000, tp) << input;
- }
- }
- }
- }
-}
-
-TEST(Parse, ExtendedOffset) {
- const time_zone utc = utc_time_zone();
- time_point<cctz::seconds> tp;
-
- EXPECT_TRUE(parse("%Ez", "+00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "-12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse("%Ez", "+12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse("%Ez", "-12:3", utc, &tp));
-
- for (auto fmt : {"%Ez", "%z"}) {
- EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
-
- EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
- EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
- }
-}
-
-TEST(Parse, ExtendedSecondOffset) {
- const time_zone utc = utc_time_zone();
- time_point<cctz::seconds> tp;
-
- for (auto fmt : {"%Ez", "%E*z", "%:z", "%::z", "%:::z"}) {
- EXPECT_TRUE(parse(fmt, "+00:00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse(fmt, "+12:34:56", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse(fmt, "-12:34:5", utc, &tp));
-
- EXPECT_TRUE(parse(fmt, "+000000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
- EXPECT_TRUE(parse(fmt, "+123456", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
- EXPECT_FALSE(parse(fmt, "-12345", utc, &tp));
-
- EXPECT_TRUE(parse(fmt, "+00:00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "+12:34", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse(fmt, "-12:3", utc, &tp));
-
- EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
- EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
-
- EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
- EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
- EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
- EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
- }
-}
-
-TEST(Parse, ExtendedYears) {
- const time_zone utc = utc_time_zone();
- const char e4y_fmt[] = "%E4Y%m%d"; // no separators
- time_point<cctz::seconds> tp;
-
- // %E4Y consumes exactly four chars, including any sign.
- EXPECT_TRUE(parse(e4y_fmt, "-9991127", utc, &tp));
- EXPECT_EQ(convert(civil_second(-999, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "-0991127", utc, &tp));
- EXPECT_EQ(convert(civil_second(-99, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "-0091127", utc, &tp));
- EXPECT_EQ(convert(civil_second(-9, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "-0011127", utc, &tp));
- EXPECT_EQ(convert(civil_second(-1, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "00001127", utc, &tp));
- EXPECT_EQ(convert(civil_second(0, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "00011127", utc, &tp));
- EXPECT_EQ(convert(civil_second(1, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "00091127", utc, &tp));
- EXPECT_EQ(convert(civil_second(9, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "00991127", utc, &tp));
- EXPECT_EQ(convert(civil_second(99, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "09991127", utc, &tp));
- EXPECT_EQ(convert(civil_second(999, 11, 27, 0, 0, 0), utc), tp);
- EXPECT_TRUE(parse(e4y_fmt, "99991127", utc, &tp));
- EXPECT_EQ(convert(civil_second(9999, 11, 27, 0, 0, 0), utc), tp);
-
- // When the year is outside [-999:9999], the parse fails.
- EXPECT_FALSE(parse(e4y_fmt, "-10001127", utc, &tp));
- EXPECT_FALSE(parse(e4y_fmt, "100001127", utc, &tp));
-}
-
-TEST(Parse, RFC3339Format) {
- const time_zone tz = utc_time_zone();
- time_point<chrono::nanoseconds> tp;
- EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp));
- ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC");
-
- // Check that %ET also accepts "t".
- time_point<chrono::nanoseconds> tp2;
- EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12t20:21:00+00:00", tz, &tp2));
- EXPECT_EQ(tp, tp2);
-
- // Check that %Ez also accepts "Z" as a synonym for "+00:00".
- time_point<chrono::nanoseconds> tp3;
- EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp3));
- EXPECT_EQ(tp, tp3);
-
- // Check that %Ez also accepts "z" as a synonym for "+00:00".
- time_point<chrono::nanoseconds> tp4;
- EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00z", tz, &tp4));
- EXPECT_EQ(tp, tp4);
-}
-
-TEST(Parse, Week) {
- const time_zone utc = utc_time_zone();
- time_point<cctz::seconds> tp;
-
- auto exp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2017-01-7", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2017-00-0", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2017-53-7", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2017-52-0", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2018-00-1", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2018-01-1", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2018-52-1", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2018-53-1", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2019-00-2", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2019-00-2", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2019-52-2", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2019-52-2", utc, &tp));
- EXPECT_EQ(exp, tp);
-}
-
-TEST(Parse, WeekYearShift) {
- // %U/%W conversions with week values in {0, 52, 53} can slip
- // into the previous/following calendar years.
- const time_zone utc = utc_time_zone();
- time_point<cctz::seconds> tp;
-
- auto exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2020-00-2", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2020-00-2", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- exp = convert(civil_second(2021, 1, 1, 0, 0, 0), utc);
- EXPECT_TRUE(parse("%Y-%U-%u", "2020-52-5", utc, &tp));
- EXPECT_EQ(exp, tp);
- EXPECT_TRUE(parse("%Y-%W-%w", "2020-52-5", utc, &tp));
- EXPECT_EQ(exp, tp);
-
- // Slipping into the previous/following calendar years should fail when
- // we're already at the extremes.
- EXPECT_FALSE(parse("%Y-%U-%u", "-9223372036854775808-0-7", utc, &tp));
- EXPECT_FALSE(parse("%Y-%U-%u", "9223372036854775807-53-7", utc, &tp));
-}
-
-TEST(Parse, MaxRange) {
- const time_zone utc = utc_time_zone();
- time_point<cctz::seconds> tp;
-
- // tests the upper limit using +00:00 offset
- EXPECT_TRUE(
- parse(RFC3339_sec, "292277026596-12-04T15:30:07+00:00", utc, &tp));
- EXPECT_EQ(tp, time_point<cctz::seconds>::max());
- EXPECT_FALSE(
- parse(RFC3339_sec, "292277026596-12-04T15:30:08+00:00", utc, &tp));
-
- // tests the upper limit using -01:00 offset
- EXPECT_TRUE(
- parse(RFC3339_sec, "292277026596-12-04T14:30:07-01:00", utc, &tp));
- EXPECT_EQ(tp, time_point<cctz::seconds>::max());
- EXPECT_FALSE(
- parse(RFC3339_sec, "292277026596-12-04T15:30:07-01:00", utc, &tp));
-
- // tests the lower limit using +00:00 offset
- EXPECT_TRUE(
- parse(RFC3339_sec, "-292277022657-01-27T08:29:52+00:00", utc, &tp));
- EXPECT_EQ(tp, time_point<cctz::seconds>::min());
- EXPECT_FALSE(
- parse(RFC3339_sec, "-292277022657-01-27T08:29:51+00:00", utc, &tp));
-
- // tests the lower limit using +01:00 offset
- EXPECT_TRUE(
- parse(RFC3339_sec, "-292277022657-01-27T09:29:52+01:00", utc, &tp));
- EXPECT_EQ(tp, time_point<cctz::seconds>::min());
- EXPECT_FALSE(
- parse(RFC3339_sec, "-292277022657-01-27T08:29:51+01:00", utc, &tp));
-
- // tests max/min civil-second overflow
- EXPECT_FALSE(parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01",
- utc, &tp));
- EXPECT_FALSE(parse(RFC3339_sec, "-9223372036854775808-01-01T00:00:00+00:01",
- utc, &tp));
-
- // TODO: Add tests that parsing times with fractional seconds overflow
- // appropriately. This can't be done until cctz::parse() properly detects
- // overflow when combining the chrono seconds and femto.
-}
-
-//
-// Roundtrip test for format()/parse().
-//
-
-TEST(FormatParse, RoundTrip) {
- time_zone lax;
- EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax));
- const auto in = convert(civil_second(1977, 6, 28, 9, 8, 7), lax);
- const auto subseconds = chrono::nanoseconds(654321);
-
- // RFC3339, which renders subseconds.
- {
- time_point<chrono::nanoseconds> out;
- const std::string s = format(RFC3339_full, in + subseconds, lax);
- EXPECT_TRUE(parse(RFC3339_full, s, lax, &out)) << s;
- EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez
- }
-
- // RFC1123, which only does whole seconds.
- {
- time_point<chrono::nanoseconds> out;
- const std::string s = format(RFC1123_full, in, lax);
- EXPECT_TRUE(parse(RFC1123_full, s, lax, &out)) << s;
- EXPECT_EQ(in, out); // RFC1123_full includes %z
- }
-
-#if defined(_WIN32) || defined(_WIN64)
- // Initial investigations indicate the %c does not roundtrip on Windows.
- // TODO: Figure out what is going on here (perhaps a locale problem).
-#else
- // Even though we don't know what %c will produce, it should roundtrip,
- // but only in the 0-offset timezone.
- {
- time_point<chrono::nanoseconds> out;
- time_zone utc = utc_time_zone();
- const std::string s = format("%c", in, utc);
- EXPECT_TRUE(parse("%c", s, utc, &out)) << s;
- EXPECT_EQ(in, out);
- }
-#endif
-}
-
-TEST(FormatParse, RoundTripDistantFuture) {
- const time_zone utc = utc_time_zone();
- const time_point<cctz::seconds> in = time_point<cctz::seconds>::max();
- const std::string s = format(RFC3339_full, in, utc);
- time_point<cctz::seconds> out;
- EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
- EXPECT_EQ(in, out);
-}
-
-TEST(FormatParse, RoundTripDistantPast) {
- const time_zone utc = utc_time_zone();
- const time_point<cctz::seconds> in = time_point<cctz::seconds>::min();
- const std::string s = format(RFC3339_full, in, utc);
- time_point<cctz::seconds> out;
- EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
- EXPECT_EQ(in, out);
-}
-
-} // namespace cctz
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "cctz/time_zone.h"
+
+#include <chrono>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#include "cctz/civil_time.h"
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+namespace chrono = std::chrono;
+
+namespace cctz {
+
+namespace {
+
+// This helper is a macro so that failed expectations show up with the
+// correct line numbers.
+#define ExpectTime(tp, tz, y, m, d, hh, mm, ss, off, isdst, zone) \
+ do { \
+ time_zone::absolute_lookup al = tz.lookup(tp); \
+ EXPECT_EQ(y, al.cs.year()); \
+ EXPECT_EQ(m, al.cs.month()); \
+ EXPECT_EQ(d, al.cs.day()); \
+ EXPECT_EQ(hh, al.cs.hour()); \
+ EXPECT_EQ(mm, al.cs.minute()); \
+ EXPECT_EQ(ss, al.cs.second()); \
+ EXPECT_EQ(off, al.offset); \
+ EXPECT_TRUE(isdst == al.is_dst); \
+ EXPECT_STREQ(zone, al.abbr); \
+ } while (0)
+
+const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
+const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
+
+const char RFC1123_full[] = "%a, %d %b %Y %H:%M:%S %z";
+const char RFC1123_no_wday[] = "%d %b %Y %H:%M:%S %z";
+
+// A helper that tests the given format specifier by itself, and with leading
+// and trailing characters. For example: TestFormatSpecifier(tp, "%a", "Thu").
+template <typename D>
+void TestFormatSpecifier(time_point<D> tp, time_zone tz, const std::string& fmt,
+ const std::string& ans) {
+ EXPECT_EQ(ans, format(fmt, tp, tz)) << fmt;
+ EXPECT_EQ("xxx " + ans, format("xxx " + fmt, tp, tz));
+ EXPECT_EQ(ans + " yyy", format(fmt + " yyy", tp, tz));
+ EXPECT_EQ("xxx " + ans + " yyy", format("xxx " + fmt + " yyy", tp, tz));
+}
+
+} // namespace
+
+//
+// Testing format()
+//
+
+TEST(Format, TimePointResolution) {
+ const char kFmt[] = "%H:%M:%E*S";
+ const time_zone utc = utc_time_zone();
+ const time_point<chrono::nanoseconds> t0 =
+ chrono::system_clock::from_time_t(1420167845) +
+ chrono::milliseconds(123) + chrono::microseconds(456) +
+ chrono::nanoseconds(789);
+ EXPECT_EQ(
+ "03:04:05.123456789",
+ format(kFmt, chrono::time_point_cast<chrono::nanoseconds>(t0), utc));
+ EXPECT_EQ(
+ "03:04:05.123456",
+ format(kFmt, chrono::time_point_cast<chrono::microseconds>(t0), utc));
+ EXPECT_EQ(
+ "03:04:05.123",
+ format(kFmt, chrono::time_point_cast<chrono::milliseconds>(t0), utc));
+ EXPECT_EQ("03:04:05",
+ format(kFmt, chrono::time_point_cast<chrono::seconds>(t0), utc));
+ EXPECT_EQ("03:04:05",
+ format(kFmt, chrono::time_point_cast<cctz::seconds>(t0), utc));
+ EXPECT_EQ("03:04:00",
+ format(kFmt, chrono::time_point_cast<chrono::minutes>(t0), utc));
+ EXPECT_EQ("03:00:00",
+ format(kFmt, chrono::time_point_cast<chrono::hours>(t0), utc));
+}
+
+TEST(Format, TimePointExtendedResolution) {
+ const char kFmt[] = "%H:%M:%E*S";
+ const time_zone utc = utc_time_zone();
+ const time_point<cctz::seconds> tp =
+ chrono::time_point_cast<cctz::seconds>(
+ chrono::system_clock::from_time_t(0)) +
+ chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56);
+
+ EXPECT_EQ(
+ "12:34:56.123456789012345",
+ detail::format(kFmt, tp, detail::femtoseconds(123456789012345), utc));
+ EXPECT_EQ(
+ "12:34:56.012345678901234",
+ detail::format(kFmt, tp, detail::femtoseconds(12345678901234), utc));
+ EXPECT_EQ(
+ "12:34:56.001234567890123",
+ detail::format(kFmt, tp, detail::femtoseconds(1234567890123), utc));
+ EXPECT_EQ(
+ "12:34:56.000123456789012",
+ detail::format(kFmt, tp, detail::femtoseconds(123456789012), utc));
+
+ EXPECT_EQ("12:34:56.000000000000123",
+ detail::format(kFmt, tp, detail::femtoseconds(123), utc));
+ EXPECT_EQ("12:34:56.000000000000012",
+ detail::format(kFmt, tp, detail::femtoseconds(12), utc));
+ EXPECT_EQ("12:34:56.000000000000001",
+ detail::format(kFmt, tp, detail::femtoseconds(1), utc));
+}
+
+TEST(Format, Basics) {
+ time_zone tz = utc_time_zone();
+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+
+ // Starts with a couple basic edge cases.
+ EXPECT_EQ("", format("", tp, tz));
+ EXPECT_EQ(" ", format(" ", tp, tz));
+ EXPECT_EQ(" ", format(" ", tp, tz));
+ EXPECT_EQ("xxx", format("xxx", tp, tz));
+ std::string big(128, 'x');
+ EXPECT_EQ(big, format(big, tp, tz));
+ // Cause the 1024-byte buffer to grow.
+ std::string bigger(100000, 'x');
+ EXPECT_EQ(bigger, format(bigger, tp, tz));
+
+ tp += chrono::hours(13) + chrono::minutes(4) + chrono::seconds(5);
+ tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+ chrono::nanoseconds(8);
+ EXPECT_EQ("1970-01-01", format("%Y-%m-%d", tp, tz));
+ EXPECT_EQ("13:04:05", format("%H:%M:%S", tp, tz));
+ EXPECT_EQ("13:04:05.006", format("%H:%M:%E3S", tp, tz));
+ EXPECT_EQ("13:04:05.006007", format("%H:%M:%E6S", tp, tz));
+ EXPECT_EQ("13:04:05.006007008", format("%H:%M:%E9S", tp, tz));
+}
+
+TEST(Format, PosixConversions) {
+ const time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+
+ TestFormatSpecifier(tp, tz, "%d", "01");
+ TestFormatSpecifier(tp, tz, "%e", " 1"); // extension but internal support
+ TestFormatSpecifier(tp, tz, "%H", "00");
+ TestFormatSpecifier(tp, tz, "%I", "12");
+ TestFormatSpecifier(tp, tz, "%j", "001");
+ TestFormatSpecifier(tp, tz, "%m", "01");
+ TestFormatSpecifier(tp, tz, "%M", "00");
+ TestFormatSpecifier(tp, tz, "%S", "00");
+ TestFormatSpecifier(tp, tz, "%U", "00");
+ TestFormatSpecifier(tp, tz, "%w", "4"); // 4=Thursday
+ TestFormatSpecifier(tp, tz, "%W", "00");
+ TestFormatSpecifier(tp, tz, "%y", "70");
+ TestFormatSpecifier(tp, tz, "%Y", "1970");
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%Z", "UTC");
+ TestFormatSpecifier(tp, tz, "%%", "%");
+
+#if defined(__linux__)
+ // SU/C99/TZ extensions
+ TestFormatSpecifier(tp, tz, "%C", "19");
+ TestFormatSpecifier(tp, tz, "%D", "01/01/70");
+ TestFormatSpecifier(tp, tz, "%F", "1970-01-01");
+ TestFormatSpecifier(tp, tz, "%g", "70");
+ TestFormatSpecifier(tp, tz, "%G", "1970");
+ TestFormatSpecifier(tp, tz, "%k", " 0");
+ TestFormatSpecifier(tp, tz, "%l", "12");
+ TestFormatSpecifier(tp, tz, "%n", "\n");
+ TestFormatSpecifier(tp, tz, "%R", "00:00");
+ TestFormatSpecifier(tp, tz, "%t", "\t");
+ TestFormatSpecifier(tp, tz, "%T", "00:00:00");
+ TestFormatSpecifier(tp, tz, "%u", "4"); // 4=Thursday
+ TestFormatSpecifier(tp, tz, "%V", "01");
+ TestFormatSpecifier(tp, tz, "%s", "0");
+#endif
+}
+
+TEST(Format, LocaleSpecific) {
+ const time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+
+ TestFormatSpecifier(tp, tz, "%a", "Thu");
+ TestFormatSpecifier(tp, tz, "%A", "Thursday");
+ TestFormatSpecifier(tp, tz, "%b", "Jan");
+ TestFormatSpecifier(tp, tz, "%B", "January");
+
+ // %c should at least produce the numeric year and time-of-day.
+ const std::string s = format("%c", tp, utc_time_zone());
+ EXPECT_THAT(s, testing::HasSubstr("1970"));
+ EXPECT_THAT(s, testing::HasSubstr("00:00:00"));
+
+ TestFormatSpecifier(tp, tz, "%p", "AM");
+ TestFormatSpecifier(tp, tz, "%x", "01/01/70");
+ TestFormatSpecifier(tp, tz, "%X", "00:00:00");
+
+#if defined(__linux__)
+ // SU/C99/TZ extensions
+ TestFormatSpecifier(tp, tz, "%h", "Jan"); // Same as %b
+ TestFormatSpecifier(tp, tz, "%P", "am");
+ TestFormatSpecifier(tp, tz, "%r", "12:00:00 AM");
+
+ // Modified conversion specifiers %E_
+ TestFormatSpecifier(tp, tz, "%Ec", "Thu Jan 1 00:00:00 1970");
+ TestFormatSpecifier(tp, tz, "%EC", "19");
+ TestFormatSpecifier(tp, tz, "%Ex", "01/01/70");
+ TestFormatSpecifier(tp, tz, "%EX", "00:00:00");
+ TestFormatSpecifier(tp, tz, "%Ey", "70");
+ TestFormatSpecifier(tp, tz, "%EY", "1970");
+
+ // Modified conversion specifiers %O_
+ TestFormatSpecifier(tp, tz, "%Od", "01");
+ TestFormatSpecifier(tp, tz, "%Oe", " 1");
+ TestFormatSpecifier(tp, tz, "%OH", "00");
+ TestFormatSpecifier(tp, tz, "%OI", "12");
+ TestFormatSpecifier(tp, tz, "%Om", "01");
+ TestFormatSpecifier(tp, tz, "%OM", "00");
+ TestFormatSpecifier(tp, tz, "%OS", "00");
+ TestFormatSpecifier(tp, tz, "%Ou", "4"); // 4=Thursday
+ TestFormatSpecifier(tp, tz, "%OU", "00");
+ TestFormatSpecifier(tp, tz, "%OV", "01");
+ TestFormatSpecifier(tp, tz, "%Ow", "4"); // 4=Thursday
+ TestFormatSpecifier(tp, tz, "%OW", "00");
+ TestFormatSpecifier(tp, tz, "%Oy", "70");
+#endif
+}
+
+TEST(Format, Escaping) {
+ const time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+
+ TestFormatSpecifier(tp, tz, "%%", "%");
+ TestFormatSpecifier(tp, tz, "%%a", "%a");
+ TestFormatSpecifier(tp, tz, "%%b", "%b");
+ TestFormatSpecifier(tp, tz, "%%Ea", "%Ea");
+ TestFormatSpecifier(tp, tz, "%%Es", "%Es");
+ TestFormatSpecifier(tp, tz, "%%E3S", "%E3S");
+ TestFormatSpecifier(tp, tz, "%%OS", "%OS");
+ TestFormatSpecifier(tp, tz, "%%O3S", "%O3S");
+
+ // Multiple levels of escaping.
+ TestFormatSpecifier(tp, tz, "%%%Y", "%1970");
+ TestFormatSpecifier(tp, tz, "%%%E3S", "%00.000");
+ TestFormatSpecifier(tp, tz, "%%%%E3S", "%%E3S");
+}
+
+TEST(Format, ExtendedSeconds) {
+ const time_zone tz = utc_time_zone();
+
+ // No subseconds.
+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+ tp += chrono::seconds(5);
+ EXPECT_EQ("05", format("%E*S", tp, tz));
+ EXPECT_EQ("05", format("%E0S", tp, tz));
+ EXPECT_EQ("05.0", format("%E1S", tp, tz));
+ EXPECT_EQ("05.00", format("%E2S", tp, tz));
+ EXPECT_EQ("05.000", format("%E3S", tp, tz));
+ EXPECT_EQ("05.0000", format("%E4S", tp, tz));
+ EXPECT_EQ("05.00000", format("%E5S", tp, tz));
+ EXPECT_EQ("05.000000", format("%E6S", tp, tz));
+ EXPECT_EQ("05.0000000", format("%E7S", tp, tz));
+ EXPECT_EQ("05.00000000", format("%E8S", tp, tz));
+ EXPECT_EQ("05.000000000", format("%E9S", tp, tz));
+ EXPECT_EQ("05.0000000000", format("%E10S", tp, tz));
+ EXPECT_EQ("05.00000000000", format("%E11S", tp, tz));
+ EXPECT_EQ("05.000000000000", format("%E12S", tp, tz));
+ EXPECT_EQ("05.0000000000000", format("%E13S", tp, tz));
+ EXPECT_EQ("05.00000000000000", format("%E14S", tp, tz));
+ EXPECT_EQ("05.000000000000000", format("%E15S", tp, tz));
+
+ // With subseconds.
+ tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+ chrono::nanoseconds(8);
+ EXPECT_EQ("05.006007008", format("%E*S", tp, tz));
+ EXPECT_EQ("05", format("%E0S", tp, tz));
+ EXPECT_EQ("05.0", format("%E1S", tp, tz));
+ EXPECT_EQ("05.00", format("%E2S", tp, tz));
+ EXPECT_EQ("05.006", format("%E3S", tp, tz));
+ EXPECT_EQ("05.0060", format("%E4S", tp, tz));
+ EXPECT_EQ("05.00600", format("%E5S", tp, tz));
+ EXPECT_EQ("05.006007", format("%E6S", tp, tz));
+ EXPECT_EQ("05.0060070", format("%E7S", tp, tz));
+ EXPECT_EQ("05.00600700", format("%E8S", tp, tz));
+ EXPECT_EQ("05.006007008", format("%E9S", tp, tz));
+ EXPECT_EQ("05.0060070080", format("%E10S", tp, tz));
+ EXPECT_EQ("05.00600700800", format("%E11S", tp, tz));
+ EXPECT_EQ("05.006007008000", format("%E12S", tp, tz));
+ EXPECT_EQ("05.0060070080000", format("%E13S", tp, tz));
+ EXPECT_EQ("05.00600700800000", format("%E14S", tp, tz));
+ EXPECT_EQ("05.006007008000000", format("%E15S", tp, tz));
+
+ // Times before the Unix epoch.
+ tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1);
+ EXPECT_EQ("1969-12-31 23:59:59.999999",
+ format("%Y-%m-%d %H:%M:%E*S", tp, tz));
+
+ // Here is a "%E*S" case we got wrong for a while. While the first
+ // instant below is correctly rendered as "...:07.333304", the second
+ // one used to appear as "...:07.33330499999999999".
+ tp = chrono::system_clock::from_time_t(0) +
+ chrono::microseconds(1395024427333304);
+ EXPECT_EQ("2014-03-17 02:47:07.333304",
+ format("%Y-%m-%d %H:%M:%E*S", tp, tz));
+ tp += chrono::microseconds(1);
+ EXPECT_EQ("2014-03-17 02:47:07.333305",
+ format("%Y-%m-%d %H:%M:%E*S", tp, tz));
+}
+
+TEST(Format, ExtendedSubeconds) {
+ const time_zone tz = utc_time_zone();
+
+ // No subseconds.
+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+ tp += chrono::seconds(5);
+ EXPECT_EQ("0", format("%E*f", tp, tz));
+ EXPECT_EQ("", format("%E0f", tp, tz));
+ EXPECT_EQ("0", format("%E1f", tp, tz));
+ EXPECT_EQ("00", format("%E2f", tp, tz));
+ EXPECT_EQ("000", format("%E3f", tp, tz));
+ EXPECT_EQ("0000", format("%E4f", tp, tz));
+ EXPECT_EQ("00000", format("%E5f", tp, tz));
+ EXPECT_EQ("000000", format("%E6f", tp, tz));
+ EXPECT_EQ("0000000", format("%E7f", tp, tz));
+ EXPECT_EQ("00000000", format("%E8f", tp, tz));
+ EXPECT_EQ("000000000", format("%E9f", tp, tz));
+ EXPECT_EQ("0000000000", format("%E10f", tp, tz));
+ EXPECT_EQ("00000000000", format("%E11f", tp, tz));
+ EXPECT_EQ("000000000000", format("%E12f", tp, tz));
+ EXPECT_EQ("0000000000000", format("%E13f", tp, tz));
+ EXPECT_EQ("00000000000000", format("%E14f", tp, tz));
+ EXPECT_EQ("000000000000000", format("%E15f", tp, tz));
+
+ // With subseconds.
+ tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+ chrono::nanoseconds(8);
+ EXPECT_EQ("006007008", format("%E*f", tp, tz));
+ EXPECT_EQ("", format("%E0f", tp, tz));
+ EXPECT_EQ("0", format("%E1f", tp, tz));
+ EXPECT_EQ("00", format("%E2f", tp, tz));
+ EXPECT_EQ("006", format("%E3f", tp, tz));
+ EXPECT_EQ("0060", format("%E4f", tp, tz));
+ EXPECT_EQ("00600", format("%E5f", tp, tz));
+ EXPECT_EQ("006007", format("%E6f", tp, tz));
+ EXPECT_EQ("0060070", format("%E7f", tp, tz));
+ EXPECT_EQ("00600700", format("%E8f", tp, tz));
+ EXPECT_EQ("006007008", format("%E9f", tp, tz));
+ EXPECT_EQ("0060070080", format("%E10f", tp, tz));
+ EXPECT_EQ("00600700800", format("%E11f", tp, tz));
+ EXPECT_EQ("006007008000", format("%E12f", tp, tz));
+ EXPECT_EQ("0060070080000", format("%E13f", tp, tz));
+ EXPECT_EQ("00600700800000", format("%E14f", tp, tz));
+ EXPECT_EQ("006007008000000", format("%E15f", tp, tz));
+
+ // Times before the Unix epoch.
+ tp = chrono::system_clock::from_time_t(0) + chrono::microseconds(-1);
+ EXPECT_EQ("1969-12-31 23:59:59.999999",
+ format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
+
+ // Here is a "%E*S" case we got wrong for a while. While the first
+ // instant below is correctly rendered as "...:07.333304", the second
+ // one used to appear as "...:07.33330499999999999".
+ tp = chrono::system_clock::from_time_t(0) +
+ chrono::microseconds(1395024427333304);
+ EXPECT_EQ("2014-03-17 02:47:07.333304",
+ format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
+ tp += chrono::microseconds(1);
+ EXPECT_EQ("2014-03-17 02:47:07.333305",
+ format("%Y-%m-%d %H:%M:%S.%E*f", tp, tz));
+}
+
+TEST(Format, CompareExtendSecondsVsSubseconds) {
+ const time_zone tz = utc_time_zone();
+
+ // This test case illustrates the differences/similarities between:
+ // fmt_A: %E<prec>S
+ // fmt_B: %S.%E<prec>f
+ auto fmt_A = [](const std::string& prec) { return "%E" + prec + "S"; };
+ auto fmt_B = [](const std::string& prec) { return "%S.%E" + prec + "f"; };
+
+ // No subseconds:
+ time_point<chrono::nanoseconds> tp = chrono::system_clock::from_time_t(0);
+ tp += chrono::seconds(5);
+ // ... %E*S and %S.%E*f are different.
+ EXPECT_EQ("05", format(fmt_A("*"), tp, tz));
+ EXPECT_EQ("05.0", format(fmt_B("*"), tp, tz));
+ // ... %E0S and %S.%E0f are different.
+ EXPECT_EQ("05", format(fmt_A("0"), tp, tz));
+ EXPECT_EQ("05.", format(fmt_B("0"), tp, tz));
+ // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15].
+ for (int prec = 1; prec <= 15; ++prec) {
+ const std::string a = format(fmt_A(std::to_string(prec)), tp, tz);
+ const std::string b = format(fmt_B(std::to_string(prec)), tp, tz);
+ EXPECT_EQ(a, b) << "prec=" << prec;
+ }
+
+ // With subseconds:
+ // ... %E*S and %S.%E*f are the same.
+ tp += chrono::milliseconds(6) + chrono::microseconds(7) +
+ chrono::nanoseconds(8);
+ EXPECT_EQ("05.006007008", format(fmt_A("*"), tp, tz));
+ EXPECT_EQ("05.006007008", format(fmt_B("*"), tp, tz));
+ // ... %E0S and %S.%E0f are different.
+ EXPECT_EQ("05", format(fmt_A("0"), tp, tz));
+ EXPECT_EQ("05.", format(fmt_B("0"), tp, tz));
+ // ... %E<prec>S and %S.%E<prec>f are the same for prec in [1:15].
+ for (int prec = 1; prec <= 15; ++prec) {
+ const std::string a = format(fmt_A(std::to_string(prec)), tp, tz);
+ const std::string b = format(fmt_B(std::to_string(prec)), tp, tz);
+ EXPECT_EQ(a, b) << "prec=" << prec;
+ }
+}
+
+TEST(Format, ExtendedOffset) {
+ const auto tp = chrono::system_clock::from_time_t(0);
+
+ auto tz = fixed_time_zone(cctz::seconds::zero());
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
+
+ tz = fixed_time_zone(chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
+
+ tz = fixed_time_zone(-chrono::seconds(56)); // NOTE: +00:00
+ TestFormatSpecifier(tp, tz, "%z", "+0000");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:00");
+
+ tz = fixed_time_zone(chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "+0034");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "-0034");
+ TestFormatSpecifier(tp, tz, "%:z", "-00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
+
+ tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+0034");
+ TestFormatSpecifier(tp, tz, "%:z", "+00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-0034");
+ TestFormatSpecifier(tp, tz, "%:z", "-00:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-00:34");
+
+ tz = fixed_time_zone(chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%z", "+1200");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
+
+ tz = fixed_time_zone(-chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%z", "-1200");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+1200");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:00");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-1200");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:00");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:00");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "+1234");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%z", "-1234");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "+1234");
+ TestFormatSpecifier(tp, tz, "%:z", "+12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%z", "-1234");
+ TestFormatSpecifier(tp, tz, "%:z", "-12:34");
+ TestFormatSpecifier(tp, tz, "%Ez", "-12:34");
+}
+
+TEST(Format, ExtendedSecondOffset) {
+ const auto tp = chrono::system_clock::from_time_t(0);
+
+ auto tz = fixed_time_zone(cctz::seconds::zero());
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00");
+
+ tz = fixed_time_zone(chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:00:56");
+
+ tz = fixed_time_zone(-chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:00:56");
+
+ tz = fixed_time_zone(chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:34");
+
+ tz = fixed_time_zone(-chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:34");
+
+ tz = fixed_time_zone(chrono::minutes(34) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+00:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+00:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+00:34:56");
+
+ tz = fixed_time_zone(-chrono::minutes(34) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-00:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-00:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-00:34:56");
+
+ tz = fixed_time_zone(chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12");
+
+ tz = fixed_time_zone(-chrono::hours(12));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:00:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:00:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:00:56");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:00:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:00:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:00:56");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:34");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:34:00");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:34:00");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:34");
+
+ tz = fixed_time_zone(chrono::hours(12) + chrono::minutes(34) +
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "+12:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "+12:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "+12:34:56");
+
+ tz = fixed_time_zone(-chrono::hours(12) - chrono::minutes(34) -
+ chrono::seconds(56));
+ TestFormatSpecifier(tp, tz, "%E*z", "-12:34:56");
+ TestFormatSpecifier(tp, tz, "%::z", "-12:34:56");
+ TestFormatSpecifier(tp, tz, "%:::z", "-12:34:56");
+}
+
+TEST(Format, ExtendedYears) {
+ const time_zone utc = utc_time_zone();
+ const char e4y_fmt[] = "%E4Y%m%d"; // no separators
+
+ // %E4Y zero-pads the year to produce at least 4 chars, including the sign.
+ auto tp = convert(civil_second(-999, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("-9991127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(-99, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("-0991127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(-9, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("-0091127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(-1, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("-0011127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(0, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("00001127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(1, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("00011127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(9, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("00091127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(99, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("00991127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(999, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("09991127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(9999, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("99991127", format(e4y_fmt, tp, utc));
+
+ // When the year is outside [-999:9999], more than 4 chars are produced.
+ tp = convert(civil_second(-1000, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("-10001127", format(e4y_fmt, tp, utc));
+ tp = convert(civil_second(10000, 11, 27, 0, 0, 0), utc);
+ EXPECT_EQ("100001127", format(e4y_fmt, tp, utc));
+}
+
+TEST(Format, RFC3339Format) {
+ time_zone tz;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+
+ time_point<chrono::nanoseconds> tp =
+ convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::milliseconds(100);
+ EXPECT_EQ("1977-06-28T09:08:07.1-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::milliseconds(20);
+ EXPECT_EQ("1977-06-28T09:08:07.12-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::milliseconds(3);
+ EXPECT_EQ("1977-06-28T09:08:07.123-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::microseconds(400);
+ EXPECT_EQ("1977-06-28T09:08:07.1234-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::microseconds(50);
+ EXPECT_EQ("1977-06-28T09:08:07.12345-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::microseconds(6);
+ EXPECT_EQ("1977-06-28T09:08:07.123456-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::nanoseconds(700);
+ EXPECT_EQ("1977-06-28T09:08:07.1234567-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::nanoseconds(80);
+ EXPECT_EQ("1977-06-28T09:08:07.12345678-07:00", format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+
+ tp += chrono::nanoseconds(9);
+ EXPECT_EQ("1977-06-28T09:08:07.123456789-07:00",
+ format(RFC3339_full, tp, tz));
+ EXPECT_EQ("1977-06-28T09:08:07-07:00", format(RFC3339_sec, tp, tz));
+}
+
+TEST(Format, RFC1123Format) { // locale specific
+ time_zone tz;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+
+ auto tp = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+ EXPECT_EQ("Tue, 28 Jun 1977 09:08:07 -0700", format(RFC1123_full, tp, tz));
+ EXPECT_EQ("28 Jun 1977 09:08:07 -0700", format(RFC1123_no_wday, tp, tz));
+}
+
+TEST(Format, Week) {
+ const time_zone utc = utc_time_zone();
+
+ auto tp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
+ EXPECT_EQ("2017-01-7", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2017-00-0", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
+ EXPECT_EQ("2017-53-7", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2017-52-0", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
+ EXPECT_EQ("2018-00-1", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2018-01-1", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
+ EXPECT_EQ("2018-52-1", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2018-53-1", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
+ EXPECT_EQ("2019-00-2", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2019-00-2", format("%Y-%W-%w", tp, utc));
+
+ tp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+ EXPECT_EQ("2019-52-2", format("%Y-%U-%u", tp, utc));
+ EXPECT_EQ("2019-52-2", format("%Y-%W-%w", tp, utc));
+}
+
+//
+// Testing parse()
+//
+
+TEST(Parse, TimePointResolution) {
+ const char kFmt[] = "%H:%M:%E*S";
+ const time_zone utc = utc_time_zone();
+
+ time_point<chrono::nanoseconds> tp_ns;
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_ns));
+ EXPECT_EQ("03:04:05.123456789", format(kFmt, tp_ns, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ns));
+ EXPECT_EQ("03:04:05.123456", format(kFmt, tp_ns, utc));
+
+ time_point<chrono::microseconds> tp_us;
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456789", utc, &tp_us));
+ EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_us));
+ EXPECT_EQ("03:04:05.123456", format(kFmt, tp_us, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_us));
+ EXPECT_EQ("03:04:05.123", format(kFmt, tp_us, utc));
+
+ time_point<chrono::milliseconds> tp_ms;
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123456", utc, &tp_ms));
+ EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_ms));
+ EXPECT_EQ("03:04:05.123", format(kFmt, tp_ms, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_ms));
+ EXPECT_EQ("03:04:05", format(kFmt, tp_ms, utc));
+
+ time_point<chrono::seconds> tp_s;
+ EXPECT_TRUE(parse(kFmt, "03:04:05.123", utc, &tp_s));
+ EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc));
+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_s));
+ EXPECT_EQ("03:04:05", format(kFmt, tp_s, utc));
+
+ time_point<chrono::minutes> tp_m;
+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_m));
+ EXPECT_EQ("03:04:00", format(kFmt, tp_m, utc));
+
+ time_point<chrono::hours> tp_h;
+ EXPECT_TRUE(parse(kFmt, "03:04:05", utc, &tp_h));
+ EXPECT_EQ("03:00:00", format(kFmt, tp_h, utc));
+}
+
+TEST(Parse, TimePointExtendedResolution) {
+ const char kFmt[] = "%H:%M:%E*S";
+ const time_zone utc = utc_time_zone();
+
+ time_point<cctz::seconds> tp;
+ detail::femtoseconds fs;
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.123456789012345", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.123456789012345", detail::format(kFmt, tp, fs, utc));
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.012345678901234", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.012345678901234", detail::format(kFmt, tp, fs, utc));
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.001234567890123", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.001234567890123", detail::format(kFmt, tp, fs, utc));
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000123", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.000000000000123", detail::format(kFmt, tp, fs, utc));
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000012", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.000000000000012", detail::format(kFmt, tp, fs, utc));
+ EXPECT_TRUE(detail::parse(kFmt, "12:34:56.000000000000001", utc, &tp, &fs));
+ EXPECT_EQ("12:34:56.000000000000001", detail::format(kFmt, tp, fs, utc));
+}
+
+TEST(Parse, Basics) {
+ time_zone tz = utc_time_zone();
+ time_point<chrono::nanoseconds> tp =
+ chrono::system_clock::from_time_t(1234567890);
+
+ // Simple edge cases.
+ EXPECT_TRUE(parse("", "", tz, &tp));
+ EXPECT_EQ(chrono::system_clock::from_time_t(0), tp); // everything defaulted
+ EXPECT_TRUE(parse(" ", " ", tz, &tp));
+ EXPECT_TRUE(parse(" ", " ", tz, &tp));
+ EXPECT_TRUE(parse("x", "x", tz, &tp));
+ EXPECT_TRUE(parse("xxx", "xxx", tz, &tp));
+
+ EXPECT_TRUE(
+ parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 -0800", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 29, 3, 8, 9, 0, false, "UTC");
+}
+
+TEST(Parse, WithTimeZone) {
+ time_zone tz;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+ time_point<chrono::nanoseconds> tp;
+
+ // We can parse a string without a UTC offset if we supply a timezone.
+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 19, 8, 9, -7 * 60 * 60, true, "PDT");
+
+ // But the timezone is ignored when a UTC offset is present.
+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S %z", "2013-06-28 19:08:09 +0800",
+ utc_time_zone(), &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 19 - 8 - 7, 8, 9, -7 * 60 * 60, true, "PDT");
+
+ // Check a skipped time (a Spring DST transition). parse() uses the
+ // pre-transition offset.
+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-03-13 02:15:00", tz, &tp));
+ ExpectTime(tp, tz, 2011, 3, 13, 3, 15, 0, -7 * 60 * 60, true, "PDT");
+
+ // Check a repeated time (a Fall DST transition). parse() uses the
+ // pre-transition offset.
+ EXPECT_TRUE(parse("%Y-%m-%d %H:%M:%S", "2011-11-06 01:15:00", tz, &tp));
+ ExpectTime(tp, tz, 2011, 11, 6, 1, 15, 0, -7 * 60 * 60, true, "PDT");
+}
+
+TEST(Parse, LeapSecond) {
+ time_zone tz;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &tz));
+ time_point<chrono::nanoseconds> tp;
+
+ // ":59" -> ":59"
+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59-08:00", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT");
+
+ // ":59.5" -> ":59.5"
+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:59.5-08:00", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 8, 8, 59, -7 * 60 * 60, true, "PDT");
+
+ // ":60" -> ":00"
+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60-08:00", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT");
+
+ // ":60.5" -> ":00.0"
+ EXPECT_TRUE(parse(RFC3339_full, "2013-06-28T07:08:60.5-08:00", tz, &tp));
+ ExpectTime(tp, tz, 2013, 6, 28, 8, 9, 0, -7 * 60 * 60, true, "PDT");
+
+ // ":61" -> error
+ EXPECT_FALSE(parse(RFC3339_full, "2013-06-28T07:08:61-08:00", tz, &tp));
+}
+
+TEST(Parse, ErrorCases) {
+ const time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+
+ // Illegal trailing data.
+ EXPECT_FALSE(parse("%S", "123", tz, &tp));
+
+ // Can't parse an illegal format specifier.
+ EXPECT_FALSE(parse("%Q", "x", tz, &tp));
+
+ // Fails because of trailing, unparsed data "blah".
+ EXPECT_FALSE(parse("%m-%d", "2-3 blah", tz, &tp));
+
+ // Trailing whitespace is allowed.
+ EXPECT_TRUE(parse("%m-%d", "2-3 ", tz, &tp));
+ EXPECT_EQ(2, convert(tp, utc_time_zone()).month());
+ EXPECT_EQ(3, convert(tp, utc_time_zone()).day());
+
+ // Feb 31 requires normalization.
+ EXPECT_FALSE(parse("%m-%d", "2-31", tz, &tp));
+
+ // Check that we cannot have spaces in UTC offsets.
+ EXPECT_TRUE(parse("%z", "-0203", tz, &tp));
+ EXPECT_FALSE(parse("%z", "- 2 3", tz, &tp));
+ EXPECT_TRUE(parse("%Ez", "-02:03", tz, &tp));
+ EXPECT_FALSE(parse("%Ez", "- 2: 3", tz, &tp));
+
+ // Check that we reject other malformed UTC offsets.
+ EXPECT_FALSE(parse("%Ez", "+-08:00", tz, &tp));
+ EXPECT_FALSE(parse("%Ez", "-+08:00", tz, &tp));
+
+ // Check that we do not accept "-0" in fields that allow zero.
+ EXPECT_FALSE(parse("%Y", "-0", tz, &tp));
+ EXPECT_FALSE(parse("%E4Y", "-0", tz, &tp));
+ EXPECT_FALSE(parse("%H", "-0", tz, &tp));
+ EXPECT_FALSE(parse("%M", "-0", tz, &tp));
+ EXPECT_FALSE(parse("%S", "-0", tz, &tp));
+ EXPECT_FALSE(parse("%z", "+-000", tz, &tp));
+ EXPECT_FALSE(parse("%Ez", "+-0:00", tz, &tp));
+ EXPECT_FALSE(parse("%z", "-00-0", tz, &tp));
+ EXPECT_FALSE(parse("%Ez", "-00:-0", tz, &tp));
+}
+
+TEST(Parse, PosixConversions) {
+ time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+ const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+
+ tp = reset;
+ EXPECT_TRUE(parse("%d", "15", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).day());
+
+ // %e is an extension, but is supported internally.
+ tp = reset;
+ EXPECT_TRUE(parse("%e", "15", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d
+
+ tp = reset;
+ EXPECT_TRUE(parse("%H", "17", tz, &tp));
+ EXPECT_EQ(17, convert(tp, tz).hour());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%I", "5", tz, &tp));
+ EXPECT_EQ(5, convert(tp, tz).hour());
+
+ // %j is parsed but ignored.
+ EXPECT_TRUE(parse("%j", "32", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%m", "11", tz, &tp));
+ EXPECT_EQ(11, convert(tp, tz).month());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%M", "33", tz, &tp));
+ EXPECT_EQ(33, convert(tp, tz).minute());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%S", "55", tz, &tp));
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+ // %U is parsed but ignored.
+ EXPECT_TRUE(parse("%U", "15", tz, &tp));
+
+ // %w is parsed but ignored.
+ EXPECT_TRUE(parse("%w", "2", tz, &tp));
+
+ // %W is parsed but ignored.
+ EXPECT_TRUE(parse("%W", "22", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%y", "04", tz, &tp));
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Y", "2004", tz, &tp));
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ EXPECT_TRUE(parse("%%", "%", tz, &tp));
+
+#if defined(__linux__)
+ // SU/C99/TZ extensions
+
+ // Because we handle each (non-internal) specifier in a separate call
+ // to strptime(), there is no way to group %C and %y together. So we
+ // just skip the %C/%y case.
+#if 0
+ tp = reset;
+ EXPECT_TRUE(parse("%C %y", "20 04", tz, &tp));
+ EXPECT_EQ(2004, convert(tp, tz).year());
+#endif
+
+ tp = reset;
+ EXPECT_TRUE(parse("%D", "02/03/04", tz, &tp));
+ EXPECT_EQ(2, convert(tp, tz).month());
+ EXPECT_EQ(3, convert(tp, tz).day());
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ EXPECT_TRUE(parse("%n", "\n", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%R", "03:44", tz, &tp));
+ EXPECT_EQ(3, convert(tp, tz).hour());
+ EXPECT_EQ(44, convert(tp, tz).minute());
+
+ EXPECT_TRUE(parse("%t", "\t\v\f\n\r ", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%T", "03:44:55", tz, &tp));
+ EXPECT_EQ(3, convert(tp, tz).hour());
+ EXPECT_EQ(44, convert(tp, tz).minute());
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%s", "1234567890", tz, &tp));
+ EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
+
+ // %s conversion, like %z/%Ez, pays no heed to the optional zone.
+ time_zone lax;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax));
+ tp = reset;
+ EXPECT_TRUE(parse("%s", "1234567890", lax, &tp));
+ EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
+
+ // This is most important when the time has the same YMDhms
+ // breakdown in the zone as some other time. For example, ...
+ // 1414917000 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PDT)
+ // 1414920600 in US/Pacific -> Sun Nov 2 01:30:00 2014 (PST)
+ tp = reset;
+ EXPECT_TRUE(parse("%s", "1414917000", lax, &tp));
+ EXPECT_EQ(chrono::system_clock::from_time_t(1414917000), tp);
+ tp = reset;
+ EXPECT_TRUE(parse("%s", "1414920600", lax, &tp));
+ EXPECT_EQ(chrono::system_clock::from_time_t(1414920600), tp);
+#endif
+}
+
+TEST(Parse, LocaleSpecific) {
+ time_zone tz = utc_time_zone();
+ auto tp = chrono::system_clock::from_time_t(0);
+ const auto reset = convert(civil_second(1977, 6, 28, 9, 8, 7), tz);
+
+ // %a is parsed but ignored.
+ EXPECT_TRUE(parse("%a", "Mon", tz, &tp));
+
+ // %A is parsed but ignored.
+ EXPECT_TRUE(parse("%A", "Monday", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%b", "Feb", tz, &tp));
+ EXPECT_EQ(2, convert(tp, tz).month());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%B", "February", tz, &tp));
+ EXPECT_EQ(2, convert(tp, tz).month());
+
+ // %p is parsed but ignored if it's alone. But it's used with %I.
+ EXPECT_TRUE(parse("%p", "AM", tz, &tp));
+ tp = reset;
+ EXPECT_TRUE(parse("%I %p", "5 PM", tz, &tp));
+ EXPECT_EQ(17, convert(tp, tz).hour());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%x", "02/03/04", tz, &tp));
+ if (convert(tp, tz).month() == 2) {
+ EXPECT_EQ(3, convert(tp, tz).day());
+ } else {
+ EXPECT_EQ(2, convert(tp, tz).day());
+ EXPECT_EQ(3, convert(tp, tz).month());
+ }
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%X", "15:44:55", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).hour());
+ EXPECT_EQ(44, convert(tp, tz).minute());
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+#if defined(__linux__)
+ // SU/C99/TZ extensions
+
+ tp = reset;
+ EXPECT_TRUE(parse("%h", "Feb", tz, &tp));
+ EXPECT_EQ(2, convert(tp, tz).month()); // Equivalent to %b
+
+ tp = reset;
+ EXPECT_TRUE(parse("%l %p", "5 PM", tz, &tp));
+ EXPECT_EQ(17, convert(tp, tz).hour());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%r", "03:44:55 PM", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).hour());
+ EXPECT_EQ(44, convert(tp, tz).minute());
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Ec", "Tue Nov 19 05:06:07 2013", tz, &tp));
+ EXPECT_EQ(convert(civil_second(2013, 11, 19, 5, 6, 7), tz), tp);
+
+ // Modified conversion specifiers %E_
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Ex", "02/03/04", tz, &tp));
+ EXPECT_EQ(2, convert(tp, tz).month());
+ EXPECT_EQ(3, convert(tp, tz).day());
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%EX", "15:44:55", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).hour());
+ EXPECT_EQ(44, convert(tp, tz).minute());
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+ // %Ey, the year offset from %EC, doesn't really make sense alone as there
+ // is no way to represent it in tm_year (%EC is not simply the century).
+ // Yet, because we handle each (non-internal) specifier in a separate call
+ // to strptime(), there is no way to group %EC and %Ey either. So we just
+ // skip the %EC and %Ey cases.
+
+ tp = reset;
+ EXPECT_TRUE(parse("%EY", "2004", tz, &tp));
+ EXPECT_EQ(2004, convert(tp, tz).year());
+
+ // Modified conversion specifiers %O_
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Od", "15", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).day());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Oe", "15", tz, &tp));
+ EXPECT_EQ(15, convert(tp, tz).day()); // Equivalent to %d
+
+ tp = reset;
+ EXPECT_TRUE(parse("%OH", "17", tz, &tp));
+ EXPECT_EQ(17, convert(tp, tz).hour());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%OI", "5", tz, &tp));
+ EXPECT_EQ(5, convert(tp, tz).hour());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Om", "11", tz, &tp));
+ EXPECT_EQ(11, convert(tp, tz).month());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%OM", "33", tz, &tp));
+ EXPECT_EQ(33, convert(tp, tz).minute());
+
+ tp = reset;
+ EXPECT_TRUE(parse("%OS", "55", tz, &tp));
+ EXPECT_EQ(55, convert(tp, tz).second());
+
+ // %OU is parsed but ignored.
+ EXPECT_TRUE(parse("%OU", "15", tz, &tp));
+
+ // %Ow is parsed but ignored.
+ EXPECT_TRUE(parse("%Ow", "2", tz, &tp));
+
+ // %OW is parsed but ignored.
+ EXPECT_TRUE(parse("%OW", "22", tz, &tp));
+
+ tp = reset;
+ EXPECT_TRUE(parse("%Oy", "04", tz, &tp));
+ EXPECT_EQ(2004, convert(tp, tz).year());
+#endif
+}
+
+TEST(Parse, ExtendedSeconds) {
+ const time_zone tz = utc_time_zone();
+ const time_point<chrono::nanoseconds> unix_epoch =
+ chrono::system_clock::from_time_t(0);
+
+ // All %E<prec>S cases are treated the same as %E*S on input.
+ auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", "10", "11", "12", "13", "14", "15"};
+ for (const std::string& prec : precisions) {
+ const std::string fmt = "%E" + prec + "S";
+ SCOPED_TRACE(fmt);
+ time_point<chrono::nanoseconds> tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "5", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.0", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.00", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.6", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.60", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.600", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.67", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.670", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(670), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "05.678", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::seconds(5) + chrono::milliseconds(678), tp);
+ }
+
+ // Here is a "%E*S" case we got wrong for a while. The fractional
+ // part of the first instant is less than 2^31 and was correctly
+ // parsed, while the second (and any subsecond field >=2^31) failed.
+ time_point<chrono::nanoseconds> tp = unix_epoch;
+ EXPECT_TRUE(parse("%E*S", "0.2147483647", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse("%E*S", "0.2147483648", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+
+ // We should also be able to specify long strings of digits far
+ // beyond the current resolution and have them convert the same way.
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(
+ "%E*S", "0.214748364801234567890123456789012345678901234567890123456789",
+ tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+}
+
+TEST(Parse, ExtendedSecondsScan) {
+ const time_zone tz = utc_time_zone();
+ time_point<chrono::nanoseconds> tp;
+ for (int ms = 0; ms < 1000; ms += 111) {
+ for (int us = 0; us < 1000; us += 27) {
+ const int micros = ms * 1000 + us;
+ for (int ns = 0; ns < 1000; ns += 9) {
+ const auto expected = chrono::system_clock::from_time_t(0) +
+ chrono::nanoseconds(micros * 1000 + ns);
+ std::ostringstream oss;
+ oss << "0." << std::setfill('0') << std::setw(3);
+ oss << ms << std::setw(3) << us << std::setw(3) << ns;
+ const std::string input = oss.str();
+ EXPECT_TRUE(parse("%E*S", input, tz, &tp));
+ EXPECT_EQ(expected, tp) << input;
+ }
+ }
+ }
+}
+
+TEST(Parse, ExtendedSubeconds) {
+ const time_zone tz = utc_time_zone();
+ const time_point<chrono::nanoseconds> unix_epoch =
+ chrono::system_clock::from_time_t(0);
+
+ // All %E<prec>f cases are treated the same as %E*f on input.
+ auto precisions = {"*", "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", "10", "11", "12", "13", "14", "15"};
+ for (const std::string& prec : precisions) {
+ const std::string fmt = "%E" + prec + "f";
+ SCOPED_TRACE(fmt);
+ time_point<chrono::nanoseconds> tp = unix_epoch - chrono::seconds(1);
+ EXPECT_TRUE(parse(fmt, "", tz, &tp));
+ EXPECT_EQ(unix_epoch, tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "6", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "60", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "600", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(600), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "67", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "670", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(670), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "678", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::milliseconds(678), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(fmt, "6789", tz, &tp));
+ EXPECT_EQ(
+ unix_epoch + chrono::milliseconds(678) + chrono::microseconds(900), tp);
+ }
+
+ // Here is a "%E*f" case we got wrong for a while. The fractional
+ // part of the first instant is less than 2^31 and was correctly
+ // parsed, while the second (and any subsecond field >=2^31) failed.
+ time_point<chrono::nanoseconds> tp = unix_epoch;
+ EXPECT_TRUE(parse("%E*f", "2147483647", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+ tp = unix_epoch;
+ EXPECT_TRUE(parse("%E*f", "2147483648", tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+
+ // We should also be able to specify long strings of digits far
+ // beyond the current resolution and have them convert the same way.
+ tp = unix_epoch;
+ EXPECT_TRUE(parse(
+ "%E*f", "214748364801234567890123456789012345678901234567890123456789",
+ tz, &tp));
+ EXPECT_EQ(unix_epoch + chrono::nanoseconds(214748364), tp);
+}
+
+TEST(Parse, ExtendedSubecondsScan) {
+ time_point<chrono::nanoseconds> tp;
+ const time_zone tz = utc_time_zone();
+ for (int ms = 0; ms < 1000; ms += 111) {
+ for (int us = 0; us < 1000; us += 27) {
+ const int micros = ms * 1000 + us;
+ for (int ns = 0; ns < 1000; ns += 9) {
+ std::ostringstream oss;
+ oss << std::setfill('0') << std::setw(3) << ms;
+ oss << std::setw(3) << us << std::setw(3) << ns;
+ const std::string nanos = oss.str();
+ const auto expected = chrono::system_clock::from_time_t(0) +
+ chrono::nanoseconds(micros * 1000 + ns);
+ for (int ps = 0; ps < 1000; ps += 250) {
+ std::ostringstream ps_oss;
+ oss << std::setfill('0') << std::setw(3) << ps;
+ const std::string input = nanos + ps_oss.str() + "999";
+ EXPECT_TRUE(parse("%E*f", input, tz, &tp));
+ EXPECT_EQ(expected + chrono::nanoseconds(ps) / 1000, tp) << input;
+ }
+ }
+ }
+ }
+}
+
+TEST(Parse, ExtendedOffset) {
+ const time_zone utc = utc_time_zone();
+ time_point<cctz::seconds> tp;
+
+ EXPECT_TRUE(parse("%Ez", "+00:00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse("%Ez", "-12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse("%Ez", "+12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse("%Ez", "-12:3", utc, &tp));
+
+ for (auto fmt : {"%Ez", "%z"}) {
+ EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
+ }
+}
+
+TEST(Parse, ExtendedSecondOffset) {
+ const time_zone utc = utc_time_zone();
+ time_point<cctz::seconds> tp;
+
+ for (auto fmt : {"%Ez", "%E*z", "%:z", "%::z", "%:::z"}) {
+ EXPECT_TRUE(parse(fmt, "+00:00:00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12:34:56", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12:34:56", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12:34:5", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+000000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-123456", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 56), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+123456", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 25, 4), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12345", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+00:00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12:34", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-12:3", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+0000", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 34, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+1234", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 11, 26, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-123", utc, &tp));
+
+ EXPECT_TRUE(parse(fmt, "+00", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "-12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1970, 1, 1, 12, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(fmt, "+12", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1969, 12, 31, 12, 0, 0), utc), tp);
+ EXPECT_FALSE(parse(fmt, "-1", utc, &tp));
+ }
+}
+
+TEST(Parse, ExtendedYears) {
+ const time_zone utc = utc_time_zone();
+ const char e4y_fmt[] = "%E4Y%m%d"; // no separators
+ time_point<cctz::seconds> tp;
+
+ // %E4Y consumes exactly four chars, including any sign.
+ EXPECT_TRUE(parse(e4y_fmt, "-9991127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(-999, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "-0991127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(-99, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "-0091127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(-9, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "-0011127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(-1, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "00001127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(0, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "00011127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(1, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "00091127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(9, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "00991127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(99, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "09991127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(999, 11, 27, 0, 0, 0), utc), tp);
+ EXPECT_TRUE(parse(e4y_fmt, "99991127", utc, &tp));
+ EXPECT_EQ(convert(civil_second(9999, 11, 27, 0, 0, 0), utc), tp);
+
+ // When the year is outside [-999:9999], the parse fails.
+ EXPECT_FALSE(parse(e4y_fmt, "-10001127", utc, &tp));
+ EXPECT_FALSE(parse(e4y_fmt, "100001127", utc, &tp));
+}
+
+TEST(Parse, RFC3339Format) {
+ const time_zone tz = utc_time_zone();
+ time_point<chrono::nanoseconds> tp;
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00+00:00", tz, &tp));
+ ExpectTime(tp, tz, 2014, 2, 12, 20, 21, 0, 0, false, "UTC");
+
+ // Check that %ET also accepts "t".
+ time_point<chrono::nanoseconds> tp2;
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12t20:21:00+00:00", tz, &tp2));
+ EXPECT_EQ(tp, tp2);
+
+ // Check that %Ez also accepts "Z" as a synonym for "+00:00".
+ time_point<chrono::nanoseconds> tp3;
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00Z", tz, &tp3));
+ EXPECT_EQ(tp, tp3);
+
+ // Check that %Ez also accepts "z" as a synonym for "+00:00".
+ time_point<chrono::nanoseconds> tp4;
+ EXPECT_TRUE(parse(RFC3339_sec, "2014-02-12T20:21:00z", tz, &tp4));
+ EXPECT_EQ(tp, tp4);
+}
+
+TEST(Parse, Week) {
+ const time_zone utc = utc_time_zone();
+ time_point<cctz::seconds> tp;
+
+ auto exp = convert(civil_second(2017, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2017-01-7", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2017-00-0", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2017, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2017-53-7", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2017-52-0", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2018, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2018-00-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2018-01-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2018, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2018-52-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2018-53-1", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2019, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2019-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2019-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2019-52-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2019-52-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+}
+
+TEST(Parse, WeekYearShift) {
+ // %U/%W conversions with week values in {0, 52, 53} can slip
+ // into the previous/following calendar years.
+ const time_zone utc = utc_time_zone();
+ time_point<cctz::seconds> tp;
+
+ auto exp = convert(civil_second(2019, 12, 31, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2020-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2020-00-2", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ exp = convert(civil_second(2021, 1, 1, 0, 0, 0), utc);
+ EXPECT_TRUE(parse("%Y-%U-%u", "2020-52-5", utc, &tp));
+ EXPECT_EQ(exp, tp);
+ EXPECT_TRUE(parse("%Y-%W-%w", "2020-52-5", utc, &tp));
+ EXPECT_EQ(exp, tp);
+
+ // Slipping into the previous/following calendar years should fail when
+ // we're already at the extremes.
+ EXPECT_FALSE(parse("%Y-%U-%u", "-9223372036854775808-0-7", utc, &tp));
+ EXPECT_FALSE(parse("%Y-%U-%u", "9223372036854775807-53-7", utc, &tp));
+}
+
+TEST(Parse, MaxRange) {
+ const time_zone utc = utc_time_zone();
+ time_point<cctz::seconds> tp;
+
+ // tests the upper limit using +00:00 offset
+ EXPECT_TRUE(
+ parse(RFC3339_sec, "292277026596-12-04T15:30:07+00:00", utc, &tp));
+ EXPECT_EQ(tp, time_point<cctz::seconds>::max());
+ EXPECT_FALSE(
+ parse(RFC3339_sec, "292277026596-12-04T15:30:08+00:00", utc, &tp));
+
+ // tests the upper limit using -01:00 offset
+ EXPECT_TRUE(
+ parse(RFC3339_sec, "292277026596-12-04T14:30:07-01:00", utc, &tp));
+ EXPECT_EQ(tp, time_point<cctz::seconds>::max());
+ EXPECT_FALSE(
+ parse(RFC3339_sec, "292277026596-12-04T15:30:07-01:00", utc, &tp));
+
+ // tests the lower limit using +00:00 offset
+ EXPECT_TRUE(
+ parse(RFC3339_sec, "-292277022657-01-27T08:29:52+00:00", utc, &tp));
+ EXPECT_EQ(tp, time_point<cctz::seconds>::min());
+ EXPECT_FALSE(
+ parse(RFC3339_sec, "-292277022657-01-27T08:29:51+00:00", utc, &tp));
+
+ // tests the lower limit using +01:00 offset
+ EXPECT_TRUE(
+ parse(RFC3339_sec, "-292277022657-01-27T09:29:52+01:00", utc, &tp));
+ EXPECT_EQ(tp, time_point<cctz::seconds>::min());
+ EXPECT_FALSE(
+ parse(RFC3339_sec, "-292277022657-01-27T08:29:51+01:00", utc, &tp));
+
+ // tests max/min civil-second overflow
+ EXPECT_FALSE(parse(RFC3339_sec, "9223372036854775807-12-31T23:59:59-00:01",
+ utc, &tp));
+ EXPECT_FALSE(parse(RFC3339_sec, "-9223372036854775808-01-01T00:00:00+00:01",
+ utc, &tp));
+
+ // TODO: Add tests that parsing times with fractional seconds overflow
+ // appropriately. This can't be done until cctz::parse() properly detects
+ // overflow when combining the chrono seconds and femto.
+}
+
+//
+// Roundtrip test for format()/parse().
+//
+
+TEST(FormatParse, RoundTrip) {
+ time_zone lax;
+ EXPECT_TRUE(load_time_zone("America/Los_Angeles", &lax));
+ const auto in = convert(civil_second(1977, 6, 28, 9, 8, 7), lax);
+ const auto subseconds = chrono::nanoseconds(654321);
+
+ // RFC3339, which renders subseconds.
+ {
+ time_point<chrono::nanoseconds> out;
+ const std::string s = format(RFC3339_full, in + subseconds, lax);
+ EXPECT_TRUE(parse(RFC3339_full, s, lax, &out)) << s;
+ EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez
+ }
+
+ // RFC1123, which only does whole seconds.
+ {
+ time_point<chrono::nanoseconds> out;
+ const std::string s = format(RFC1123_full, in, lax);
+ EXPECT_TRUE(parse(RFC1123_full, s, lax, &out)) << s;
+ EXPECT_EQ(in, out); // RFC1123_full includes %z
+ }
+
+#if defined(_WIN32) || defined(_WIN64)
+ // Initial investigations indicate the %c does not roundtrip on Windows.
+ // TODO: Figure out what is going on here (perhaps a locale problem).
+#else
+ // Even though we don't know what %c will produce, it should roundtrip,
+ // but only in the 0-offset timezone.
+ {
+ time_point<chrono::nanoseconds> out;
+ time_zone utc = utc_time_zone();
+ const std::string s = format("%c", in, utc);
+ EXPECT_TRUE(parse("%c", s, utc, &out)) << s;
+ EXPECT_EQ(in, out);
+ }
+#endif
+}
+
+TEST(FormatParse, RoundTripDistantFuture) {
+ const time_zone utc = utc_time_zone();
+ const time_point<cctz::seconds> in = time_point<cctz::seconds>::max();
+ const std::string s = format(RFC3339_full, in, utc);
+ time_point<cctz::seconds> out;
+ EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
+ EXPECT_EQ(in, out);
+}
+
+TEST(FormatParse, RoundTripDistantPast) {
+ const time_zone utc = utc_time_zone();
+ const time_point<cctz::seconds> in = time_point<cctz::seconds>::min();
+ const std::string s = format(RFC3339_full, in, utc);
+ time_point<cctz::seconds> out;
+ EXPECT_TRUE(parse(RFC3339_full, s, utc, &out)) << s;
+ EXPECT_EQ(in, out);
+}
+
+} // namespace cctz
diff --git a/contrib/libs/cctz/test/time_zone_lookup_test.cc b/contrib/libs/cctz/test/time_zone_lookup_test.cc
index bf816ac6e9..991d7af1c8 100644
--- a/contrib/libs/cctz/test/time_zone_lookup_test.cc
+++ b/contrib/libs/cctz/test/time_zone_lookup_test.cc
@@ -4,7 +4,7 @@
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
-// https://www.apache.org/licenses/LICENSE-2.0
+// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
@@ -12,21 +12,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "cctz/time_zone.h"
+#include "cctz/time_zone.h"
#include <chrono>
#include <cstddef>
-#include <cstdlib>
+#include <cstdlib>
#include <future>
-#include <limits>
+#include <limits>
#include <string>
#include <thread>
#include <vector>
-#include "cctz/civil_time.h"
-#include "gtest/gtest.h"
+#include "cctz/civil_time.h"
+#include "gtest/gtest.h"
-namespace chrono = std::chrono;
+namespace chrono = std::chrono;
namespace cctz {
@@ -209,7 +209,7 @@ const char* const kTimeZoneNames[] = {
"America/North_Dakota/Beulah",
"America/North_Dakota/Center",
"America/North_Dakota/New_Salem",
- "America/Nuuk",
+ "America/Nuuk",
"America/Ojinaga",
"America/Panama",
"America/Pangnirtung",
@@ -336,7 +336,7 @@ const char* const kTimeZoneNames[] = {
"Asia/Pontianak",
"Asia/Pyongyang",
"Asia/Qatar",
- "Asia/Qostanay",
+ "Asia/Qostanay",
"Asia/Qyzylorda",
"Asia/Rangoon",
"Asia/Riyadh",
@@ -653,17 +653,17 @@ time_zone LoadZone(const std::string& name) {
/* EXPECT_STREQ(zone, al.abbr); */ \
} while (0)
-// These tests sometimes run on platforms that have zoneinfo data so old
-// that the transition we are attempting to check does not exist, most
-// notably Android emulators. Fortunately, AndroidZoneInfoSource supports
-// time_zone::version() so, in cases where we've learned that it matters,
-// we can make the check conditionally.
-int VersionCmp(time_zone tz, const std::string& target) {
- std::string version = tz.version();
- if (version.empty() && !target.empty()) return 1; // unknown > known
- return version.compare(target);
-}
-
+// These tests sometimes run on platforms that have zoneinfo data so old
+// that the transition we are attempting to check does not exist, most
+// notably Android emulators. Fortunately, AndroidZoneInfoSource supports
+// time_zone::version() so, in cases where we've learned that it matters,
+// we can make the check conditionally.
+int VersionCmp(time_zone tz, const std::string& target) {
+ std::string version = tz.version();
+ if (version.empty() && !target.empty()) return 1; // unknown > known
+ return version.compare(target);
+}
+
} // namespace
TEST(TimeZones, LoadZonesConcurrently) {
@@ -684,7 +684,7 @@ TEST(TimeZones, LoadZonesConcurrently) {
}
};
- const std::size_t n_threads = 128;
+ const std::size_t n_threads = 128;
std::vector<std::thread> threads;
std::vector<std::set<std::string>> thread_failures(n_threads);
for (std::size_t i = 0; i != n_threads; ++i) {
@@ -699,19 +699,19 @@ TEST(TimeZones, LoadZonesConcurrently) {
// Allow a small number of failures to account for skew between
// the contents of kTimeZoneNames and the zoneinfo data source.
-#if defined(__ANDROID__)
- // Cater to the possibility of using an even older zoneinfo data
- // source when running on Android, where it is difficult to override
- // the bionic tzdata provided by the test environment.
- const std::size_t max_failures = 20;
-#else
+#if defined(__ANDROID__)
+ // Cater to the possibility of using an even older zoneinfo data
+ // source when running on Android, where it is difficult to override
+ // the bionic tzdata provided by the test environment.
+ const std::size_t max_failures = 20;
+#else
const std::size_t max_failures = 3;
-#endif
+#endif
std::set<std::string> failures;
for (const auto& thread_failure : thread_failures) {
failures.insert(thread_failure.begin(), thread_failure.end());
}
- EXPECT_LE(failures.size(), max_failures) << testing::PrintToString(failures);
+ EXPECT_LE(failures.size(), max_failures) << testing::PrintToString(failures);
}
TEST(TimeZone, NamedTimeZones) {
@@ -721,13 +721,13 @@ TEST(TimeZone, NamedTimeZones) {
EXPECT_EQ("America/New_York", nyc.name());
const time_zone syd = LoadZone("Australia/Sydney");
EXPECT_EQ("Australia/Sydney", syd.name());
- const time_zone fixed0 = fixed_time_zone(cctz::seconds::zero());
+ const time_zone fixed0 = fixed_time_zone(cctz::seconds::zero());
EXPECT_EQ("UTC", fixed0.name());
- const time_zone fixed_pos = fixed_time_zone(
- chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
+ const time_zone fixed_pos = fixed_time_zone(
+ chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
EXPECT_EQ("Fixed/UTC+03:25:45", fixed_pos.name());
- const time_zone fixed_neg = fixed_time_zone(
- -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56)));
+ const time_zone fixed_neg = fixed_time_zone(
+ -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56)));
EXPECT_EQ("Fixed/UTC-12:34:56", fixed_neg.name());
}
@@ -737,34 +737,34 @@ TEST(TimeZone, Failures) {
tz = LoadZone("America/Los_Angeles");
EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &tz));
- EXPECT_EQ(chrono::system_clock::from_time_t(0),
+ EXPECT_EQ(chrono::system_clock::from_time_t(0),
convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC
// Ensures that the load still fails on a subsequent attempt.
tz = LoadZone("America/Los_Angeles");
EXPECT_FALSE(load_time_zone("Invalid/TimeZone", &tz));
- EXPECT_EQ(chrono::system_clock::from_time_t(0),
+ EXPECT_EQ(chrono::system_clock::from_time_t(0),
convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC
// Loading an empty string timezone should fail.
tz = LoadZone("America/Los_Angeles");
EXPECT_FALSE(load_time_zone("", &tz));
- EXPECT_EQ(chrono::system_clock::from_time_t(0),
+ EXPECT_EQ(chrono::system_clock::from_time_t(0),
convert(civil_second(1970, 1, 1, 0, 0, 0), tz)); // UTC
}
TEST(TimeZone, Equality) {
- const time_zone a;
- const time_zone b;
+ const time_zone a;
+ const time_zone b;
EXPECT_EQ(a, b);
EXPECT_EQ(a.name(), b.name());
- const time_zone implicit_utc;
+ const time_zone implicit_utc;
const time_zone explicit_utc = utc_time_zone();
EXPECT_EQ(implicit_utc, explicit_utc);
EXPECT_EQ(implicit_utc.name(), explicit_utc.name());
- const time_zone fixed_zero = fixed_time_zone(cctz::seconds::zero());
+ const time_zone fixed_zero = fixed_time_zone(cctz::seconds::zero());
EXPECT_EQ(fixed_zero, LoadZone(fixed_zero.name()));
EXPECT_EQ(fixed_zero, explicit_utc);
@@ -772,25 +772,25 @@ TEST(TimeZone, Equality) {
EXPECT_EQ(fixed_utc, LoadZone(fixed_utc.name()));
EXPECT_EQ(fixed_utc, explicit_utc);
- const time_zone fixed_pos = fixed_time_zone(
- chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
+ const time_zone fixed_pos = fixed_time_zone(
+ chrono::hours(3) + chrono::minutes(25) + chrono::seconds(45));
EXPECT_EQ(fixed_pos, LoadZone(fixed_pos.name()));
EXPECT_NE(fixed_pos, explicit_utc);
- const time_zone fixed_neg = fixed_time_zone(
- -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56)));
+ const time_zone fixed_neg = fixed_time_zone(
+ -(chrono::hours(12) + chrono::minutes(34) + chrono::seconds(56)));
EXPECT_EQ(fixed_neg, LoadZone(fixed_neg.name()));
EXPECT_NE(fixed_neg, explicit_utc);
- const time_zone fixed_lim = fixed_time_zone(chrono::hours(24));
+ const time_zone fixed_lim = fixed_time_zone(chrono::hours(24));
EXPECT_EQ(fixed_lim, LoadZone(fixed_lim.name()));
EXPECT_NE(fixed_lim, explicit_utc);
- const time_zone fixed_ovfl =
- fixed_time_zone(chrono::hours(24) + chrono::seconds(1));
+ const time_zone fixed_ovfl =
+ fixed_time_zone(chrono::hours(24) + chrono::seconds(1));
EXPECT_EQ(fixed_ovfl, LoadZone(fixed_ovfl.name()));
EXPECT_EQ(fixed_ovfl, explicit_utc);
- EXPECT_EQ(fixed_time_zone(chrono::seconds(1)),
- fixed_time_zone(chrono::seconds(1)));
+ EXPECT_EQ(fixed_time_zone(chrono::seconds(1)),
+ fixed_time_zone(chrono::seconds(1)));
const time_zone local = local_time_zone();
EXPECT_EQ(local, LoadZone(local.name()));
@@ -803,113 +803,113 @@ TEST(TimeZone, Equality) {
TEST(StdChronoTimePoint, TimeTAlignment) {
// Ensures that the Unix epoch and the system clock epoch are an integral
// number of seconds apart. This simplifies conversions to/from time_t.
- auto diff = chrono::system_clock::time_point() -
- chrono::system_clock::from_time_t(0);
- EXPECT_EQ(chrono::system_clock::time_point::duration::zero(),
- diff % chrono::seconds(1));
+ auto diff = chrono::system_clock::time_point() -
+ chrono::system_clock::from_time_t(0);
+ EXPECT_EQ(chrono::system_clock::time_point::duration::zero(),
+ diff % chrono::seconds(1));
}
TEST(BreakTime, TimePointResolution) {
const time_zone utc = utc_time_zone();
- const auto t0 = chrono::system_clock::from_time_t(0);
+ const auto t0 = chrono::system_clock::from_time_t(0);
- ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::nanoseconds>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::microseconds>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::milliseconds>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::seconds>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<cctz::seconds>(t0), utc,
+ ExpectTime(chrono::time_point_cast<cctz::seconds>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::minutes>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc,
+ ExpectTime(chrono::time_point_cast<chrono::hours>(t0), utc,
1970, 1, 1, 0, 0, 0, 0, false, "UTC");
}
TEST(BreakTime, LocalTimeInUTC) {
const time_zone tz = utc_time_zone();
- const auto tp = chrono::system_clock::from_time_t(0);
+ const auto tp = chrono::system_clock::from_time_t(0);
ExpectTime(tp, tz, 1970, 1, 1, 0, 0, 0, 0, false, "UTC");
- EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInUTCUnaligned) {
const time_zone tz = utc_time_zone();
- const auto tp =
- chrono::system_clock::from_time_t(0) - chrono::milliseconds(500);
+ const auto tp =
+ chrono::system_clock::from_time_t(0) - chrono::milliseconds(500);
ExpectTime(tp, tz, 1969, 12, 31, 23, 59, 59, 0, false, "UTC");
- EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimePosix) {
// See IEEE Std 1003.1-1988 B.2.3 General Terms, Epoch.
const time_zone tz = utc_time_zone();
- const auto tp = chrono::system_clock::from_time_t(536457599);
+ const auto tp = chrono::system_clock::from_time_t(536457599);
ExpectTime(tp, tz, 1986, 12, 31, 23, 59, 59, 0, false, "UTC");
- EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(TimeZoneImpl, LocalTimeInFixed) {
- const cctz::seconds offset =
- -(chrono::hours(8) + chrono::minutes(33) + chrono::seconds(47));
+ const cctz::seconds offset =
+ -(chrono::hours(8) + chrono::minutes(33) + chrono::seconds(47));
const time_zone tz = fixed_time_zone(offset);
- const auto tp = chrono::system_clock::from_time_t(0);
+ const auto tp = chrono::system_clock::from_time_t(0);
ExpectTime(tp, tz, 1969, 12, 31, 15, 26, 13, offset.count(), false,
- "-083347");
- EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
+ "-083347");
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInNewYork) {
const time_zone tz = LoadZone("America/New_York");
- const auto tp = chrono::system_clock::from_time_t(45);
+ const auto tp = chrono::system_clock::from_time_t(45);
ExpectTime(tp, tz, 1969, 12, 31, 19, 0, 45, -5 * 60 * 60, false, "EST");
- EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::wednesday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInMTV) {
const time_zone tz = LoadZone("America/Los_Angeles");
- const auto tp = chrono::system_clock::from_time_t(1380855729);
+ const auto tp = chrono::system_clock::from_time_t(1380855729);
ExpectTime(tp, tz, 2013, 10, 3, 20, 2, 9, -7 * 60 * 60, true, "PDT");
- EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
}
TEST(BreakTime, LocalTimeInSydney) {
const time_zone tz = LoadZone("Australia/Sydney");
- const auto tp = chrono::system_clock::from_time_t(90);
+ const auto tp = chrono::system_clock::from_time_t(90);
ExpectTime(tp, tz, 1970, 1, 1, 10, 1, 30, 10 * 60 * 60, false, "AEST");
- EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::thursday, get_weekday(convert(tp, tz)));
}
TEST(MakeTime, TimePointResolution) {
const time_zone utc = utc_time_zone();
- const time_point<chrono::nanoseconds> tp_ns =
+ const time_point<chrono::nanoseconds> tp_ns =
convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
EXPECT_EQ("04:05", format("%M:%E*S", tp_ns, utc));
- const time_point<chrono::microseconds> tp_us =
+ const time_point<chrono::microseconds> tp_us =
convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
EXPECT_EQ("04:05", format("%M:%E*S", tp_us, utc));
- const time_point<chrono::milliseconds> tp_ms =
+ const time_point<chrono::milliseconds> tp_ms =
convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
EXPECT_EQ("04:05", format("%M:%E*S", tp_ms, utc));
- const time_point<chrono::seconds> tp_s =
+ const time_point<chrono::seconds> tp_s =
convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
EXPECT_EQ("04:05", format("%M:%E*S", tp_s, utc));
- const time_point<cctz::seconds> tp_s64 =
+ const time_point<cctz::seconds> tp_s64 =
convert(civil_second(2015, 1, 2, 3, 4, 5), utc);
EXPECT_EQ("04:05", format("%M:%E*S", tp_s64, utc));
- // These next two require chrono::time_point_cast because the conversion
- // from a resolution of seconds (the return value of convert()) to a
- // coarser resolution requires an explicit cast.
- const time_point<chrono::minutes> tp_m =
- chrono::time_point_cast<chrono::minutes>(
+ // These next two require chrono::time_point_cast because the conversion
+ // from a resolution of seconds (the return value of convert()) to a
+ // coarser resolution requires an explicit cast.
+ const time_point<chrono::minutes> tp_m =
+ chrono::time_point_cast<chrono::minutes>(
convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
EXPECT_EQ("04:00", format("%M:%E*S", tp_m, utc));
- const time_point<chrono::hours> tp_h =
- chrono::time_point_cast<chrono::hours>(
+ const time_point<chrono::hours> tp_h =
+ chrono::time_point_cast<chrono::hours>(
convert(civil_second(2015, 1, 2, 3, 4, 5), utc));
EXPECT_EQ("00:00", format("%M:%E*S", tp_h, utc));
}
@@ -917,7 +917,7 @@ TEST(MakeTime, TimePointResolution) {
TEST(MakeTime, Normalization) {
const time_zone tz = LoadZone("America/New_York");
const auto tp = convert(civil_second(2009, 2, 13, 18, 31, 30), tz);
- EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
+ EXPECT_EQ(chrono::system_clock::from_time_t(1234567890), tp);
// Now requests for the same time_point but with out-of-range fields.
EXPECT_EQ(tp, convert(civil_second(2008, 14, 13, 18, 31, 30), tz)); // month
@@ -927,253 +927,253 @@ TEST(MakeTime, Normalization) {
EXPECT_EQ(tp, convert(civil_second(2009, 2, 13, 18, 30, 90), tz)); // second
}
-// NOTE: Run this with -ftrapv to detect overflow problems.
+// NOTE: Run this with -ftrapv to detect overflow problems.
TEST(MakeTime, SysSecondsLimits) {
- const char RFC3339[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
+ const char RFC3339[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
const time_zone utc = utc_time_zone();
- const time_zone east = fixed_time_zone(chrono::hours(14));
- const time_zone west = fixed_time_zone(-chrono::hours(14));
- time_point<cctz::seconds> tp;
+ const time_zone east = fixed_time_zone(chrono::hours(14));
+ const time_zone west = fixed_time_zone(-chrono::hours(14));
+ time_point<cctz::seconds> tp;
- // Approach the maximal time_point<cctz::seconds> value from below.
+ // Approach the maximal time_point<cctz::seconds> value from below.
tp = convert(civil_second(292277026596, 12, 4, 15, 30, 6), utc);
EXPECT_EQ("292277026596-12-04T15:30:06+00:00", format(RFC3339, tp, utc));
tp = convert(civil_second(292277026596, 12, 4, 15, 30, 7), utc);
EXPECT_EQ("292277026596-12-04T15:30:07+00:00", format(RFC3339, tp, utc));
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second(292277026596, 12, 4, 15, 30, 8), utc);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second::max(), utc);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
// Checks that we can also get the maximal value for a far-east zone.
tp = convert(civil_second(292277026596, 12, 5, 5, 30, 7), east);
EXPECT_EQ("292277026596-12-05T05:30:07+14:00", format(RFC3339, tp, east));
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second(292277026596, 12, 5, 5, 30, 8), east);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second::max(), east);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
// Checks that we can also get the maximal value for a far-west zone.
tp = convert(civil_second(292277026596, 12, 4, 1, 30, 7), west);
EXPECT_EQ("292277026596-12-04T01:30:07-14:00", format(RFC3339, tp, west));
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second(292277026596, 12, 4, 7, 30, 8), west);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
tp = convert(civil_second::max(), west);
- EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::max(), tp);
- // Approach the minimal time_point<cctz::seconds> value from above.
+ // Approach the minimal time_point<cctz::seconds> value from above.
tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 53), utc);
EXPECT_EQ("-292277022657-01-27T08:29:53+00:00", format(RFC3339, tp, utc));
tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 52), utc);
EXPECT_EQ("-292277022657-01-27T08:29:52+00:00", format(RFC3339, tp, utc));
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second(-292277022657, 1, 27, 8, 29, 51), utc);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second::min(), utc);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
// Checks that we can also get the minimal value for a far-east zone.
tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 52), east);
EXPECT_EQ("-292277022657-01-27T22:29:52+14:00", format(RFC3339, tp, east));
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second(-292277022657, 1, 27, 22, 29, 51), east);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second::min(), east);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
// Checks that we can also get the minimal value for a far-west zone.
tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 52), west);
EXPECT_EQ("-292277022657-01-26T18:29:52-14:00", format(RFC3339, tp, west));
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second(-292277022657, 1, 26, 18, 29, 51), west);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
tp = convert(civil_second::min(), west);
- EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
-
- // Some similar checks for the "libc" time-zone implementation.
- if (sizeof(std::time_t) >= 8) {
- // Checks that "tm_year + 1900", as used by the "libc" implementation,
- // can produce year values beyond the range on an int without overflow.
-#if defined(_WIN32) || defined(_WIN64)
- // localtime_s() and gmtime_s() don't believe in years outside [1970:3000].
-#else
- const time_zone cut = LoadZone("libc:UTC");
- const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
- tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut);
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
- // The BSD gmtime_r() fails on extreme positive tm_year values.
-#else
- EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, cut));
-#endif
- const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
- tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut);
- EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, cut));
-#endif
- }
+ EXPECT_EQ(time_point<cctz::seconds>::min(), tp);
+
+ // Some similar checks for the "libc" time-zone implementation.
+ if (sizeof(std::time_t) >= 8) {
+ // Checks that "tm_year + 1900", as used by the "libc" implementation,
+ // can produce year values beyond the range on an int without overflow.
+#if defined(_WIN32) || defined(_WIN64)
+ // localtime_s() and gmtime_s() don't believe in years outside [1970:3000].
+#else
+ const time_zone cut = LoadZone("libc:UTC");
+ const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
+ tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut);
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ // The BSD gmtime_r() fails on extreme positive tm_year values.
+#else
+ EXPECT_EQ("2147485547-12-31T23:59:59+00:00", format(RFC3339, tp, cut));
+#endif
+ const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
+ tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut);
+ EXPECT_EQ("-2147481748-01-01T00:00:00+00:00", format(RFC3339, tp, cut));
+#endif
+ }
+}
+
+TEST(MakeTime, LocalTimeLibC) {
+ // Checks that cctz and libc agree on transition points in [1970:2037].
+ //
+ // We limit this test case to environments where:
+ // 1) we know how to change the time zone used by localtime()/mktime(),
+ // 2) cctz and localtime()/mktime() will use similar-enough tzdata, and
+ // 3) we have some idea about how mktime() behaves during transitions.
+#if defined(__linux__) && !defined(__ANDROID__) && defined(CCTZ_TEST_LIBC_LOCALTIME)
+ const char* const ep = getenv("TZ");
+ std::string tz_name = (ep != nullptr) ? ep : "";
+ for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) {
+ ASSERT_EQ(0, setenv("TZ", *np, 1)); // change what "localtime" means
+ const auto zi = local_time_zone();
+ const auto lc = LoadZone("libc:localtime");
+ time_zone::civil_transition transition;
+ for (auto tp = zi.lookup(civil_second()).trans;
+ zi.next_transition(tp, &transition);
+ tp = zi.lookup(transition.to).trans) {
+ const auto fcl = zi.lookup(transition.from);
+ const auto tcl = zi.lookup(transition.to);
+ civil_second cs; // compare cs in zi and lc
+ if (fcl.kind == time_zone::civil_lookup::UNIQUE) {
+ if (tcl.kind == time_zone::civil_lookup::UNIQUE) {
+ // Both unique; must be an is_dst or abbr change.
+ ASSERT_EQ(transition.from, transition.to);
+ const auto trans = fcl.trans;
+ const auto tal = zi.lookup(trans);
+ const auto tprev = trans - cctz::seconds(1);
+ const auto pal = zi.lookup(tprev);
+ if (pal.is_dst == tal.is_dst) {
+ ASSERT_STRNE(pal.abbr, tal.abbr);
+ }
+ continue;
+ }
+ ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind);
+ cs = transition.to;
+ } else {
+ ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind);
+ ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind);
+ cs = transition.from;
+ }
+ if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t)
+ const auto cl_zi = zi.lookup(cs);
+ if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) {
+ // The "libc" implementation cannot correctly classify transitions
+ // that don't change the "tm_isdst" flag. In Europe/Volgograd, for
+ // example, there is a SKIPPED transition from +03 to +04 with dst=F
+ // on both sides ...
+ // 1540681199 = 2018-10-28 01:59:59 +03:00:00 [dst=F off=10800]
+ // 1540681200 = 2018-10-28 03:00:00 +04:00:00 [dst=F off=14400]
+ // but std::mktime(2018-10-28 02:00:00, tm_isdst=0) fails, unlike,
+ // say, the similar Europe/Chisinau transition from +02 to +03 ...
+ // 1521935999 = 2018-03-25 01:59:59 +02:00:00 [dst=F off=7200]
+ // 1521936000 = 2018-03-25 03:00:00 +03:00:00 [dst=T off=10800]
+ // where std::mktime(2018-03-25 02:00:00, tm_isdst=0) succeeds and
+ // returns 1521936000.
+ continue;
+ }
+ if (cs == civil_second(2037, 10, 4, 2, 0, 0)) {
+ const std::string tzname = *np;
+ if (tzname == "Africa/Casablanca" || tzname == "Africa/El_Aaiun") {
+ // The "libc" implementation gets this transition wrong (at least
+ // until 2018g when it was removed), returning an offset of 3600
+ // instead of 0. TODO: Revert this when 2018g is ubiquitous.
+ continue;
+ }
+ }
+ const auto cl_lc = lc.lookup(cs);
+ SCOPED_TRACE(testing::Message() << "For " << cs << " in " << *np);
+ EXPECT_EQ(cl_zi.kind, cl_lc.kind);
+ EXPECT_EQ(cl_zi.pre, cl_lc.pre);
+ EXPECT_EQ(cl_zi.trans, cl_lc.trans);
+ EXPECT_EQ(cl_zi.post, cl_lc.post);
+ }
+ }
+ if (ep == nullptr) {
+ ASSERT_EQ(0, unsetenv("TZ"));
+ } else {
+ ASSERT_EQ(0, setenv("TZ", tz_name.c_str(), 1));
+ }
+#endif
+}
+
+TEST(NextTransition, UTC) {
+ const auto tz = utc_time_zone();
+ time_zone::civil_transition trans;
+
+ auto tp = time_point<cctz::seconds>::min();
+ EXPECT_FALSE(tz.next_transition(tp, &trans));
+
+ tp = time_point<cctz::seconds>::max();
+ EXPECT_FALSE(tz.next_transition(tp, &trans));
+}
+
+TEST(PrevTransition, UTC) {
+ const auto tz = utc_time_zone();
+ time_zone::civil_transition trans;
+
+ auto tp = time_point<cctz::seconds>::max();
+ EXPECT_FALSE(tz.prev_transition(tp, &trans));
+
+ tp = time_point<cctz::seconds>::min();
+ EXPECT_FALSE(tz.prev_transition(tp, &trans));
+}
+
+TEST(NextTransition, AmericaNewYork) {
+ const auto tz = LoadZone("America/New_York");
+ time_zone::civil_transition trans;
+
+ auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz);
+ EXPECT_TRUE(tz.next_transition(tp, &trans));
+ EXPECT_EQ(civil_second(2018, 11, 4, 2, 0, 0), trans.from);
+ EXPECT_EQ(civil_second(2018, 11, 4, 1, 0, 0), trans.to);
+
+ tp = time_point<cctz::seconds>::max();
+ EXPECT_FALSE(tz.next_transition(tp, &trans));
+
+ tp = time_point<cctz::seconds>::min();
+ EXPECT_TRUE(tz.next_transition(tp, &trans));
+ if (trans.from == civil_second(1918, 3, 31, 2, 0, 0)) {
+ // It looks like the tzdata is only 32 bit (probably macOS),
+ // which bottoms out at 1901-12-13T20:45:52+00:00.
+ EXPECT_EQ(civil_second(1918, 3, 31, 3, 0, 0), trans.to);
+ } else {
+ EXPECT_EQ(civil_second(1883, 11, 18, 12, 3, 58), trans.from);
+ EXPECT_EQ(civil_second(1883, 11, 18, 12, 0, 0), trans.to);
+ }
+}
+
+TEST(PrevTransition, AmericaNewYork) {
+ const auto tz = LoadZone("America/New_York");
+ time_zone::civil_transition trans;
+
+ auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz);
+ EXPECT_TRUE(tz.prev_transition(tp, &trans));
+ EXPECT_EQ(civil_second(2018, 3, 11, 2, 0, 0), trans.from);
+ EXPECT_EQ(civil_second(2018, 3, 11, 3, 0, 0), trans.to);
+
+ tp = time_point<cctz::seconds>::min();
+ EXPECT_FALSE(tz.prev_transition(tp, &trans));
+
+ tp = time_point<cctz::seconds>::max();
+ EXPECT_TRUE(tz.prev_transition(tp, &trans));
+ // We have a transition but we don't know which one.
}
-TEST(MakeTime, LocalTimeLibC) {
- // Checks that cctz and libc agree on transition points in [1970:2037].
- //
- // We limit this test case to environments where:
- // 1) we know how to change the time zone used by localtime()/mktime(),
- // 2) cctz and localtime()/mktime() will use similar-enough tzdata, and
- // 3) we have some idea about how mktime() behaves during transitions.
-#if defined(__linux__) && !defined(__ANDROID__) && defined(CCTZ_TEST_LIBC_LOCALTIME)
- const char* const ep = getenv("TZ");
- std::string tz_name = (ep != nullptr) ? ep : "";
- for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) {
- ASSERT_EQ(0, setenv("TZ", *np, 1)); // change what "localtime" means
- const auto zi = local_time_zone();
- const auto lc = LoadZone("libc:localtime");
- time_zone::civil_transition transition;
- for (auto tp = zi.lookup(civil_second()).trans;
- zi.next_transition(tp, &transition);
- tp = zi.lookup(transition.to).trans) {
- const auto fcl = zi.lookup(transition.from);
- const auto tcl = zi.lookup(transition.to);
- civil_second cs; // compare cs in zi and lc
- if (fcl.kind == time_zone::civil_lookup::UNIQUE) {
- if (tcl.kind == time_zone::civil_lookup::UNIQUE) {
- // Both unique; must be an is_dst or abbr change.
- ASSERT_EQ(transition.from, transition.to);
- const auto trans = fcl.trans;
- const auto tal = zi.lookup(trans);
- const auto tprev = trans - cctz::seconds(1);
- const auto pal = zi.lookup(tprev);
- if (pal.is_dst == tal.is_dst) {
- ASSERT_STRNE(pal.abbr, tal.abbr);
- }
- continue;
- }
- ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind);
- cs = transition.to;
- } else {
- ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind);
- ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind);
- cs = transition.from;
- }
- if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t)
- const auto cl_zi = zi.lookup(cs);
- if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) {
- // The "libc" implementation cannot correctly classify transitions
- // that don't change the "tm_isdst" flag. In Europe/Volgograd, for
- // example, there is a SKIPPED transition from +03 to +04 with dst=F
- // on both sides ...
- // 1540681199 = 2018-10-28 01:59:59 +03:00:00 [dst=F off=10800]
- // 1540681200 = 2018-10-28 03:00:00 +04:00:00 [dst=F off=14400]
- // but std::mktime(2018-10-28 02:00:00, tm_isdst=0) fails, unlike,
- // say, the similar Europe/Chisinau transition from +02 to +03 ...
- // 1521935999 = 2018-03-25 01:59:59 +02:00:00 [dst=F off=7200]
- // 1521936000 = 2018-03-25 03:00:00 +03:00:00 [dst=T off=10800]
- // where std::mktime(2018-03-25 02:00:00, tm_isdst=0) succeeds and
- // returns 1521936000.
- continue;
- }
- if (cs == civil_second(2037, 10, 4, 2, 0, 0)) {
- const std::string tzname = *np;
- if (tzname == "Africa/Casablanca" || tzname == "Africa/El_Aaiun") {
- // The "libc" implementation gets this transition wrong (at least
- // until 2018g when it was removed), returning an offset of 3600
- // instead of 0. TODO: Revert this when 2018g is ubiquitous.
- continue;
- }
- }
- const auto cl_lc = lc.lookup(cs);
- SCOPED_TRACE(testing::Message() << "For " << cs << " in " << *np);
- EXPECT_EQ(cl_zi.kind, cl_lc.kind);
- EXPECT_EQ(cl_zi.pre, cl_lc.pre);
- EXPECT_EQ(cl_zi.trans, cl_lc.trans);
- EXPECT_EQ(cl_zi.post, cl_lc.post);
- }
- }
- if (ep == nullptr) {
- ASSERT_EQ(0, unsetenv("TZ"));
- } else {
- ASSERT_EQ(0, setenv("TZ", tz_name.c_str(), 1));
- }
-#endif
-}
-
-TEST(NextTransition, UTC) {
- const auto tz = utc_time_zone();
- time_zone::civil_transition trans;
-
- auto tp = time_point<cctz::seconds>::min();
- EXPECT_FALSE(tz.next_transition(tp, &trans));
-
- tp = time_point<cctz::seconds>::max();
- EXPECT_FALSE(tz.next_transition(tp, &trans));
-}
-
-TEST(PrevTransition, UTC) {
- const auto tz = utc_time_zone();
- time_zone::civil_transition trans;
-
- auto tp = time_point<cctz::seconds>::max();
- EXPECT_FALSE(tz.prev_transition(tp, &trans));
-
- tp = time_point<cctz::seconds>::min();
- EXPECT_FALSE(tz.prev_transition(tp, &trans));
-}
-
-TEST(NextTransition, AmericaNewYork) {
- const auto tz = LoadZone("America/New_York");
- time_zone::civil_transition trans;
-
- auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz);
- EXPECT_TRUE(tz.next_transition(tp, &trans));
- EXPECT_EQ(civil_second(2018, 11, 4, 2, 0, 0), trans.from);
- EXPECT_EQ(civil_second(2018, 11, 4, 1, 0, 0), trans.to);
-
- tp = time_point<cctz::seconds>::max();
- EXPECT_FALSE(tz.next_transition(tp, &trans));
-
- tp = time_point<cctz::seconds>::min();
- EXPECT_TRUE(tz.next_transition(tp, &trans));
- if (trans.from == civil_second(1918, 3, 31, 2, 0, 0)) {
- // It looks like the tzdata is only 32 bit (probably macOS),
- // which bottoms out at 1901-12-13T20:45:52+00:00.
- EXPECT_EQ(civil_second(1918, 3, 31, 3, 0, 0), trans.to);
- } else {
- EXPECT_EQ(civil_second(1883, 11, 18, 12, 3, 58), trans.from);
- EXPECT_EQ(civil_second(1883, 11, 18, 12, 0, 0), trans.to);
- }
-}
-
-TEST(PrevTransition, AmericaNewYork) {
- const auto tz = LoadZone("America/New_York");
- time_zone::civil_transition trans;
-
- auto tp = convert(civil_second(2018, 6, 30, 0, 0, 0), tz);
- EXPECT_TRUE(tz.prev_transition(tp, &trans));
- EXPECT_EQ(civil_second(2018, 3, 11, 2, 0, 0), trans.from);
- EXPECT_EQ(civil_second(2018, 3, 11, 3, 0, 0), trans.to);
-
- tp = time_point<cctz::seconds>::min();
- EXPECT_FALSE(tz.prev_transition(tp, &trans));
-
- tp = time_point<cctz::seconds>::max();
- EXPECT_TRUE(tz.prev_transition(tp, &trans));
- // We have a transition but we don't know which one.
-}
-
TEST(TimeZoneEdgeCase, AmericaNewYork) {
const time_zone tz = LoadZone("America/New_York");
// Spring 1:59:59 -> 3:00:00
auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -5 * 3600, false, "EST");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 3, 10, 3, 0, 0, -4 * 3600, true, "EDT");
// Fall 1:59:59 -> 1:00:00
tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -4 * 3600, true, "EDT");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 11, 3, 1, 0, 0, -5 * 3600, false, "EST");
}
@@ -1183,13 +1183,13 @@ TEST(TimeZoneEdgeCase, AmericaLosAngeles) {
// Spring 1:59:59 -> 3:00:00
auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -8 * 3600, false, "PST");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 3, 10, 3, 0, 0, -7 * 3600, true, "PDT");
// Fall 1:59:59 -> 1:00:00
tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -7 * 3600, true, "PDT");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 11, 3, 1, 0, 0, -8 * 3600, false, "PST");
}
@@ -1199,13 +1199,13 @@ TEST(TimeZoneEdgeCase, ArizonaNoTransition) {
// No transition in Spring.
auto tp = convert(civil_second(2013, 3, 10, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 3, 10, 1, 59, 59, -7 * 3600, false, "MST");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 3, 10, 2, 0, 0, -7 * 3600, false, "MST");
// No transition in Fall.
tp = convert(civil_second(2013, 11, 3, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 11, 3, 1, 59, 59, -7 * 3600, false, "MST");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 11, 3, 2, 0, 0, -7 * 3600, false, "MST");
}
@@ -1218,7 +1218,7 @@ TEST(TimeZoneEdgeCase, AsiaKathmandu) {
// 504901800 == Wed, 1 Jan 1986 00:15:00 +0545 (+0545)
auto tp = convert(civil_second(1985, 12, 31, 23, 59, 59), tz);
ExpectTime(tp, tz, 1985, 12, 31, 23, 59, 59, 5.5 * 3600, false, "+0530");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 1986, 1, 1, 0, 15, 0, 5.75 * 3600, false, "+0545");
}
@@ -1231,14 +1231,14 @@ TEST(TimeZoneEdgeCase, PacificChatham) {
// 1365256800 == Sun, 7 Apr 2013 02:45:00 +1245 (+1245)
auto tp = convert(civil_second(2013, 4, 7, 3, 44, 59), tz);
ExpectTime(tp, tz, 2013, 4, 7, 3, 44, 59, 13.75 * 3600, true, "+1345");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 4, 7, 2, 45, 0, 12.75 * 3600, false, "+1245");
// 1380376799 == Sun, 29 Sep 2013 02:44:59 +1245 (+1245)
// 1380376800 == Sun, 29 Sep 2013 03:45:00 +1345 (+1345)
tp = convert(civil_second(2013, 9, 29, 2, 44, 59), tz);
ExpectTime(tp, tz, 2013, 9, 29, 2, 44, 59, 12.75 * 3600, false, "+1245");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 9, 29, 3, 45, 0, 13.75 * 3600, true, "+1345");
}
@@ -1251,14 +1251,14 @@ TEST(TimeZoneEdgeCase, AustraliaLordHowe) {
// 1365260400 == Sun, 7 Apr 2013 01:30:00 +1030 (+1030)
auto tp = convert(civil_second(2013, 4, 7, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 4, 7, 1, 59, 59, 11 * 3600, true, "+11");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 4, 7, 1, 30, 0, 10.5 * 3600, false, "+1030");
// 1380986999 == Sun, 6 Oct 2013 01:59:59 +1030 (+1030)
// 1380987000 == Sun, 6 Oct 2013 02:30:00 +1100 (+11)
tp = convert(civil_second(2013, 10, 6, 1, 59, 59), tz);
ExpectTime(tp, tz, 2013, 10, 6, 1, 59, 59, 10.5 * 3600, false, "+1030");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2013, 10, 6, 2, 30, 0, 11 * 3600, true, "+11");
}
@@ -1275,40 +1275,40 @@ TEST(TimeZoneEdgeCase, PacificApia) {
// 1325239200 == Sat, 31 Dec 2011 00:00:00 +1400 (+14)
auto tp = convert(civil_second(2011, 12, 29, 23, 59, 59), tz);
ExpectTime(tp, tz, 2011, 12, 29, 23, 59, 59, -10 * 3600, true, "-10");
- EXPECT_EQ(363, get_yearday(convert(tp, tz)));
- tp += cctz::seconds(1);
+ EXPECT_EQ(363, get_yearday(convert(tp, tz)));
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2011, 12, 31, 0, 0, 0, 14 * 3600, true, "+14");
- EXPECT_EQ(365, get_yearday(convert(tp, tz)));
+ EXPECT_EQ(365, get_yearday(convert(tp, tz)));
}
TEST(TimeZoneEdgeCase, AfricaCairo) {
const time_zone tz = LoadZone("Africa/Cairo");
- if (VersionCmp(tz, "2014c") >= 0) {
- // An interesting case of midnight not existing.
- //
- // 1400191199 == Thu, 15 May 2014 23:59:59 +0200 (EET)
- // 1400191200 == Fri, 16 May 2014 01:00:00 +0300 (EEST)
- auto tp = convert(civil_second(2014, 5, 15, 23, 59, 59), tz);
- ExpectTime(tp, tz, 2014, 5, 15, 23, 59, 59, 2 * 3600, false, "EET");
- tp += cctz::seconds(1);
- ExpectTime(tp, tz, 2014, 5, 16, 1, 0, 0, 3 * 3600, true, "EEST");
- }
+ if (VersionCmp(tz, "2014c") >= 0) {
+ // An interesting case of midnight not existing.
+ //
+ // 1400191199 == Thu, 15 May 2014 23:59:59 +0200 (EET)
+ // 1400191200 == Fri, 16 May 2014 01:00:00 +0300 (EEST)
+ auto tp = convert(civil_second(2014, 5, 15, 23, 59, 59), tz);
+ ExpectTime(tp, tz, 2014, 5, 15, 23, 59, 59, 2 * 3600, false, "EET");
+ tp += cctz::seconds(1);
+ ExpectTime(tp, tz, 2014, 5, 16, 1, 0, 0, 3 * 3600, true, "EEST");
+ }
}
TEST(TimeZoneEdgeCase, AfricaMonrovia) {
const time_zone tz = LoadZone("Africa/Monrovia");
- if (VersionCmp(tz, "2017b") >= 0) {
- // Strange offset change -00:44:30 -> +00:00:00 (non-DST)
- //
- // 63593069 == Thu, 6 Jan 1972 23:59:59 -0044 (MMT)
- // 63593070 == Fri, 7 Jan 1972 00:44:30 +0000 (GMT)
- auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz);
- ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
- tp += cctz::seconds(1);
- ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
- }
+ if (VersionCmp(tz, "2017b") >= 0) {
+ // Strange offset change -00:44:30 -> +00:00:00 (non-DST)
+ //
+ // 63593069 == Thu, 6 Jan 1972 23:59:59 -0044 (MMT)
+ // 63593070 == Fri, 7 Jan 1972 00:44:30 +0000 (GMT)
+ auto tp = convert(civil_second(1972, 1, 6, 23, 59, 59), tz);
+ ExpectTime(tp, tz, 1972, 1, 6, 23, 59, 59, -44.5 * 60, false, "MMT");
+ tp += cctz::seconds(1);
+ ExpectTime(tp, tz, 1972, 1, 7, 0, 44, 30, 0 * 60, false, "GMT");
+ }
}
TEST(TimeZoneEdgeCase, AmericaJamaica) {
@@ -1320,31 +1320,31 @@ TEST(TimeZoneEdgeCase, AmericaJamaica) {
const time_zone tz = LoadZone("America/Jamaica");
// Before the first transition.
- if (!tz.version().empty() && VersionCmp(tz, "2018d") >= 0) {
- // We avoid the expectations on the -18430 offset below unless we are
- // certain we have commit 907241e (Fix off-by-1 error for Jamaica and
- // T&C before 1913) from 2018d. TODO: Remove the "version() not empty"
- // part when 2018d is generally available from /usr/share/zoneinfo.
- auto tp = convert(civil_second(1889, 12, 31, 0, 0, 0), tz);
- ExpectTime(tp, tz, 1889, 12, 31, 0, 0, 0, -18430, false,
- tz.lookup(tp).abbr);
-
- // Over the first (abbreviation-change only) transition.
- // -2524503170 == Tue, 31 Dec 1889 23:59:59 -0507 (LMT)
- // -2524503169 == Wed, 1 Jan 1890 00:00:00 -0507 (KMT)
- tp = convert(civil_second(1889, 12, 31, 23, 59, 59), tz);
- ExpectTime(tp, tz, 1889, 12, 31, 23, 59, 59, -18430, false,
- tz.lookup(tp).abbr);
- tp += cctz::seconds(1);
- ExpectTime(tp, tz, 1890, 1, 1, 0, 0, 0, -18430, false, "KMT");
- }
+ if (!tz.version().empty() && VersionCmp(tz, "2018d") >= 0) {
+ // We avoid the expectations on the -18430 offset below unless we are
+ // certain we have commit 907241e (Fix off-by-1 error for Jamaica and
+ // T&C before 1913) from 2018d. TODO: Remove the "version() not empty"
+ // part when 2018d is generally available from /usr/share/zoneinfo.
+ auto tp = convert(civil_second(1889, 12, 31, 0, 0, 0), tz);
+ ExpectTime(tp, tz, 1889, 12, 31, 0, 0, 0, -18430, false,
+ tz.lookup(tp).abbr);
+
+ // Over the first (abbreviation-change only) transition.
+ // -2524503170 == Tue, 31 Dec 1889 23:59:59 -0507 (LMT)
+ // -2524503169 == Wed, 1 Jan 1890 00:00:00 -0507 (KMT)
+ tp = convert(civil_second(1889, 12, 31, 23, 59, 59), tz);
+ ExpectTime(tp, tz, 1889, 12, 31, 23, 59, 59, -18430, false,
+ tz.lookup(tp).abbr);
+ tp += cctz::seconds(1);
+ ExpectTime(tp, tz, 1890, 1, 1, 0, 0, 0, -18430, false, "KMT");
+ }
// Over the last (DST) transition.
// 436341599 == Sun, 30 Oct 1983 01:59:59 -0400 (EDT)
// 436341600 == Sun, 30 Oct 1983 01:00:00 -0500 (EST)
- auto tp = convert(civil_second(1983, 10, 30, 1, 59, 59), tz);
+ auto tp = convert(civil_second(1983, 10, 30, 1, 59, 59), tz);
ExpectTime(tp, tz, 1983, 10, 30, 1, 59, 59, -4 * 3600, true, "EDT");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 1983, 10, 30, 1, 0, 0, -5 * 3600, false, "EST");
// After the last transition.
@@ -1365,7 +1365,7 @@ TEST(TimeZoneEdgeCase, WET) {
// 228877200 == Sun, 3 Apr 1977 02:00:00 +0100 (WEST)
tp = convert(civil_second(1977, 4, 3, 0, 59, 59), tz);
ExpectTime(tp, tz, 1977, 4, 3, 0, 59, 59, 0, false, "WET");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 1977, 4, 3, 2, 0, 0, 1 * 3600, true, "WEST");
// A non-existent time within the first transition.
@@ -1387,12 +1387,12 @@ TEST(TimeZoneEdgeCase, FixedOffsets) {
const time_zone gmtm5 = LoadZone("Etc/GMT+5"); // -0500
auto tp = convert(civil_second(1970, 1, 1, 0, 0, 0), gmtm5);
ExpectTime(tp, gmtm5, 1970, 1, 1, 0, 0, 0, -5 * 3600, false, "-05");
- EXPECT_EQ(chrono::system_clock::from_time_t(5 * 3600), tp);
+ EXPECT_EQ(chrono::system_clock::from_time_t(5 * 3600), tp);
const time_zone gmtp5 = LoadZone("Etc/GMT-5"); // +0500
tp = convert(civil_second(1970, 1, 1, 0, 0, 0), gmtp5);
ExpectTime(tp, gmtp5, 1970, 1, 1, 0, 0, 0, 5 * 3600, false, "+05");
- EXPECT_EQ(chrono::system_clock::from_time_t(-5 * 3600), tp);
+ EXPECT_EQ(chrono::system_clock::from_time_t(-5 * 3600), tp);
}
TEST(TimeZoneEdgeCase, NegativeYear) {
@@ -1400,10 +1400,10 @@ TEST(TimeZoneEdgeCase, NegativeYear) {
const time_zone tz = utc_time_zone();
auto tp = convert(civil_second(0, 1, 1, 0, 0, 0), tz);
ExpectTime(tp, tz, 0, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC");
- EXPECT_EQ(weekday::saturday, get_weekday(convert(tp, tz)));
- tp -= cctz::seconds(1);
+ EXPECT_EQ(weekday::saturday, get_weekday(convert(tp, tz)));
+ tp -= cctz::seconds(1);
ExpectTime(tp, tz, -1, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC");
- EXPECT_EQ(weekday::friday, get_weekday(convert(tp, tz)));
+ EXPECT_EQ(weekday::friday, get_weekday(convert(tp, tz)));
}
TEST(TimeZoneEdgeCase, UTC32bitLimit) {
@@ -1415,7 +1415,7 @@ TEST(TimeZoneEdgeCase, UTC32bitLimit) {
// 2147483648 == Tue, 19 Jan 2038 03:14:08 +0000 (UTC)
auto tp = convert(civil_second(2038, 1, 19, 3, 14, 7), tz);
ExpectTime(tp, tz, 2038, 1, 19, 3, 14, 7, 0 * 3600, false, "UTC");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 2038, 1, 19, 3, 14, 8, 0 * 3600, false, "UTC");
}
@@ -1428,7 +1428,7 @@ TEST(TimeZoneEdgeCase, UTC5DigitYear) {
// 253402300800 == Sat, 1 Jan 1000 00:00:00 +0000 (UTC)
auto tp = convert(civil_second(9999, 12, 31, 23, 59, 59), tz);
ExpectTime(tp, tz, 9999, 12, 31, 23, 59, 59, 0 * 3600, false, "UTC");
- tp += cctz::seconds(1);
+ tp += cctz::seconds(1);
ExpectTime(tp, tz, 10000, 1, 1, 0, 0, 0, 0 * 3600, false, "UTC");
}
diff --git a/contrib/libs/cctz/test/ya.make b/contrib/libs/cctz/test/ya.make
index 57b9be0018..8815f9769d 100644
--- a/contrib/libs/cctz/test/ya.make
+++ b/contrib/libs/cctz/test/ya.make
@@ -1,4 +1,4 @@
-GTEST()
+GTEST()
LICENSE(Apache-2.0)
@@ -10,26 +10,26 @@ OWNER(
)
PEERDIR(
- contrib/libs/cctz
+ contrib/libs/cctz
contrib/libs/cctz/tzdata
)
ADDINCL(
contrib/libs/cctz/include
)
-
-IF (NOT AUTOCHECK)
- # We do not set TZDIR to a stable data source, so
- # LoadZone("libc:localtime") is inconsistent and makes
- # LocalTimeLibC test fail on distbuild.
+
+IF (NOT AUTOCHECK)
+ # We do not set TZDIR to a stable data source, so
+ # LoadZone("libc:localtime") is inconsistent and makes
+ # LocalTimeLibC test fail on distbuild.
CFLAGS(
-DCCTZ_TEST_LIBC_LOCALTIME
)
-ENDIF()
-
+ENDIF()
+
SRCS(
civil_time_test.cc
- time_zone_format_test.cc
+ time_zone_format_test.cc
time_zone_lookup_test.cc
)
diff --git a/contrib/libs/cctz/tzdata/factory.cpp b/contrib/libs/cctz/tzdata/factory.cpp
index a9dcbf6cd7..5a4b4a27b6 100644
--- a/contrib/libs/cctz/tzdata/factory.cpp
+++ b/contrib/libs/cctz/tzdata/factory.cpp
@@ -1,4 +1,4 @@
-#include <contrib/libs/cctz/include/cctz/zone_info_source.h>
+#include <contrib/libs/cctz/include/cctz/zone_info_source.h>
#include <library/cpp/resource/resource.h>
diff --git a/contrib/libs/cctz/ya.make b/contrib/libs/cctz/ya.make
index d221d70f5d..954d24908f 100644
--- a/contrib/libs/cctz/ya.make
+++ b/contrib/libs/cctz/ya.make
@@ -1,5 +1,5 @@
-# Generated by devtools/yamaker from nixpkgs 5852a21819542e6809f68ba5a798600e69874e76.
-
+# Generated by devtools/yamaker from nixpkgs 5852a21819542e6809f68ba5a798600e69874e76.
+
LIBRARY()
OWNER(
@@ -7,14 +7,14 @@ OWNER(
petrk
)
-VERSION(2020-11-11)
+VERSION(2020-11-11)
+
+ORIGINAL_SOURCE(https://github.com/google/cctz/archive/98fb541c6f0f35cf0dffcbc3777d8385bbd5b4c1.tar.gz)
-ORIGINAL_SOURCE(https://github.com/google/cctz/archive/98fb541c6f0f35cf0dffcbc3777d8385bbd5b4c1.tar.gz)
-
LICENSE(
Apache-2.0 AND
Public-Domain
-)
+)
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
@@ -22,33 +22,33 @@ ADDINCL(
GLOBAL contrib/libs/cctz/include
)
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-IF (OS_DARWIN)
- LDFLAGS(
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+IF (OS_DARWIN)
+ LDFLAGS(
-framework
CoreFoundation
- )
-ENDIF()
-
+ )
+ENDIF()
+
SRCS(
- src/civil_time_detail.cc
- src/time_zone_fixed.cc
- src/time_zone_format.cc
- src/time_zone_if.cc
- src/time_zone_impl.cc
- src/time_zone_info.cc
- src/time_zone_libc.cc
- src/time_zone_lookup.cc
- src/time_zone_posix.cc
- src/zone_info_source.cc
+ src/civil_time_detail.cc
+ src/time_zone_fixed.cc
+ src/time_zone_format.cc
+ src/time_zone_if.cc
+ src/time_zone_impl.cc
+ src/time_zone_info.cc
+ src/time_zone_libc.cc
+ src/time_zone_lookup.cc
+ src/time_zone_posix.cc
+ src/zone_info_source.cc
)
-END()
+END()
-RECURSE(
- test
- tzdata
-)
+RECURSE(
+ test
+ tzdata
+)