aboutsummaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorpetrk <petrk@yandex-team.ru>2022-02-10 16:47:26 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:47:26 +0300
commitaf66956edf116b93d5a07894ccb61dd4447d0b34 (patch)
tree7b4cde47a2b3630f5a3048855949c4d46b893fc0 /contrib
parentdc5feacd15e76abe98d23fe0d4ea3c02cb8de60f (diff)
downloadydb-af66956edf116b93d5a07894ccb61dd4447d0b34.tar.gz
Restoring authorship annotation for <petrk@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib')
-rw-r--r--contrib/libs/cctz/include/cctz/civil_time.h636
-rw-r--r--contrib/libs/cctz/include/cctz/civil_time_detail.h994
-rw-r--r--contrib/libs/cctz/include/cctz/time_zone.h548
-rw-r--r--contrib/libs/cctz/include/cctz/zone_info_source.h162
-rw-r--r--contrib/libs/cctz/src/civil_time_detail.cc142
-rw-r--r--contrib/libs/cctz/src/time_zone_fixed.cc164
-rw-r--r--contrib/libs/cctz/src/time_zone_fixed.h80
-rw-r--r--contrib/libs/cctz/src/time_zone_format.cc1496
-rw-r--r--contrib/libs/cctz/src/time_zone_if.cc66
-rw-r--r--contrib/libs/cctz/src/time_zone_if.h98
-rw-r--r--contrib/libs/cctz/src/time_zone_impl.cc148
-rw-r--r--contrib/libs/cctz/src/time_zone_impl.h132
-rw-r--r--contrib/libs/cctz/src/time_zone_info.cc1362
-rw-r--r--contrib/libs/cctz/src/time_zone_info.h224
-rw-r--r--contrib/libs/cctz/src/time_zone_libc.cc138
-rw-r--r--contrib/libs/cctz/src/time_zone_libc.h84
-rw-r--r--contrib/libs/cctz/src/time_zone_lookup.cc176
-rw-r--r--contrib/libs/cctz/src/time_zone_posix.cc290
-rw-r--r--contrib/libs/cctz/src/time_zone_posix.h196
-rw-r--r--contrib/libs/cctz/src/tzfile.h64
-rw-r--r--contrib/libs/cctz/tzdata/factory.cpp110
-rwxr-xr-xcontrib/libs/cctz/tzdata/update_tzdata.py14
-rw-r--r--contrib/libs/cctz/tzdata/ya.make6
-rw-r--r--contrib/libs/cctz/tzdata/ya.make.resources4
24 files changed, 3667 insertions, 3667 deletions
diff --git a/contrib/libs/cctz/include/cctz/civil_time.h b/contrib/libs/cctz/include/cctz/civil_time.h
index 57bd86cc06..0b339e8248 100644
--- a/contrib/libs/cctz/include/cctz/civil_time.h
+++ b/contrib/libs/cctz/include/cctz/civil_time.h
@@ -1,325 +1,325 @@
-// 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
-//
+// 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.
-
-#ifndef CCTZ_CIVIL_TIME_H_
-#define CCTZ_CIVIL_TIME_H_
-
+//
+// 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.
+
+#ifndef CCTZ_CIVIL_TIME_H_
+#define CCTZ_CIVIL_TIME_H_
+
#include "cctz/civil_time_detail.h"
-
-namespace cctz {
-
-// The term "civil time" refers to the legally recognized human-scale time
-// that is represented by the six fields YYYY-MM-DD hh:mm:ss. Modern-day civil
-// time follows the Gregorian Calendar and is a time-zone-independent concept.
-// A "date" is perhaps the most common example of a civil time (represented in
-// this library as cctz::civil_day). This library provides six classes and a
-// handful of functions that help with rounding, iterating, and arithmetic on
-// civil times while avoiding complications like daylight-saving time (DST).
-//
-// The following six classes form the core of this civil-time library:
-//
-// * civil_second
-// * civil_minute
-// * civil_hour
-// * civil_day
-// * civil_month
-// * civil_year
-//
-// Each class is a simple value type with the same interface for construction
-// and the same six accessors for each of the civil fields (year, month, day,
-// hour, minute, and second, aka YMDHMS). These classes differ only in their
-// alignment, which is indicated by the type name and specifies the field on
-// which arithmetic operates.
-//
-// Each class can be constructed by passing up to six optional integer
-// arguments representing the YMDHMS fields (in that order) to the
-// constructor. Omitted fields are assigned their minimum valid value. Hours,
-// minutes, and seconds will be set to 0, month and day will be set to 1, and
-// since there is no minimum valid year, it will be set to 1970. So, a
-// default-constructed civil-time object will have YMDHMS fields representing
-// "1970-01-01 00:00:00". Fields that are out-of-range are normalized (e.g.,
-// October 32 -> November 1) so that all civil-time objects represent valid
-// values.
-//
-// Each civil-time class is aligned to the civil-time field indicated in the
-// class's name after normalization. Alignment is performed by setting all the
-// inferior fields to their minimum valid value (as described above). The
-// following are examples of how each of the six types would align the fields
-// representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the
-// string format used here is not important; it's just a shorthand way of
-// showing the six YMDHMS fields.)
-//
-// civil_second 2015-11-22 12:34:56
-// civil_minute 2015-11-22 12:34:00
-// civil_hour 2015-11-22 12:00:00
-// civil_day 2015-11-22 00:00:00
-// civil_month 2015-11-01 00:00:00
-// civil_year 2015-01-01 00:00:00
-//
-// Each civil-time type performs arithmetic on the field to which it is
-// aligned. This means that adding 1 to a civil_day increments the day field
-// (normalizing as necessary), and subtracting 7 from a civil_month operates
-// on the month field (normalizing as necessary). All arithmetic produces a
-// valid civil time. Difference requires two similarly aligned civil-time
-// objects and returns the scalar answer in units of the objects' alignment.
-// For example, the difference between two civil_hour objects will give an
-// answer in units of civil hours.
-//
-// In addition to the six civil-time types just described, there are
-// a handful of helper functions and algorithms for performing common
-// calculations. These are described below.
-//
-// Note: In C++14 and later, this library is usable in a constexpr context.
-//
-// CONSTRUCTION:
-//
-// Each of the civil-time types can be constructed in two ways: by directly
-// passing to the constructor up to six (optional) integers representing the
-// YMDHMS fields, or by copying the YMDHMS fields from a differently aligned
-// civil-time type.
-//
-// civil_day default_value; // 1970-01-01 00:00:00
-//
-// civil_day a(2015, 2, 3); // 2015-02-03 00:00:00
-// civil_day b(2015, 2, 3, 4, 5, 6); // 2015-02-03 00:00:00
-// civil_day c(2015); // 2015-01-01 00:00:00
-//
-// civil_second ss(2015, 2, 3, 4, 5, 6); // 2015-02-03 04:05:06
-// civil_minute mm(ss); // 2015-02-03 04:05:00
-// civil_hour hh(mm); // 2015-02-03 04:00:00
-// civil_day d(hh); // 2015-02-03 00:00:00
-// civil_month m(d); // 2015-02-01 00:00:00
-// civil_year y(m); // 2015-01-01 00:00:00
-//
-// m = civil_month(y); // 2015-01-01 00:00:00
-// d = civil_day(m); // 2015-01-01 00:00:00
-// hh = civil_hour(d); // 2015-01-01 00:00:00
-// mm = civil_minute(hh); // 2015-01-01 00:00:00
-// ss = civil_second(mm); // 2015-01-01 00:00:00
-//
-// ALIGNMENT CONVERSION:
-//
-// The alignment of a civil-time object cannot change, but the object may be
-// used to construct a new object with a different alignment. This is referred
-// to as "realigning". When realigning to a type with the same or more
-// precision (e.g., civil_day -> civil_second), the conversion may be
-// performed implicitly since no information is lost. However, if information
-// could be discarded (e.g., civil_second -> civil_day), the conversion must
-// be explicit at the call site.
-//
-// void fun(const civil_day& day);
-//
-// civil_second cs;
-// fun(cs); // Won't compile because data may be discarded
-// fun(civil_day(cs)); // OK: explicit conversion
-//
-// civil_day cd;
-// fun(cd); // OK: no conversion needed
-//
-// civil_month cm;
-// fun(cm); // OK: implicit conversion to civil_day
-//
-// NORMALIZATION:
-//
-// Integer arguments passed to the constructor may be out-of-range, in which
-// case they are normalized to produce a valid civil-time object. This enables
-// natural arithmetic on constructor arguments without worrying about the
-// field's range. Normalization guarantees that there are no invalid
-// civil-time objects.
-//
-// civil_day d(2016, 10, 32); // Out-of-range day; normalized to 2016-11-01
-//
-// Note: If normalization is undesired, you can signal an error by comparing
-// the constructor arguments to the normalized values returned by the YMDHMS
-// properties.
-//
-// PROPERTIES:
-//
-// 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
+
+namespace cctz {
+
+// The term "civil time" refers to the legally recognized human-scale time
+// that is represented by the six fields YYYY-MM-DD hh:mm:ss. Modern-day civil
+// time follows the Gregorian Calendar and is a time-zone-independent concept.
+// A "date" is perhaps the most common example of a civil time (represented in
+// this library as cctz::civil_day). This library provides six classes and a
+// handful of functions that help with rounding, iterating, and arithmetic on
+// civil times while avoiding complications like daylight-saving time (DST).
+//
+// The following six classes form the core of this civil-time library:
+//
+// * civil_second
+// * civil_minute
+// * civil_hour
+// * civil_day
+// * civil_month
+// * civil_year
+//
+// Each class is a simple value type with the same interface for construction
+// and the same six accessors for each of the civil fields (year, month, day,
+// hour, minute, and second, aka YMDHMS). These classes differ only in their
+// alignment, which is indicated by the type name and specifies the field on
+// which arithmetic operates.
+//
+// Each class can be constructed by passing up to six optional integer
+// arguments representing the YMDHMS fields (in that order) to the
+// constructor. Omitted fields are assigned their minimum valid value. Hours,
+// minutes, and seconds will be set to 0, month and day will be set to 1, and
+// since there is no minimum valid year, it will be set to 1970. So, a
+// default-constructed civil-time object will have YMDHMS fields representing
+// "1970-01-01 00:00:00". Fields that are out-of-range are normalized (e.g.,
+// October 32 -> November 1) so that all civil-time objects represent valid
+// values.
+//
+// Each civil-time class is aligned to the civil-time field indicated in the
+// class's name after normalization. Alignment is performed by setting all the
+// inferior fields to their minimum valid value (as described above). The
+// following are examples of how each of the six types would align the fields
+// representing November 22, 2015 at 12:34:56 in the afternoon. (Note: the
+// string format used here is not important; it's just a shorthand way of
+// showing the six YMDHMS fields.)
+//
+// civil_second 2015-11-22 12:34:56
+// civil_minute 2015-11-22 12:34:00
+// civil_hour 2015-11-22 12:00:00
+// civil_day 2015-11-22 00:00:00
+// civil_month 2015-11-01 00:00:00
+// civil_year 2015-01-01 00:00:00
+//
+// Each civil-time type performs arithmetic on the field to which it is
+// aligned. This means that adding 1 to a civil_day increments the day field
+// (normalizing as necessary), and subtracting 7 from a civil_month operates
+// on the month field (normalizing as necessary). All arithmetic produces a
+// valid civil time. Difference requires two similarly aligned civil-time
+// objects and returns the scalar answer in units of the objects' alignment.
+// For example, the difference between two civil_hour objects will give an
+// answer in units of civil hours.
+//
+// In addition to the six civil-time types just described, there are
+// a handful of helper functions and algorithms for performing common
+// calculations. These are described below.
+//
+// Note: In C++14 and later, this library is usable in a constexpr context.
+//
+// CONSTRUCTION:
+//
+// Each of the civil-time types can be constructed in two ways: by directly
+// passing to the constructor up to six (optional) integers representing the
+// YMDHMS fields, or by copying the YMDHMS fields from a differently aligned
+// civil-time type.
+//
+// civil_day default_value; // 1970-01-01 00:00:00
+//
+// civil_day a(2015, 2, 3); // 2015-02-03 00:00:00
+// civil_day b(2015, 2, 3, 4, 5, 6); // 2015-02-03 00:00:00
+// civil_day c(2015); // 2015-01-01 00:00:00
+//
+// civil_second ss(2015, 2, 3, 4, 5, 6); // 2015-02-03 04:05:06
+// civil_minute mm(ss); // 2015-02-03 04:05:00
+// civil_hour hh(mm); // 2015-02-03 04:00:00
+// civil_day d(hh); // 2015-02-03 00:00:00
+// civil_month m(d); // 2015-02-01 00:00:00
+// civil_year y(m); // 2015-01-01 00:00:00
+//
+// m = civil_month(y); // 2015-01-01 00:00:00
+// d = civil_day(m); // 2015-01-01 00:00:00
+// hh = civil_hour(d); // 2015-01-01 00:00:00
+// mm = civil_minute(hh); // 2015-01-01 00:00:00
+// ss = civil_second(mm); // 2015-01-01 00:00:00
+//
+// ALIGNMENT CONVERSION:
+//
+// The alignment of a civil-time object cannot change, but the object may be
+// used to construct a new object with a different alignment. This is referred
+// to as "realigning". When realigning to a type with the same or more
+// precision (e.g., civil_day -> civil_second), the conversion may be
+// performed implicitly since no information is lost. However, if information
+// could be discarded (e.g., civil_second -> civil_day), the conversion must
+// be explicit at the call site.
+//
+// void fun(const civil_day& day);
+//
+// civil_second cs;
+// fun(cs); // Won't compile because data may be discarded
+// fun(civil_day(cs)); // OK: explicit conversion
+//
+// civil_day cd;
+// fun(cd); // OK: no conversion needed
+//
+// civil_month cm;
+// fun(cm); // OK: implicit conversion to civil_day
+//
+// NORMALIZATION:
+//
+// Integer arguments passed to the constructor may be out-of-range, in which
+// case they are normalized to produce a valid civil-time object. This enables
+// natural arithmetic on constructor arguments without worrying about the
+// field's range. Normalization guarantees that there are no invalid
+// civil-time objects.
+//
+// civil_day d(2016, 10, 32); // Out-of-range day; normalized to 2016-11-01
+//
+// Note: If normalization is undesired, you can signal an error by comparing
+// the constructor arguments to the normalized values returned by the YMDHMS
+// properties.
+//
+// PROPERTIES:
+//
+// 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.
-//
-// civil_day d(2015, 6, 28);
-// // d.year() == 2015
-// // d.month() == 6
-// // d.day() == 28
-// // d.hour() == 0
-// // d.minute() == 0
-// // d.second() == 0
-//
-// COMPARISON:
-//
-// Comparison always considers all six YMDHMS fields, regardless of the type's
-// alignment. Comparison between differently aligned civil-time types is
-// allowed.
-//
-// civil_day feb_3(2015, 2, 3); // 2015-02-03 00:00:00
-// civil_day mar_4(2015, 3, 4); // 2015-03-04 00:00:00
-// // feb_3 < mar_4
-// // civil_year(feb_3) == civil_year(mar_4)
-//
-// civil_second feb_3_noon(2015, 2, 3, 12, 0, 0); // 2015-02-03 12:00:00
-// // feb_3 < feb_3_noon
-// // feb_3 == civil_day(feb_3_noon)
-//
-// // Iterates all the days of February 2015.
-// for (civil_day d(2015, 2, 1); d < civil_month(2015, 3); ++d) {
-// // ...
-// }
-//
-// STREAMING:
-//
-// Each civil-time type may be sent to an output stream using operator<<().
-// The output format follows the pattern "YYYY-MM-DDThh:mm:ss" where fields
-// inferior to the type's alignment are omitted.
-//
-// civil_second cs(2015, 2, 3, 4, 5, 6);
-// std::cout << cs << "\n"; // Outputs: 2015-02-03T04:05:06
-//
-// civil_day cd(cs);
-// std::cout << cd << "\n"; // Outputs: 2015-02-03
-//
-// civil_year cy(cs);
-// std::cout << cy << "\n"; // Outputs: 2015
-//
-// ARITHMETIC:
-//
-// Civil-time types support natural arithmetic operators such as addition,
-// subtraction, and difference. Arithmetic operates on the civil-time field
-// indicated in the type's name. Difference requires arguments with the same
-// alignment and returns the answer in units of the alignment.
-//
-// civil_day a(2015, 2, 3);
-// ++a; // 2015-02-04 00:00:00
-// --a; // 2015-02-03 00:00:00
-// civil_day b = a + 1; // 2015-02-04 00:00:00
-// civil_day c = 1 + b; // 2015-02-05 00:00:00
-// int n = c - a; // n = 2 (civil days)
-// int m = c - civil_month(c); // Won't compile: different types.
-//
-// EXAMPLE: Adding a month to January 31.
-//
-// One of the classic questions that arises when considering a civil-time
-// library (or a date library or a date/time library) is this: "What happens
-// when you add a month to January 31?" This is an interesting question
-// because there could be a number of possible answers:
-//
-// 1. March 3 (or 2 if a leap year). This may make sense if the operation
-// wants the equivalent of February 31.
-// 2. February 28 (or 29 if a leap year). This may make sense if the operation
-// wants the last day of January to go to the last day of February.
-// 3. Error. The caller may get some error, an exception, an invalid date
-// object, or maybe false is returned. This may make sense because there is
-// no single unambiguously correct answer to the question.
-//
-// Practically speaking, any answer that is not what the programmer intended
-// is the wrong answer.
-//
-// This civil-time library avoids the problem by making it impossible to ask
-// ambiguous questions. All civil-time objects are aligned to a particular
-// civil-field boundary (such as aligned to a year, month, day, hour, minute,
-// or second), and arithmetic operates on the field to which the object is
-// aligned. This means that in order to "add a month" the object must first be
-// aligned to a month boundary, which is equivalent to the first day of that
-// month.
-//
-// Of course, there are ways to compute an answer the question at hand using
-// this civil-time library, but they require the programmer to be explicit
-// about the answer they expect. To illustrate, let's see how to compute all
-// three of the above possible answers to the question of "Jan 31 plus 1
-// month":
-//
-// const civil_day d(2015, 1, 31);
-//
-// // Answer 1:
-// // Add 1 to the month field in the constructor, and rely on normalization.
-// const auto ans_normalized = civil_day(d.year(), d.month() + 1, d.day());
-// // ans_normalized == 2015-03-03 (aka Feb 31)
-//
-// // Answer 2:
-// // Add 1 to month field, capping to the end of next month.
-// const auto next_month = civil_month(d) + 1;
-// const auto last_day_of_next_month = civil_day(next_month + 1) - 1;
-// const auto ans_capped = std::min(ans_normalized, last_day_of_next_month);
-// // ans_capped == 2015-02-28
-//
-// // Answer 3:
-// // Signal an error if the normalized answer is not in next month.
-// if (civil_month(ans_normalized) != next_month) {
-// // error, month overflow
-// }
-//
-using civil_year = detail::civil_year;
-using civil_month = detail::civil_month;
-using civil_day = detail::civil_day;
-using civil_hour = detail::civil_hour;
-using civil_minute = detail::civil_minute;
-using civil_second = detail::civil_second;
-
-// An enum class with members monday, tuesday, wednesday, thursday, friday,
-// saturday, and sunday. These enum values may be sent to an output stream
-// using operator<<(). The result is the full weekday name in English with a
-// leading capital letter.
-//
-// weekday wd = weekday::thursday;
-// std::cout << wd << "\n"; // Outputs: Thursday
-//
-using detail::weekday;
-
+//
+// civil_day d(2015, 6, 28);
+// // d.year() == 2015
+// // d.month() == 6
+// // d.day() == 28
+// // d.hour() == 0
+// // d.minute() == 0
+// // d.second() == 0
+//
+// COMPARISON:
+//
+// Comparison always considers all six YMDHMS fields, regardless of the type's
+// alignment. Comparison between differently aligned civil-time types is
+// allowed.
+//
+// civil_day feb_3(2015, 2, 3); // 2015-02-03 00:00:00
+// civil_day mar_4(2015, 3, 4); // 2015-03-04 00:00:00
+// // feb_3 < mar_4
+// // civil_year(feb_3) == civil_year(mar_4)
+//
+// civil_second feb_3_noon(2015, 2, 3, 12, 0, 0); // 2015-02-03 12:00:00
+// // feb_3 < feb_3_noon
+// // feb_3 == civil_day(feb_3_noon)
+//
+// // Iterates all the days of February 2015.
+// for (civil_day d(2015, 2, 1); d < civil_month(2015, 3); ++d) {
+// // ...
+// }
+//
+// STREAMING:
+//
+// Each civil-time type may be sent to an output stream using operator<<().
+// The output format follows the pattern "YYYY-MM-DDThh:mm:ss" where fields
+// inferior to the type's alignment are omitted.
+//
+// civil_second cs(2015, 2, 3, 4, 5, 6);
+// std::cout << cs << "\n"; // Outputs: 2015-02-03T04:05:06
+//
+// civil_day cd(cs);
+// std::cout << cd << "\n"; // Outputs: 2015-02-03
+//
+// civil_year cy(cs);
+// std::cout << cy << "\n"; // Outputs: 2015
+//
+// ARITHMETIC:
+//
+// Civil-time types support natural arithmetic operators such as addition,
+// subtraction, and difference. Arithmetic operates on the civil-time field
+// indicated in the type's name. Difference requires arguments with the same
+// alignment and returns the answer in units of the alignment.
+//
+// civil_day a(2015, 2, 3);
+// ++a; // 2015-02-04 00:00:00
+// --a; // 2015-02-03 00:00:00
+// civil_day b = a + 1; // 2015-02-04 00:00:00
+// civil_day c = 1 + b; // 2015-02-05 00:00:00
+// int n = c - a; // n = 2 (civil days)
+// int m = c - civil_month(c); // Won't compile: different types.
+//
+// EXAMPLE: Adding a month to January 31.
+//
+// One of the classic questions that arises when considering a civil-time
+// library (or a date library or a date/time library) is this: "What happens
+// when you add a month to January 31?" This is an interesting question
+// because there could be a number of possible answers:
+//
+// 1. March 3 (or 2 if a leap year). This may make sense if the operation
+// wants the equivalent of February 31.
+// 2. February 28 (or 29 if a leap year). This may make sense if the operation
+// wants the last day of January to go to the last day of February.
+// 3. Error. The caller may get some error, an exception, an invalid date
+// object, or maybe false is returned. This may make sense because there is
+// no single unambiguously correct answer to the question.
+//
+// Practically speaking, any answer that is not what the programmer intended
+// is the wrong answer.
+//
+// This civil-time library avoids the problem by making it impossible to ask
+// ambiguous questions. All civil-time objects are aligned to a particular
+// civil-field boundary (such as aligned to a year, month, day, hour, minute,
+// or second), and arithmetic operates on the field to which the object is
+// aligned. This means that in order to "add a month" the object must first be
+// aligned to a month boundary, which is equivalent to the first day of that
+// month.
+//
+// Of course, there are ways to compute an answer the question at hand using
+// this civil-time library, but they require the programmer to be explicit
+// about the answer they expect. To illustrate, let's see how to compute all
+// three of the above possible answers to the question of "Jan 31 plus 1
+// month":
+//
+// const civil_day d(2015, 1, 31);
+//
+// // Answer 1:
+// // Add 1 to the month field in the constructor, and rely on normalization.
+// const auto ans_normalized = civil_day(d.year(), d.month() + 1, d.day());
+// // ans_normalized == 2015-03-03 (aka Feb 31)
+//
+// // Answer 2:
+// // Add 1 to month field, capping to the end of next month.
+// const auto next_month = civil_month(d) + 1;
+// const auto last_day_of_next_month = civil_day(next_month + 1) - 1;
+// const auto ans_capped = std::min(ans_normalized, last_day_of_next_month);
+// // ans_capped == 2015-02-28
+//
+// // Answer 3:
+// // Signal an error if the normalized answer is not in next month.
+// if (civil_month(ans_normalized) != next_month) {
+// // error, month overflow
+// }
+//
+using civil_year = detail::civil_year;
+using civil_month = detail::civil_month;
+using civil_day = detail::civil_day;
+using civil_hour = detail::civil_hour;
+using civil_minute = detail::civil_minute;
+using civil_second = detail::civil_second;
+
+// An enum class with members monday, tuesday, wednesday, thursday, friday,
+// saturday, and sunday. These enum values may be sent to an output stream
+// using operator<<(). The result is the full weekday name in English with a
+// leading capital letter.
+//
+// weekday wd = weekday::thursday;
+// std::cout << wd << "\n"; // Outputs: Thursday
+//
+using detail::weekday;
+
// Returns the weekday for the given civil-time value.
-//
-// civil_day a(2015, 8, 13);
-// weekday wd = get_weekday(a); // wd == weekday::thursday
-//
-using detail::get_weekday;
-
-// Returns the civil_day that strictly follows or precedes the given
-// civil_day, and that falls on the given weekday.
-//
-// For example, given:
-//
-// August 2015
-// Su Mo Tu We Th Fr Sa
-// 1
-// 2 3 4 5 6 7 8
-// 9 10 11 12 13 14 15
-// 16 17 18 19 20 21 22
-// 23 24 25 26 27 28 29
-// 30 31
-//
-// civil_day a(2015, 8, 13); // get_weekday(a) == weekday::thursday
-// civil_day b = next_weekday(a, weekday::thursday); // b = 2015-08-20
-// civil_day c = prev_weekday(a, weekday::thursday); // c = 2015-08-06
-//
-// civil_day d = ...
-// // Gets the following Thursday if d is not already Thursday
+//
+// civil_day a(2015, 8, 13);
+// weekday wd = get_weekday(a); // wd == weekday::thursday
+//
+using detail::get_weekday;
+
+// Returns the civil_day that strictly follows or precedes the given
+// civil_day, and that falls on the given weekday.
+//
+// For example, given:
+//
+// August 2015
+// Su Mo Tu We Th Fr Sa
+// 1
+// 2 3 4 5 6 7 8
+// 9 10 11 12 13 14 15
+// 16 17 18 19 20 21 22
+// 23 24 25 26 27 28 29
+// 30 31
+//
+// civil_day a(2015, 8, 13); // get_weekday(a) == weekday::thursday
+// civil_day b = next_weekday(a, weekday::thursday); // b = 2015-08-20
+// civil_day c = prev_weekday(a, weekday::thursday); // c = 2015-08-06
+//
+// civil_day d = ...
+// // Gets the following Thursday if d is not already Thursday
// civil_day thurs1 = next_weekday(d - 1, weekday::thursday);
-// // Gets the previous Thursday if d is not already Thursday
+// // Gets the previous Thursday if d is not already Thursday
// civil_day thurs2 = prev_weekday(d + 1, weekday::thursday);
-//
-using detail::next_weekday;
-using detail::prev_weekday;
-
+//
+using detail::next_weekday;
+using detail::prev_weekday;
+
// 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
-// civil_day b(2015, 12, 31);
-// int yd_dec_31 = get_yearday(b); // yd_dec_31 = 365
-//
-using detail::get_yearday;
-
-} // namespace cctz
-
-#endif // CCTZ_CIVIL_TIME_H_
+//
+// civil_day a(2015, 1, 1);
+// int yd_jan_1 = get_yearday(a); // yd_jan_1 = 1
+// civil_day b(2015, 12, 31);
+// int yd_dec_31 = get_yearday(b); // yd_dec_31 = 365
+//
+using detail::get_yearday;
+
+} // namespace cctz
+
+#endif // CCTZ_CIVIL_TIME_H_
diff --git a/contrib/libs/cctz/include/cctz/civil_time_detail.h b/contrib/libs/cctz/include/cctz/civil_time_detail.h
index ea1a1dc276..22d958b3cf 100644
--- a/contrib/libs/cctz/include/cctz/civil_time_detail.h
+++ b/contrib/libs/cctz/include/cctz/civil_time_detail.h
@@ -1,528 +1,528 @@
-// 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
-//
+// 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.
-
-#ifndef CCTZ_CIVIL_TIME_DETAIL_H_
-#define CCTZ_CIVIL_TIME_DETAIL_H_
-
-#include <cstdint>
-#include <limits>
-#include <ostream>
-#include <type_traits>
-
+//
+// 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.
+
+#ifndef CCTZ_CIVIL_TIME_DETAIL_H_
+#define CCTZ_CIVIL_TIME_DETAIL_H_
+
+#include <cstdint>
+#include <limits>
+#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)
-#define CONSTEXPR_D constexpr // data
-#define CONSTEXPR_F constexpr // function
-#define CONSTEXPR_M constexpr // member
-#else
-#define CONSTEXPR_D const
-#define CONSTEXPR_F inline
-#define CONSTEXPR_M
-#endif
-
-namespace cctz {
-
-// Support years that at least span the range of 64-bit time_t values.
-using year_t = std::int_fast64_t;
-
-// Type alias that indicates an argument is not normalized (e.g., the
-// constructor parameters and operands/results of addition/subtraction).
-using diff_t = std::int_fast64_t;
-
-namespace detail {
-
-// Type aliases that indicate normalized argument values.
-using month_t = std::int_fast8_t; // [1:12]
-using day_t = std::int_fast8_t; // [1:31]
-using hour_t = std::int_fast8_t; // [0:23]
-using minute_t = std::int_fast8_t; // [0:59]
-using second_t = std::int_fast8_t; // [0:59]
-
-// Normalized civil-time fields: Y-M-D HH:MM:SS.
-struct fields {
- CONSTEXPR_M fields(year_t year, month_t month, day_t day,
- hour_t hour, minute_t minute, second_t second)
- : y(year), m(month), d(day), hh(hour), mm(minute), ss(second) {}
- std::int_least64_t y;
- std::int_least8_t m;
- std::int_least8_t d;
- std::int_least8_t hh;
- std::int_least8_t mm;
- std::int_least8_t ss;
-};
-
-struct second_tag {};
-struct minute_tag : second_tag {};
-struct hour_tag : minute_tag {};
-struct day_tag : hour_tag {};
-struct month_tag : day_tag {};
-struct year_tag : month_tag {};
-
-////////////////////////////////////////////////////////////////////////
-
-// Field normalization (without avoidable overflow).
-
-namespace impl {
-
-CONSTEXPR_F bool is_leap_year(year_t y) noexcept {
- return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
-}
-CONSTEXPR_F int year_index(year_t y, month_t m) noexcept {
- return (static_cast<int>((y + (m > 2)) % 400) + 400) % 400;
-}
-CONSTEXPR_F int days_per_century(year_t y, month_t m) noexcept {
- const int yi = year_index(y, m);
- return 36524 + (yi == 0 || yi > 300);
-}
-CONSTEXPR_F int days_per_4years(year_t y, month_t m) noexcept {
- const int yi = year_index(y, m);
- return 1460 + (yi == 0 || yi > 300 || (yi - 1) % 100 < 96);
-}
-CONSTEXPR_F int days_per_year(year_t y, month_t m) noexcept {
- return is_leap_year(y + (m > 2)) ? 366 : 365;
-}
-CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept {
- CONSTEXPR_D int k_days_per_month[1 + 12] = {
- -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // non leap year
- };
- return k_days_per_month[m] + (m == 2 && is_leap_year(y));
-}
-
-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 {
+#define CONSTEXPR_D constexpr // data
+#define CONSTEXPR_F constexpr // function
+#define CONSTEXPR_M constexpr // member
+#else
+#define CONSTEXPR_D const
+#define CONSTEXPR_F inline
+#define CONSTEXPR_M
+#endif
+
+namespace cctz {
+
+// Support years that at least span the range of 64-bit time_t values.
+using year_t = std::int_fast64_t;
+
+// Type alias that indicates an argument is not normalized (e.g., the
+// constructor parameters and operands/results of addition/subtraction).
+using diff_t = std::int_fast64_t;
+
+namespace detail {
+
+// Type aliases that indicate normalized argument values.
+using month_t = std::int_fast8_t; // [1:12]
+using day_t = std::int_fast8_t; // [1:31]
+using hour_t = std::int_fast8_t; // [0:23]
+using minute_t = std::int_fast8_t; // [0:59]
+using second_t = std::int_fast8_t; // [0:59]
+
+// Normalized civil-time fields: Y-M-D HH:MM:SS.
+struct fields {
+ CONSTEXPR_M fields(year_t year, month_t month, day_t day,
+ hour_t hour, minute_t minute, second_t second)
+ : y(year), m(month), d(day), hh(hour), mm(minute), ss(second) {}
+ std::int_least64_t y;
+ std::int_least8_t m;
+ std::int_least8_t d;
+ std::int_least8_t hh;
+ std::int_least8_t mm;
+ std::int_least8_t ss;
+};
+
+struct second_tag {};
+struct minute_tag : second_tag {};
+struct hour_tag : minute_tag {};
+struct day_tag : hour_tag {};
+struct month_tag : day_tag {};
+struct year_tag : month_tag {};
+
+////////////////////////////////////////////////////////////////////////
+
+// Field normalization (without avoidable overflow).
+
+namespace impl {
+
+CONSTEXPR_F bool is_leap_year(year_t y) noexcept {
+ return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0);
+}
+CONSTEXPR_F int year_index(year_t y, month_t m) noexcept {
+ return (static_cast<int>((y + (m > 2)) % 400) + 400) % 400;
+}
+CONSTEXPR_F int days_per_century(year_t y, month_t m) noexcept {
+ const int yi = year_index(y, m);
+ return 36524 + (yi == 0 || yi > 300);
+}
+CONSTEXPR_F int days_per_4years(year_t y, month_t m) noexcept {
+ const int yi = year_index(y, m);
+ return 1460 + (yi == 0 || yi > 300 || (yi - 1) % 100 < 96);
+}
+CONSTEXPR_F int days_per_year(year_t y, month_t m) noexcept {
+ return is_leap_year(y + (m > 2)) ? 366 : 365;
+}
+CONSTEXPR_F int days_per_month(year_t y, month_t m) noexcept {
+ CONSTEXPR_D int k_days_per_month[1 + 12] = {
+ -1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // non leap year
+ };
+ return k_days_per_month[m] + (m == 2 && is_leap_year(y));
+}
+
+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;
- cd %= 146097;
- if (cd < 0) {
+ cd %= 146097;
+ if (cd < 0) {
ey -= 400;
- cd += 146097;
- }
+ cd += 146097;
+ }
ey += (d / 146097) * 400;
- d = d % 146097 + cd;
- if (d > 0) {
- if (d > 146097) {
+ d = d % 146097 + cd;
+ if (d > 0) {
+ if (d > 146097) {
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.
+ 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);
- } else {
+ } else {
ey -= 400;
- d += 146097;
- }
- }
- if (d > 365) {
+ d += 146097;
+ }
+ }
+ if (d > 365) {
for (;;) {
int n = days_per_century(ey, m);
if (d <= n) break;
- d -= n;
+ d -= n;
ey += 100;
- }
+ }
for (;;) {
int n = days_per_4years(ey, m);
if (d <= n) break;
- d -= n;
+ d -= n;
ey += 4;
- }
+ }
for (;;) {
int n = days_per_year(ey, m);
if (d <= n) break;
- d -= n;
+ d -= n;
++ey;
- }
- }
- if (d > 28) {
+ }
+ }
+ if (d > 28) {
for (;;) {
int n = days_per_month(ey, m);
if (d <= n) break;
- d -= n;
- if (++m > 12) {
+ d -= n;
+ if (++m > 12) {
++ey;
- m = 1;
- }
- }
- }
+ m = 1;
+ }
+ }
+ }
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 {
- if (m != 12) {
- y += m / 12;
- m %= 12;
- if (m <= 0) {
- y -= 1;
- m += 12;
- }
- }
- return n_day(y, static_cast<month_t>(m), d, cd, hh, mm, ss);
-}
-CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd,
- diff_t hh, minute_t mm, second_t ss) noexcept {
- cd += hh / 24;
- hh %= 24;
- if (hh < 0) {
- cd -= 1;
- hh += 24;
- }
- return n_mon(y, m, d, cd, static_cast<hour_t>(hh), mm, ss);
-}
-CONSTEXPR_F fields n_min(year_t y, diff_t m, diff_t d, diff_t hh, diff_t ch,
- diff_t mm, second_t ss) noexcept {
- ch += mm / 60;
- mm %= 60;
- if (mm < 0) {
- ch -= 1;
- mm += 60;
- }
- return n_hour(y, m, d, hh / 24 + ch / 24, hh % 24 + ch % 24,
- static_cast<minute_t>(mm), ss);
-}
-CONSTEXPR_F fields n_sec(year_t y, diff_t m, diff_t d, diff_t hh, diff_t mm,
- diff_t ss) noexcept {
- // Optimization for when (non-constexpr) fields are already normalized.
- if (0 <= ss && ss < 60) {
- const second_t nss = static_cast<second_t>(ss);
- if (0 <= mm && mm < 60) {
- const minute_t nmm = static_cast<minute_t>(mm);
- if (0 <= hh && hh < 24) {
- const hour_t nhh = static_cast<hour_t>(hh);
- if (1 <= d && d <= 28 && 1 <= m && m <= 12) {
- const day_t nd = static_cast<day_t>(d);
- const month_t nm = static_cast<month_t>(m);
- return fields(y, nm, nd, nhh, nmm, nss);
- }
- return n_mon(y, m, d, 0, nhh, nmm, nss);
- }
- return n_hour(y, m, d, hh / 24, hh % 24, nmm, nss);
- }
- return n_min(y, m, d, hh, mm / 60, mm % 60, nss);
- }
- diff_t cm = ss / 60;
- ss %= 60;
- if (ss < 0) {
- cm -= 1;
- ss += 60;
- }
- return n_min(y, m, d, hh, mm / 60 + cm / 60, mm % 60 + cm % 60,
- static_cast<second_t>(ss));
-}
-
-} // namespace impl
-
-////////////////////////////////////////////////////////////////////////
-
-// Increments the indicated (normalized) field by "n".
-CONSTEXPR_F fields step(second_tag, fields f, diff_t n) noexcept {
- return impl::n_sec(f.y, f.m, f.d, f.hh, f.mm + n / 60, f.ss + n % 60);
-}
-CONSTEXPR_F fields step(minute_tag, fields f, diff_t n) noexcept {
- return impl::n_min(f.y, f.m, f.d, f.hh + n / 60, 0, f.mm + n % 60, f.ss);
-}
-CONSTEXPR_F fields step(hour_tag, fields f, diff_t n) noexcept {
- return impl::n_hour(f.y, f.m, f.d + n / 24, 0, f.hh + n % 24, f.mm, f.ss);
-}
-CONSTEXPR_F fields step(day_tag, fields f, diff_t n) noexcept {
- return impl::n_day(f.y, f.m, f.d, n, f.hh, f.mm, f.ss);
-}
-CONSTEXPR_F fields step(month_tag, fields f, diff_t n) noexcept {
- return impl::n_mon(f.y + n / 12, f.m + n % 12, f.d, 0, f.hh, f.mm, f.ss);
-}
-CONSTEXPR_F fields step(year_tag, fields f, diff_t n) noexcept {
- return fields(f.y + n, f.m, f.d, f.hh, f.mm, f.ss);
-}
-
-////////////////////////////////////////////////////////////////////////
-
-namespace impl {
-
-// Returns (v * f + a) but avoiding intermediate overflow when possible.
-CONSTEXPR_F diff_t scale_add(diff_t v, diff_t f, diff_t a) noexcept {
- return (v < 0) ? ((v + 1) * f + a) - f : ((v - 1) * f + a) + f;
-}
-
-// Map a (normalized) Y/M/D to the number of days before/after 1970-01-01.
-// Probably overflows for years outside [-292277022656:292277026595].
-CONSTEXPR_F diff_t ymd_ord(year_t y, month_t m, day_t d) noexcept {
- const diff_t eyear = (m <= 2) ? y - 1 : y;
- const diff_t era = (eyear >= 0 ? eyear : eyear - 399) / 400;
- const diff_t yoe = eyear - era * 400;
- const diff_t doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;
- const diff_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
- return era * 146097 + doe - 719468;
-}
-
-// Returns the difference in days between two normalized Y-M-D tuples.
-// ymd_ord() will encounter integer overflow given extreme year values,
-// yet the difference between two such extreme values may actually be
-// small, so we take a little care to avoid overflow when possible by
-// exploiting the 146097-day cycle.
-CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1,
- year_t y2, month_t m2, day_t d2) noexcept {
- const diff_t a_c4_off = y1 % 400;
- const diff_t b_c4_off = y2 % 400;
- diff_t c4_diff = (y1 - a_c4_off) - (y2 - b_c4_off);
- diff_t delta = ymd_ord(a_c4_off, m1, d1) - ymd_ord(b_c4_off, m2, d2);
- if (c4_diff > 0 && delta < 0) {
- delta += 2 * 146097;
- c4_diff -= 2 * 400;
- } else if (c4_diff < 0 && delta > 0) {
- delta -= 2 * 146097;
- c4_diff += 2 * 400;
- }
- return (c4_diff / 400 * 146097) + delta;
-}
-
-} // namespace impl
-
-// Returns the difference between fields structs using the indicated unit.
-CONSTEXPR_F diff_t difference(year_tag, fields f1, fields f2) noexcept {
- return f1.y - f2.y;
-}
-CONSTEXPR_F diff_t difference(month_tag, fields f1, fields f2) noexcept {
- return impl::scale_add(difference(year_tag{}, f1, f2), 12, (f1.m - f2.m));
-}
-CONSTEXPR_F diff_t difference(day_tag, fields f1, fields f2) noexcept {
- return impl::day_difference(f1.y, f1.m, f1.d, f2.y, f2.m, f2.d);
-}
-CONSTEXPR_F diff_t difference(hour_tag, fields f1, fields f2) noexcept {
- return impl::scale_add(difference(day_tag{}, f1, f2), 24, (f1.hh - f2.hh));
-}
-CONSTEXPR_F diff_t difference(minute_tag, fields f1, fields f2) noexcept {
- return impl::scale_add(difference(hour_tag{}, f1, f2), 60, (f1.mm - f2.mm));
-}
-CONSTEXPR_F diff_t difference(second_tag, fields f1, fields f2) noexcept {
- return impl::scale_add(difference(minute_tag{}, f1, f2), 60, f1.ss - f2.ss);
-}
-
-////////////////////////////////////////////////////////////////////////
-
-// Aligns the (normalized) fields struct to the indicated field.
-CONSTEXPR_F fields align(second_tag, fields f) noexcept {
- return f;
-}
-CONSTEXPR_F fields align(minute_tag, fields f) noexcept {
- return fields{f.y, f.m, f.d, f.hh, f.mm, 0};
-}
-CONSTEXPR_F fields align(hour_tag, fields f) noexcept {
- return fields{f.y, f.m, f.d, f.hh, 0, 0};
-}
-CONSTEXPR_F fields align(day_tag, fields f) noexcept {
- return fields{f.y, f.m, f.d, 0, 0, 0};
-}
-CONSTEXPR_F fields align(month_tag, fields f) noexcept {
- return fields{f.y, f.m, 1, 0, 0, 0};
-}
-CONSTEXPR_F fields align(year_tag, fields f) noexcept {
- return fields{f.y, 1, 1, 0, 0, 0};
-}
-
-////////////////////////////////////////////////////////////////////////
-
-template <typename T>
-class civil_time {
- public:
- explicit CONSTEXPR_M civil_time(year_t y, diff_t m = 1, diff_t d = 1,
- diff_t hh = 0, diff_t mm = 0,
- diff_t ss = 0) noexcept
- : civil_time(impl::n_sec(y, m, d, hh, mm, ss)) {}
-
- CONSTEXPR_M civil_time() noexcept : f_{1970, 1, 1, 0, 0, 0} {}
- civil_time(const civil_time&) = default;
- civil_time& operator=(const civil_time&) = default;
-
- // Conversion between civil times of different alignment. Conversion to
- // a more precise alignment is allowed implicitly (e.g., day -> hour),
- // but conversion where information is discarded must be explicit
- // (e.g., second -> minute).
- template <typename U, typename S>
- using preserves_data =
- typename std::enable_if<std::is_base_of<U, S>::value>::type;
- template <typename U>
- CONSTEXPR_M civil_time(const civil_time<U>& ct,
- preserves_data<T, U>* = nullptr) noexcept
- : civil_time(ct.f_) {}
- template <typename U>
- explicit CONSTEXPR_M civil_time(const civil_time<U>& ct,
- preserves_data<U, T>* = nullptr) noexcept
- : civil_time(ct.f_) {}
-
- // Factories for the maximum/minimum representable civil_time.
+}
+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 {
+ if (m != 12) {
+ y += m / 12;
+ m %= 12;
+ if (m <= 0) {
+ y -= 1;
+ m += 12;
+ }
+ }
+ return n_day(y, static_cast<month_t>(m), d, cd, hh, mm, ss);
+}
+CONSTEXPR_F fields n_hour(year_t y, diff_t m, diff_t d, diff_t cd,
+ diff_t hh, minute_t mm, second_t ss) noexcept {
+ cd += hh / 24;
+ hh %= 24;
+ if (hh < 0) {
+ cd -= 1;
+ hh += 24;
+ }
+ return n_mon(y, m, d, cd, static_cast<hour_t>(hh), mm, ss);
+}
+CONSTEXPR_F fields n_min(year_t y, diff_t m, diff_t d, diff_t hh, diff_t ch,
+ diff_t mm, second_t ss) noexcept {
+ ch += mm / 60;
+ mm %= 60;
+ if (mm < 0) {
+ ch -= 1;
+ mm += 60;
+ }
+ return n_hour(y, m, d, hh / 24 + ch / 24, hh % 24 + ch % 24,
+ static_cast<minute_t>(mm), ss);
+}
+CONSTEXPR_F fields n_sec(year_t y, diff_t m, diff_t d, diff_t hh, diff_t mm,
+ diff_t ss) noexcept {
+ // Optimization for when (non-constexpr) fields are already normalized.
+ if (0 <= ss && ss < 60) {
+ const second_t nss = static_cast<second_t>(ss);
+ if (0 <= mm && mm < 60) {
+ const minute_t nmm = static_cast<minute_t>(mm);
+ if (0 <= hh && hh < 24) {
+ const hour_t nhh = static_cast<hour_t>(hh);
+ if (1 <= d && d <= 28 && 1 <= m && m <= 12) {
+ const day_t nd = static_cast<day_t>(d);
+ const month_t nm = static_cast<month_t>(m);
+ return fields(y, nm, nd, nhh, nmm, nss);
+ }
+ return n_mon(y, m, d, 0, nhh, nmm, nss);
+ }
+ return n_hour(y, m, d, hh / 24, hh % 24, nmm, nss);
+ }
+ return n_min(y, m, d, hh, mm / 60, mm % 60, nss);
+ }
+ diff_t cm = ss / 60;
+ ss %= 60;
+ if (ss < 0) {
+ cm -= 1;
+ ss += 60;
+ }
+ return n_min(y, m, d, hh, mm / 60 + cm / 60, mm % 60 + cm % 60,
+ static_cast<second_t>(ss));
+}
+
+} // namespace impl
+
+////////////////////////////////////////////////////////////////////////
+
+// Increments the indicated (normalized) field by "n".
+CONSTEXPR_F fields step(second_tag, fields f, diff_t n) noexcept {
+ return impl::n_sec(f.y, f.m, f.d, f.hh, f.mm + n / 60, f.ss + n % 60);
+}
+CONSTEXPR_F fields step(minute_tag, fields f, diff_t n) noexcept {
+ return impl::n_min(f.y, f.m, f.d, f.hh + n / 60, 0, f.mm + n % 60, f.ss);
+}
+CONSTEXPR_F fields step(hour_tag, fields f, diff_t n) noexcept {
+ return impl::n_hour(f.y, f.m, f.d + n / 24, 0, f.hh + n % 24, f.mm, f.ss);
+}
+CONSTEXPR_F fields step(day_tag, fields f, diff_t n) noexcept {
+ return impl::n_day(f.y, f.m, f.d, n, f.hh, f.mm, f.ss);
+}
+CONSTEXPR_F fields step(month_tag, fields f, diff_t n) noexcept {
+ return impl::n_mon(f.y + n / 12, f.m + n % 12, f.d, 0, f.hh, f.mm, f.ss);
+}
+CONSTEXPR_F fields step(year_tag, fields f, diff_t n) noexcept {
+ return fields(f.y + n, f.m, f.d, f.hh, f.mm, f.ss);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+namespace impl {
+
+// Returns (v * f + a) but avoiding intermediate overflow when possible.
+CONSTEXPR_F diff_t scale_add(diff_t v, diff_t f, diff_t a) noexcept {
+ return (v < 0) ? ((v + 1) * f + a) - f : ((v - 1) * f + a) + f;
+}
+
+// Map a (normalized) Y/M/D to the number of days before/after 1970-01-01.
+// Probably overflows for years outside [-292277022656:292277026595].
+CONSTEXPR_F diff_t ymd_ord(year_t y, month_t m, day_t d) noexcept {
+ const diff_t eyear = (m <= 2) ? y - 1 : y;
+ const diff_t era = (eyear >= 0 ? eyear : eyear - 399) / 400;
+ const diff_t yoe = eyear - era * 400;
+ const diff_t doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1;
+ const diff_t doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
+ return era * 146097 + doe - 719468;
+}
+
+// Returns the difference in days between two normalized Y-M-D tuples.
+// ymd_ord() will encounter integer overflow given extreme year values,
+// yet the difference between two such extreme values may actually be
+// small, so we take a little care to avoid overflow when possible by
+// exploiting the 146097-day cycle.
+CONSTEXPR_F diff_t day_difference(year_t y1, month_t m1, day_t d1,
+ year_t y2, month_t m2, day_t d2) noexcept {
+ const diff_t a_c4_off = y1 % 400;
+ const diff_t b_c4_off = y2 % 400;
+ diff_t c4_diff = (y1 - a_c4_off) - (y2 - b_c4_off);
+ diff_t delta = ymd_ord(a_c4_off, m1, d1) - ymd_ord(b_c4_off, m2, d2);
+ if (c4_diff > 0 && delta < 0) {
+ delta += 2 * 146097;
+ c4_diff -= 2 * 400;
+ } else if (c4_diff < 0 && delta > 0) {
+ delta -= 2 * 146097;
+ c4_diff += 2 * 400;
+ }
+ return (c4_diff / 400 * 146097) + delta;
+}
+
+} // namespace impl
+
+// Returns the difference between fields structs using the indicated unit.
+CONSTEXPR_F diff_t difference(year_tag, fields f1, fields f2) noexcept {
+ return f1.y - f2.y;
+}
+CONSTEXPR_F diff_t difference(month_tag, fields f1, fields f2) noexcept {
+ return impl::scale_add(difference(year_tag{}, f1, f2), 12, (f1.m - f2.m));
+}
+CONSTEXPR_F diff_t difference(day_tag, fields f1, fields f2) noexcept {
+ return impl::day_difference(f1.y, f1.m, f1.d, f2.y, f2.m, f2.d);
+}
+CONSTEXPR_F diff_t difference(hour_tag, fields f1, fields f2) noexcept {
+ return impl::scale_add(difference(day_tag{}, f1, f2), 24, (f1.hh - f2.hh));
+}
+CONSTEXPR_F diff_t difference(minute_tag, fields f1, fields f2) noexcept {
+ return impl::scale_add(difference(hour_tag{}, f1, f2), 60, (f1.mm - f2.mm));
+}
+CONSTEXPR_F diff_t difference(second_tag, fields f1, fields f2) noexcept {
+ return impl::scale_add(difference(minute_tag{}, f1, f2), 60, f1.ss - f2.ss);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+// Aligns the (normalized) fields struct to the indicated field.
+CONSTEXPR_F fields align(second_tag, fields f) noexcept {
+ return f;
+}
+CONSTEXPR_F fields align(minute_tag, fields f) noexcept {
+ return fields{f.y, f.m, f.d, f.hh, f.mm, 0};
+}
+CONSTEXPR_F fields align(hour_tag, fields f) noexcept {
+ return fields{f.y, f.m, f.d, f.hh, 0, 0};
+}
+CONSTEXPR_F fields align(day_tag, fields f) noexcept {
+ return fields{f.y, f.m, f.d, 0, 0, 0};
+}
+CONSTEXPR_F fields align(month_tag, fields f) noexcept {
+ return fields{f.y, f.m, 1, 0, 0, 0};
+}
+CONSTEXPR_F fields align(year_tag, fields f) noexcept {
+ return fields{f.y, 1, 1, 0, 0, 0};
+}
+
+////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+class civil_time {
+ public:
+ explicit CONSTEXPR_M civil_time(year_t y, diff_t m = 1, diff_t d = 1,
+ diff_t hh = 0, diff_t mm = 0,
+ diff_t ss = 0) noexcept
+ : civil_time(impl::n_sec(y, m, d, hh, mm, ss)) {}
+
+ CONSTEXPR_M civil_time() noexcept : f_{1970, 1, 1, 0, 0, 0} {}
+ civil_time(const civil_time&) = default;
+ civil_time& operator=(const civil_time&) = default;
+
+ // Conversion between civil times of different alignment. Conversion to
+ // a more precise alignment is allowed implicitly (e.g., day -> hour),
+ // but conversion where information is discarded must be explicit
+ // (e.g., second -> minute).
+ template <typename U, typename S>
+ using preserves_data =
+ typename std::enable_if<std::is_base_of<U, S>::value>::type;
+ template <typename U>
+ CONSTEXPR_M civil_time(const civil_time<U>& ct,
+ preserves_data<T, U>* = nullptr) noexcept
+ : civil_time(ct.f_) {}
+ template <typename U>
+ explicit CONSTEXPR_M civil_time(const civil_time<U>& ct,
+ preserves_data<U, T>* = nullptr) noexcept
+ : 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)();
- return civil_time(max_year, 12, 31, 23, 59, 59);
- }
+ 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)();
- return civil_time(min_year, 1, 1, 0, 0, 0);
- }
-
- // Field accessors. Note: All but year() return an int.
- CONSTEXPR_M year_t year() const noexcept { return f_.y; }
- CONSTEXPR_M int month() const noexcept { return f_.m; }
- CONSTEXPR_M int day() const noexcept { return f_.d; }
- CONSTEXPR_M int hour() const noexcept { return f_.hh; }
- CONSTEXPR_M int minute() const noexcept { return f_.mm; }
- CONSTEXPR_M int second() const noexcept { return f_.ss; }
-
- // Assigning arithmetic.
- CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept {
+ return civil_time(min_year, 1, 1, 0, 0, 0);
+ }
+
+ // Field accessors. Note: All but year() return an int.
+ CONSTEXPR_M year_t year() const noexcept { return f_.y; }
+ CONSTEXPR_M int month() const noexcept { return f_.m; }
+ CONSTEXPR_M int day() const noexcept { return f_.d; }
+ CONSTEXPR_M int hour() const noexcept { return f_.hh; }
+ CONSTEXPR_M int minute() const noexcept { return f_.mm; }
+ CONSTEXPR_M int second() const noexcept { return f_.ss; }
+
+ // Assigning arithmetic.
+ CONSTEXPR_M civil_time& operator+=(diff_t n) noexcept {
return *this = *this + n;
- }
- CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
+ }
+ CONSTEXPR_M civil_time& operator-=(diff_t n) noexcept {
return *this = *this - n;
- }
- CONSTEXPR_M civil_time& operator++() noexcept {
- return *this += 1;
- }
- CONSTEXPR_M civil_time operator++(int) noexcept {
- const civil_time a = *this;
- ++*this;
- return a;
- }
- CONSTEXPR_M civil_time& operator--() noexcept {
- return *this -= 1;
- }
- CONSTEXPR_M civil_time operator--(int) noexcept {
- const civil_time a = *this;
- --*this;
- return a;
- }
-
- // Binary arithmetic operators.
+ }
+ CONSTEXPR_M civil_time& operator++() noexcept {
+ return *this += 1;
+ }
+ CONSTEXPR_M civil_time operator++(int) noexcept {
+ const civil_time a = *this;
+ ++*this;
+ return a;
+ }
+ CONSTEXPR_M civil_time& operator--() noexcept {
+ return *this -= 1;
+ }
+ CONSTEXPR_M civil_time operator--(int) noexcept {
+ const civil_time a = *this;
+ --*this;
+ return a;
+ }
+
+ // 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+(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 diff_t operator-(civil_time lhs, civil_time rhs) noexcept {
- return difference(T{}, lhs.f_, rhs.f_);
- }
-
- private:
- // All instantiations of this template are allowed to call the following
- // private constructor and access the private fields member.
- template <typename U>
- friend class civil_time;
-
- // The designated constructor that all others eventually call.
- explicit CONSTEXPR_M civil_time(fields f) noexcept : f_(align(T{}, f)) {}
-
- fields f_;
-};
-
-// Disallows difference between differently aligned types.
-// auto n = civil_day(...) - civil_hour(...); // would be confusing.
+ return difference(T{}, lhs.f_, rhs.f_);
+ }
+
+ private:
+ // All instantiations of this template are allowed to call the following
+ // private constructor and access the private fields member.
+ template <typename U>
+ friend class civil_time;
+
+ // The designated constructor that all others eventually call.
+ explicit CONSTEXPR_M civil_time(fields f) noexcept : f_(align(T{}, f)) {}
+
+ fields f_;
+};
+
+// 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;
-
-using civil_year = civil_time<year_tag>;
-using civil_month = civil_time<month_tag>;
-using civil_day = civil_time<day_tag>;
-using civil_hour = civil_time<hour_tag>;
-using civil_minute = civil_time<minute_tag>;
-using civil_second = civil_time<second_tag>;
-
-////////////////////////////////////////////////////////////////////////
-
-// Relational operators that work with differently aligned objects.
-// Always compares all six fields.
-template <typename T1, typename T2>
-CONSTEXPR_F bool operator<(const civil_time<T1>& lhs,
- const civil_time<T2>& rhs) noexcept {
- return (lhs.year() < rhs.year() ||
- (lhs.year() == rhs.year() &&
- (lhs.month() < rhs.month() ||
- (lhs.month() == rhs.month() &&
- (lhs.day() < rhs.day() ||
- (lhs.day() == rhs.day() &&
- (lhs.hour() < rhs.hour() ||
- (lhs.hour() == rhs.hour() &&
- (lhs.minute() < rhs.minute() ||
- (lhs.minute() == rhs.minute() &&
- (lhs.second() < rhs.second())))))))))));
-}
-template <typename T1, typename T2>
-CONSTEXPR_F bool operator<=(const civil_time<T1>& lhs,
- const civil_time<T2>& rhs) noexcept {
- return !(rhs < lhs);
-}
-template <typename T1, typename T2>
-CONSTEXPR_F bool operator>=(const civil_time<T1>& lhs,
- const civil_time<T2>& rhs) noexcept {
- return !(lhs < rhs);
-}
-template <typename T1, typename T2>
-CONSTEXPR_F bool operator>(const civil_time<T1>& lhs,
- const civil_time<T2>& rhs) noexcept {
- return rhs < lhs;
-}
-template <typename T1, typename T2>
-CONSTEXPR_F bool operator==(const civil_time<T1>& lhs,
- const civil_time<T2>& rhs) noexcept {
- return lhs.year() == rhs.year() && lhs.month() == rhs.month() &&
- lhs.day() == rhs.day() && lhs.hour() == rhs.hour() &&
- lhs.minute() == rhs.minute() && lhs.second() == rhs.second();
-}
-template <typename T1, typename T2>
-CONSTEXPR_F bool operator!=(const civil_time<T1>& lhs,
- const civil_time<T2>& rhs) noexcept {
- return !(lhs == rhs);
-}
-
-////////////////////////////////////////////////////////////////////////
-
-enum class weekday {
- monday,
- tuesday,
- wednesday,
- thursday,
- friday,
- saturday,
- sunday,
-};
-
+
+using civil_year = civil_time<year_tag>;
+using civil_month = civil_time<month_tag>;
+using civil_day = civil_time<day_tag>;
+using civil_hour = civil_time<hour_tag>;
+using civil_minute = civil_time<minute_tag>;
+using civil_second = civil_time<second_tag>;
+
+////////////////////////////////////////////////////////////////////////
+
+// Relational operators that work with differently aligned objects.
+// Always compares all six fields.
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator<(const civil_time<T1>& lhs,
+ const civil_time<T2>& rhs) noexcept {
+ return (lhs.year() < rhs.year() ||
+ (lhs.year() == rhs.year() &&
+ (lhs.month() < rhs.month() ||
+ (lhs.month() == rhs.month() &&
+ (lhs.day() < rhs.day() ||
+ (lhs.day() == rhs.day() &&
+ (lhs.hour() < rhs.hour() ||
+ (lhs.hour() == rhs.hour() &&
+ (lhs.minute() < rhs.minute() ||
+ (lhs.minute() == rhs.minute() &&
+ (lhs.second() < rhs.second())))))))))));
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator<=(const civil_time<T1>& lhs,
+ const civil_time<T2>& rhs) noexcept {
+ return !(rhs < lhs);
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator>=(const civil_time<T1>& lhs,
+ const civil_time<T2>& rhs) noexcept {
+ return !(lhs < rhs);
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator>(const civil_time<T1>& lhs,
+ const civil_time<T2>& rhs) noexcept {
+ return rhs < lhs;
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator==(const civil_time<T1>& lhs,
+ const civil_time<T2>& rhs) noexcept {
+ return lhs.year() == rhs.year() && lhs.month() == rhs.month() &&
+ lhs.day() == rhs.day() && lhs.hour() == rhs.hour() &&
+ lhs.minute() == rhs.minute() && lhs.second() == rhs.second();
+}
+template <typename T1, typename T2>
+CONSTEXPR_F bool operator!=(const civil_time<T1>& lhs,
+ const civil_time<T2>& rhs) noexcept {
+ return !(lhs == rhs);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+enum class weekday {
+ monday,
+ tuesday,
+ wednesday,
+ thursday,
+ friday,
+ saturday,
+ 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,
- weekday::saturday,
- };
- CONSTEXPR_D int k_weekday_offsets[1 + 12] = {
- -1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4,
- };
+ 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];
-}
-
-////////////////////////////////////////////////////////////////////////
-
-CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept {
+}
+
+////////////////////////////////////////////////////////////////////////
+
+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,
@@ -540,9 +540,9 @@ CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept {
}
}
}
-}
-
-CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept {
+}
+
+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,
@@ -560,31 +560,31 @@ CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept {
}
}
}
-}
-
+}
+
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,
- };
+ 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();
-}
-
-////////////////////////////////////////////////////////////////////////
-
-std::ostream& operator<<(std::ostream& os, const civil_year& y);
-std::ostream& operator<<(std::ostream& os, const civil_month& m);
-std::ostream& operator<<(std::ostream& os, const civil_day& d);
-std::ostream& operator<<(std::ostream& os, const civil_hour& h);
-std::ostream& operator<<(std::ostream& os, const civil_minute& m);
-std::ostream& operator<<(std::ostream& os, const civil_second& s);
-std::ostream& operator<<(std::ostream& os, weekday wd);
-
-} // namespace detail
-} // namespace cctz
-
-#undef CONSTEXPR_M
-#undef CONSTEXPR_F
-#undef CONSTEXPR_D
-
-#endif // CCTZ_CIVIL_TIME_DETAIL_H_
+}
+
+////////////////////////////////////////////////////////////////////////
+
+std::ostream& operator<<(std::ostream& os, const civil_year& y);
+std::ostream& operator<<(std::ostream& os, const civil_month& m);
+std::ostream& operator<<(std::ostream& os, const civil_day& d);
+std::ostream& operator<<(std::ostream& os, const civil_hour& h);
+std::ostream& operator<<(std::ostream& os, const civil_minute& m);
+std::ostream& operator<<(std::ostream& os, const civil_second& s);
+std::ostream& operator<<(std::ostream& os, weekday wd);
+
+} // namespace detail
+} // namespace cctz
+
+#undef CONSTEXPR_M
+#undef CONSTEXPR_F
+#undef CONSTEXPR_D
+
+#endif // CCTZ_CIVIL_TIME_DETAIL_H_
diff --git a/contrib/libs/cctz/include/cctz/time_zone.h b/contrib/libs/cctz/include/cctz/time_zone.h
index 4fc1a2a24f..e497e6780f 100644
--- a/contrib/libs/cctz/include/cctz/time_zone.h
+++ b/contrib/libs/cctz/include/cctz/time_zone.h
@@ -1,162 +1,162 @@
-// 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
-//
+// 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.
-
-// A library for translating between absolute times (represented by
-// std::chrono::time_points of the std::chrono::system_clock) and civil
-// times (represented by cctz::civil_second) using the rules defined by
-// a time zone (cctz::time_zone).
-
-#ifndef CCTZ_TIME_ZONE_H_
-#define CCTZ_TIME_ZONE_H_
-
-#include <chrono>
-#include <cstdint>
-#include <string>
-#include <utility>
-
+//
+// 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.
+
+// A library for translating between absolute times (represented by
+// std::chrono::time_points of the std::chrono::system_clock) and civil
+// times (represented by cctz::civil_second) using the rules defined by
+// a time zone (cctz::time_zone).
+
+#ifndef CCTZ_TIME_ZONE_H_
+#define CCTZ_TIME_ZONE_H_
+
+#include <chrono>
+#include <cstdint>
+#include <string>
+#include <utility>
+
#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>;
+
+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.
-
-namespace detail {
-template <typename D>
+
+namespace detail {
+template <typename D>
inline std::pair<time_point<seconds>, D>
-split_seconds(const time_point<D>& tp) {
+split_seconds(const time_point<D>& tp) {
auto sec = std::chrono::time_point_cast<seconds>(tp);
- auto sub = tp - sec;
- if (sub.count() < 0) {
+ auto sub = tp - sec;
+ if (sub.count() < 0) {
sec -= seconds(1);
sub += seconds(1);
- }
- return {sec, std::chrono::duration_cast<D>(sub)};
-}
+ }
+ 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()};
-}
-} // namespace detail
-
-// cctz::time_zone is an opaque, small, value-type class representing a
-// geo-political region within which particular rules are used for mapping
-// between absolute and civil times. Time zones are named using the TZ
-// identifiers from the IANA Time Zone Database, such as "America/Los_Angeles"
-// or "Australia/Sydney". Time zones are created from factory functions such
-// as load_time_zone(). Note: strings like "PST" and "EDT" are not valid TZ
-// identifiers.
-//
-// Example:
-// cctz::time_zone utc = cctz::utc_time_zone();
-// cctz::time_zone pst = cctz::fixed_time_zone(std::chrono::hours(-8));
-// cctz::time_zone loc = cctz::local_time_zone();
-// cctz::time_zone lax;
-// if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
-//
-// See also:
-// - http://www.iana.org/time-zones
+}
+} // namespace detail
+
+// cctz::time_zone is an opaque, small, value-type class representing a
+// geo-political region within which particular rules are used for mapping
+// between absolute and civil times. Time zones are named using the TZ
+// identifiers from the IANA Time Zone Database, such as "America/Los_Angeles"
+// or "Australia/Sydney". Time zones are created from factory functions such
+// as load_time_zone(). Note: strings like "PST" and "EDT" are not valid TZ
+// identifiers.
+//
+// Example:
+// cctz::time_zone utc = cctz::utc_time_zone();
+// cctz::time_zone pst = cctz::fixed_time_zone(std::chrono::hours(-8));
+// cctz::time_zone loc = cctz::local_time_zone();
+// cctz::time_zone lax;
+// if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
+//
+// See also:
+// - http://www.iana.org/time-zones
// - https://en.wikipedia.org/wiki/Zoneinfo
-class time_zone {
- public:
+class time_zone {
+ public:
time_zone() : time_zone(nullptr) {} // Equivalent to UTC
- time_zone(const time_zone&) = default;
- time_zone& operator=(const time_zone&) = default;
-
- std::string name() const;
-
- // An absolute_lookup represents the civil time (cctz::civil_second) within
- // this time_zone at the given absolute time (time_point). There are
- // additionally a few other fields that may be useful when working with
- // older APIs, such as std::tm.
- //
- // Example:
- // const cctz::time_zone tz = ...
- // const auto tp = std::chrono::system_clock::now();
- // const cctz::time_zone::absolute_lookup al = tz.lookup(tp);
- struct absolute_lookup {
- civil_second cs;
- // Note: The following fields exist for backward compatibility with older
- // APIs. Accessing these fields directly is a sign of imprudent logic in
- // the calling code. Modern time-related code should only access this data
- // indirectly by way of cctz::format().
- int offset; // civil seconds east of UTC
- bool is_dst; // is offset non-standard?
- const char* abbr; // time-zone abbreviation (e.g., "PST")
- };
+ time_zone(const time_zone&) = default;
+ time_zone& operator=(const time_zone&) = default;
+
+ std::string name() const;
+
+ // An absolute_lookup represents the civil time (cctz::civil_second) within
+ // this time_zone at the given absolute time (time_point). There are
+ // additionally a few other fields that may be useful when working with
+ // older APIs, such as std::tm.
+ //
+ // Example:
+ // const cctz::time_zone tz = ...
+ // const auto tp = std::chrono::system_clock::now();
+ // const cctz::time_zone::absolute_lookup al = tz.lookup(tp);
+ struct absolute_lookup {
+ civil_second cs;
+ // Note: The following fields exist for backward compatibility with older
+ // APIs. Accessing these fields directly is a sign of imprudent logic in
+ // the calling code. Modern time-related code should only access this data
+ // indirectly by way of cctz::format().
+ int offset; // civil seconds east of UTC
+ 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;
- template <typename D>
- absolute_lookup lookup(const time_point<D>& tp) const {
- return lookup(detail::split_seconds(tp).first);
- }
-
- // A civil_lookup represents the absolute time(s) (time_point) that
- // correspond to the given civil time (cctz::civil_second) within this
- // time_zone. Usually the given civil time represents a unique instant
- // in time, in which case the conversion is unambiguous. However,
- // within this time zone, the given civil time may be skipped (e.g.,
- // during a positive UTC offset shift), or repeated (e.g., during a
- // negative UTC offset shift). To account for these possibilities,
- // civil_lookup is richer than just a single time_point.
- //
- // In all cases the civil_lookup::kind enum will indicate the nature
- // 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,
+ template <typename D>
+ absolute_lookup lookup(const time_point<D>& tp) const {
+ return lookup(detail::split_seconds(tp).first);
+ }
+
+ // A civil_lookup represents the absolute time(s) (time_point) that
+ // correspond to the given civil time (cctz::civil_second) within this
+ // time_zone. Usually the given civil time represents a unique instant
+ // in time, in which case the conversion is unambiguous. However,
+ // within this time zone, the given civil time may be skipped (e.g.,
+ // during a positive UTC offset shift), or repeated (e.g., during a
+ // negative UTC offset shift). To account for these possibilities,
+ // civil_lookup is richer than just a single time_point.
+ //
+ // In all cases the civil_lookup::kind enum will indicate the nature
+ // 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
- // of these three absolute times is outside the representable range of a
+ // of these three absolute times is outside the representable range of a
// time_point<seconds> the field is set to its maximum/minimum value.
- //
- // Example:
- // cctz::time_zone lax;
- // if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
- //
- // // A unique civil time.
- // auto jan01 = lax.lookup(cctz::civil_second(2011, 1, 1, 0, 0, 0));
- // // jan01.kind == cctz::time_zone::civil_lookup::UNIQUE
- // // jan01.pre is 2011/01/01 00:00:00 -0800
- // // jan01.trans is 2011/01/01 00:00:00 -0800
- // // jan01.post is 2011/01/01 00:00:00 -0800
- //
- // // A Spring DST transition, when there is a gap in civil time.
- // auto mar13 = lax.lookup(cctz::civil_second(2011, 3, 13, 2, 15, 0));
- // // mar13.kind == cctz::time_zone::civil_lookup::SKIPPED
- // // mar13.pre is 2011/03/13 03:15:00 -0700
- // // mar13.trans is 2011/03/13 03:00:00 -0700
- // // mar13.post is 2011/03/13 01:15:00 -0800
- //
- // // A Fall DST transition, when civil times are repeated.
- // auto nov06 = lax.lookup(cctz::civil_second(2011, 11, 6, 1, 15, 0));
- // // nov06.kind == cctz::time_zone::civil_lookup::REPEATED
- // // nov06.pre is 2011/11/06 01:15:00 -0700
- // // nov06.trans is 2011/11/06 01:00:00 -0800
- // // nov06.post is 2011/11/06 01:15:00 -0800
- struct civil_lookup {
- enum civil_kind {
- UNIQUE, // the civil time was singular (pre == trans == post)
- SKIPPED, // the civil time did not exist (pre >= trans > post)
- REPEATED, // the civil time was ambiguous (pre < trans <= post)
- } kind;
+ //
+ // Example:
+ // cctz::time_zone lax;
+ // if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
+ //
+ // // A unique civil time.
+ // auto jan01 = lax.lookup(cctz::civil_second(2011, 1, 1, 0, 0, 0));
+ // // jan01.kind == cctz::time_zone::civil_lookup::UNIQUE
+ // // jan01.pre is 2011/01/01 00:00:00 -0800
+ // // jan01.trans is 2011/01/01 00:00:00 -0800
+ // // jan01.post is 2011/01/01 00:00:00 -0800
+ //
+ // // A Spring DST transition, when there is a gap in civil time.
+ // auto mar13 = lax.lookup(cctz::civil_second(2011, 3, 13, 2, 15, 0));
+ // // mar13.kind == cctz::time_zone::civil_lookup::SKIPPED
+ // // mar13.pre is 2011/03/13 03:15:00 -0700
+ // // mar13.trans is 2011/03/13 03:00:00 -0700
+ // // mar13.post is 2011/03/13 01:15:00 -0800
+ //
+ // // A Fall DST transition, when civil times are repeated.
+ // auto nov06 = lax.lookup(cctz::civil_second(2011, 11, 6, 1, 15, 0));
+ // // nov06.kind == cctz::time_zone::civil_lookup::REPEATED
+ // // nov06.pre is 2011/11/06 01:15:00 -0700
+ // // nov06.trans is 2011/11/06 01:00:00 -0800
+ // // nov06.post is 2011/11/06 01:15:00 -0800
+ struct civil_lookup {
+ enum civil_kind {
+ UNIQUE, // the civil time was singular (pre == trans == post)
+ 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
- };
- civil_lookup lookup(const civil_second& cs) const;
-
+ };
+ 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
@@ -222,161 +222,161 @@ class time_zone {
return !(lhs == rhs);
}
- class Impl;
-
- private:
- explicit time_zone(const Impl* impl) : impl_(impl) {}
+ class Impl;
+
+ private:
+ explicit time_zone(const Impl* impl) : 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.
-// If the name is invalid, or some other kind of error occurs, returns
-// false and "*tz" is set to the UTC time zone.
-bool load_time_zone(const std::string& name, time_zone* tz);
-
-// Returns a time_zone representing UTC. Cannot fail.
-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.
+};
+
+// Loads the named time zone. May perform I/O on the initial load.
+// If the name is invalid, or some other kind of error occurs, returns
+// false and "*tz" is set to the UTC time zone.
+bool load_time_zone(const std::string& name, time_zone* tz);
+
+// Returns a time_zone representing UTC. Cannot fail.
+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);
-
-// Returns a time zone representing the local time zone. Falls back to UTC.
+
+// Returns a time zone representing the local time zone. Falls back to UTC.
// 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
-// the given absolute time (time_point). Since the additional fields provided
-// by the time_zone::absolute_lookup struct should rarely be needed in modern
-// code, this convert() function is simpler and should be preferred.
-template <typename D>
-inline civil_second convert(const time_point<D>& tp, const time_zone& tz) {
- return tz.lookup(tp).cs;
-}
-
-// Returns the absolute time (time_point) that corresponds to the given civil
-// time within the given time zone. If the civil time is not unique (i.e., if
-// 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).
+time_zone local_time_zone();
+
+// Returns the civil time (cctz::civil_second) within the given time zone at
+// the given absolute time (time_point). Since the additional fields provided
+// by the time_zone::absolute_lookup struct should rarely be needed in modern
+// code, this convert() function is simpler and should be preferred.
+template <typename D>
+inline civil_second convert(const time_point<D>& tp, const time_zone& tz) {
+ return tz.lookup(tp).cs;
+}
+
+// Returns the absolute time (time_point) that corresponds to the given civil
+// time within the given time zone. If the civil time is not unique (i.e., if
+// 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) {
- const time_zone::civil_lookup cl = tz.lookup(cs);
- if (cl.kind == time_zone::civil_lookup::SKIPPED) return cl.trans;
- return cl.pre;
-}
-
-namespace detail {
-using femtoseconds = std::chrono::duration<std::int_fast64_t, std::femto>;
+ const time_zone::civil_lookup cl = tz.lookup(cs);
+ if (cl.kind == time_zone::civil_lookup::SKIPPED) return cl.trans;
+ return cl.pre;
+}
+
+namespace detail {
+using femtoseconds = std::chrono::duration<std::int_fast64_t, std::femto>;
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&,
+ const femtoseconds&, const time_zone&);
+bool parse(const std::string&, const std::string&, const time_zone&,
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:
-//
+} // 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)
-// - %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)
+// - %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"
-//
+//
// 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.
-//
+// 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.
-//
-// Example:
-// cctz::time_zone lax;
-// if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
-// auto tp = cctz::convert(cctz::civil_second(2013, 1, 2, 3, 4, 5), lax);
-// std::string f = cctz::format("%H:%M:%S", tp, lax); // "03:04:05"
-// f = cctz::format("%H:%M:%E3S", tp, lax); // "03:04:05.000"
-template <typename D>
-inline std::string format(const std::string& fmt, const time_point<D>& tp,
- const time_zone& tz) {
- const auto p = detail::split_seconds(tp);
- const auto n = std::chrono::duration_cast<detail::femtoseconds>(p.second);
- return detail::format(fmt, p.first, n, tz);
-}
-
-// 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
+//
+// Example:
+// cctz::time_zone lax;
+// if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
+// auto tp = cctz::convert(cctz::civil_second(2013, 1, 2, 3, 4, 5), lax);
+// std::string f = cctz::format("%H:%M:%S", tp, lax); // "03:04:05"
+// f = cctz::format("%H:%M:%E3S", tp, lax); // "03:04:05.000"
+template <typename D>
+inline std::string format(const std::string& fmt, const time_point<D>& tp,
+ const time_zone& tz) {
+ const auto p = detail::split_seconds(tp);
+ const auto n = std::chrono::duration_cast<detail::femtoseconds>(p.second);
+ return detail::format(fmt, p.first, n, tz);
+}
+
+// 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'.
-//
-// %Y consumes as many numeric characters as it can, so the matching data
-// should always be terminated with a non-numeric. %E4Y always consumes
-// exactly four characters, including any sign.
-//
-// Unspecified fields are taken from the default date and time of ...
-//
-// "1970-01-01 00:00:00.0 +0000"
-//
-// For example, parsing a string of "15:45" (%H:%M) will return a time_point
-// that represents "1970-01-01 15:45:00.0 +0000".
-//
-// Note that parse() returns time instants, so it makes most sense to parse
+//
+// %Y consumes as many numeric characters as it can, so the matching data
+// should always be terminated with a non-numeric. %E4Y always consumes
+// exactly four characters, including any sign.
+//
+// Unspecified fields are taken from the default date and time of ...
+//
+// "1970-01-01 00:00:00.0 +0000"
+//
+// For example, parsing a string of "15:45" (%H:%M) will return a time_point
+// 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).
-//
-// Note also that parse() only heeds the fields year, month, day, hour,
-// minute, (fractional) second, and UTC offset. Other fields, like weekday (%a
-// or %A), while parsed for syntactic validity, are ignored in the conversion.
-//
-// Date and time fields that are out-of-range will be treated as errors rather
-// than normalizing them like cctz::civil_second() would do. For example, it
-// is an error to parse the date "Oct 32, 2013" because 32 is out of range.
-//
-// A second of ":60" is normalized to ":00" of the following minute with
-// fractional seconds discarded. The following table shows how the given
-// seconds and subseconds will be parsed:
-//
-// "59.x" -> 59.x // exact
-// "60.x" -> 00.0 // normalized
-// "00.x" -> 00.x // exact
-//
-// Errors are indicated by returning false.
-//
-// Example:
-// const cctz::time_zone tz = ...
-// std::chrono::system_clock::time_point tp;
-// if (cctz::parse("%Y-%m-%d", "2015-10-09", tz, &tp)) {
-// ...
-// }
-template <typename D>
-inline bool parse(const std::string& fmt, const std::string& input,
- const time_zone& tz, time_point<D>* tpp) {
+//
+// Note also that parse() only heeds the fields year, month, day, hour,
+// minute, (fractional) second, and UTC offset. Other fields, like weekday (%a
+// or %A), while parsed for syntactic validity, are ignored in the conversion.
+//
+// Date and time fields that are out-of-range will be treated as errors rather
+// than normalizing them like cctz::civil_second() would do. For example, it
+// is an error to parse the date "Oct 32, 2013" because 32 is out of range.
+//
+// A second of ":60" is normalized to ":00" of the following minute with
+// fractional seconds discarded. The following table shows how the given
+// seconds and subseconds will be parsed:
+//
+// "59.x" -> 59.x // exact
+// "60.x" -> 00.0 // normalized
+// "00.x" -> 00.x // exact
+//
+// Errors are indicated by returning false.
+//
+// Example:
+// const cctz::time_zone tz = ...
+// std::chrono::system_clock::time_point tp;
+// if (cctz::parse("%Y-%m-%d", "2015-10-09", tz, &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;
- detail::femtoseconds fs;
- const bool b = detail::parse(fmt, input, tz, &sec, &fs);
- if (b) {
- // TODO: Return false if unrepresentable as a time_point<D>.
- *tpp = std::chrono::time_point_cast<D>(sec);
- *tpp += std::chrono::duration_cast<D>(fs);
- }
- return b;
-}
-
+ detail::femtoseconds fs;
+ const bool b = detail::parse(fmt, input, tz, &sec, &fs);
+ if (b) {
+ // TODO: Return false if unrepresentable as a time_point<D>.
+ *tpp = std::chrono::time_point_cast<D>(sec);
+ *tpp += std::chrono::duration_cast<D>(fs);
+ }
+ return b;
+}
+
// 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);
-} // namespace cctz
-
-#endif // CCTZ_TIME_ZONE_H_
+} // namespace cctz
+
+#endif // CCTZ_TIME_ZONE_H_
diff --git a/contrib/libs/cctz/include/cctz/zone_info_source.h b/contrib/libs/cctz/include/cctz/zone_info_source.h
index 08e91b3c1f..ccdb73f2fa 100644
--- a/contrib/libs/cctz/include/cctz/zone_info_source.h
+++ b/contrib/libs/cctz/include/cctz/zone_info_source.h
@@ -1,88 +1,88 @@
-// 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
-//
+// 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.
-
-#ifndef CCTZ_ZONE_INFO_SOURCE_H_
-#define CCTZ_ZONE_INFO_SOURCE_H_
-
-#include <cstddef>
-#include <functional>
-#include <memory>
-#include <string>
-
-namespace cctz {
-
-// A stdio-like interface for providing zoneinfo data for a particular zone.
-class ZoneInfoSource {
- public:
+//
+// 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.
+
+#ifndef CCTZ_ZONE_INFO_SOURCE_H_
+#define CCTZ_ZONE_INFO_SOURCE_H_
+
+#include <cstddef>
+#include <functional>
+#include <memory>
+#include <string>
+
+namespace cctz {
+
+// A stdio-like interface for providing zoneinfo data for a particular zone.
+class ZoneInfoSource {
+ public:
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()
+
+ 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;
-};
-
-} // namespace cctz
-
-namespace cctz_extension {
-
-// A function-pointer type for a factory that returns a ZoneInfoSource
-// given the name of a time zone and a fallback factory. Returns null
-// when the data for the named zone cannot be found.
-using ZoneInfoSourceFactory =
- std::unique_ptr<cctz::ZoneInfoSource> (*)(
- const std::string&,
- const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
- const std::string&)>&);
-
-// The user can control the mapping of zone names to zoneinfo data by
-// providing a definition for cctz_extension::zone_info_source_factory.
-// For example, given functions my_factory() and my_other_factory() that
-// can return a ZoneInfoSource for a named zone, we could inject them into
-// cctz::load_time_zone() with:
-//
-// namespace cctz_extension {
-// namespace {
-// std::unique_ptr<cctz::ZoneInfoSource> CustomFactory(
-// const std::string& name,
-// const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
-// const std::string& name)>& fallback_factory) {
-// if (auto zip = my_factory(name)) return zip;
-// if (auto zip = fallback_factory(name)) return zip;
-// if (auto zip = my_other_factory(name)) return zip;
-// return nullptr;
-// }
-// } // namespace
-// ZoneInfoSourceFactory zone_info_source_factory = CustomFactory;
-// } // namespace cctz_extension
-//
-// This might be used, say, to use zoneinfo data embedded in the program,
-// or read from a (possibly compressed) file archive, or both.
-//
-// cctz_extension::zone_info_source_factory() will be called:
-// (1) from the same thread as the cctz::load_time_zone() call,
-// (2) only once for any zone name, and
-// (3) serially (i.e., no concurrent execution).
-//
-// The fallback factory obtains zoneinfo data by reading files in ${TZDIR},
-// and it is used automatically when no zone_info_source_factory definition
-// is linked into the program.
-extern ZoneInfoSourceFactory zone_info_source_factory;
-
-} // namespace cctz_extension
-
-#endif // CCTZ_ZONE_INFO_SOURCE_H_
+};
+
+} // namespace cctz
+
+namespace cctz_extension {
+
+// A function-pointer type for a factory that returns a ZoneInfoSource
+// given the name of a time zone and a fallback factory. Returns null
+// when the data for the named zone cannot be found.
+using ZoneInfoSourceFactory =
+ std::unique_ptr<cctz::ZoneInfoSource> (*)(
+ const std::string&,
+ const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
+ const std::string&)>&);
+
+// The user can control the mapping of zone names to zoneinfo data by
+// providing a definition for cctz_extension::zone_info_source_factory.
+// For example, given functions my_factory() and my_other_factory() that
+// can return a ZoneInfoSource for a named zone, we could inject them into
+// cctz::load_time_zone() with:
+//
+// namespace cctz_extension {
+// namespace {
+// std::unique_ptr<cctz::ZoneInfoSource> CustomFactory(
+// const std::string& name,
+// const std::function<std::unique_ptr<cctz::ZoneInfoSource>(
+// const std::string& name)>& fallback_factory) {
+// if (auto zip = my_factory(name)) return zip;
+// if (auto zip = fallback_factory(name)) return zip;
+// if (auto zip = my_other_factory(name)) return zip;
+// return nullptr;
+// }
+// } // namespace
+// ZoneInfoSourceFactory zone_info_source_factory = CustomFactory;
+// } // namespace cctz_extension
+//
+// This might be used, say, to use zoneinfo data embedded in the program,
+// or read from a (possibly compressed) file archive, or both.
+//
+// cctz_extension::zone_info_source_factory() will be called:
+// (1) from the same thread as the cctz::load_time_zone() call,
+// (2) only once for any zone name, and
+// (3) serially (i.e., no concurrent execution).
+//
+// The fallback factory obtains zoneinfo data by reading files in ${TZDIR},
+// and it is used automatically when no zone_info_source_factory definition
+// is linked into the program.
+extern ZoneInfoSourceFactory zone_info_source_factory;
+
+} // namespace cctz_extension
+
+#endif // CCTZ_ZONE_INFO_SOURCE_H_
diff --git a/contrib/libs/cctz/src/civil_time_detail.cc b/contrib/libs/cctz/src/civil_time_detail.cc
index b6856b8df4..4f9019f353 100644
--- a/contrib/libs/cctz/src/civil_time_detail.cc
+++ b/contrib/libs/cctz/src/civil_time_detail.cc
@@ -11,76 +11,76 @@
// 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 <iomanip>
-#include <ostream>
-#include <sstream>
-
-namespace cctz {
-namespace detail {
-
-// Output stream operators output a format matching YYYY-MM-DDThh:mm:ss,
-// while omitting fields inferior to the type's alignment. For example,
-// civil_day is formatted only as YYYY-MM-DD.
-std::ostream& operator<<(std::ostream& os, const civil_year& y) {
- std::stringstream ss;
- ss << y.year(); // No padding.
- return os << ss.str();
-}
-std::ostream& operator<<(std::ostream& os, const civil_month& m) {
- std::stringstream ss;
- ss << civil_year(m) << '-';
- ss << std::setfill('0') << std::setw(2) << m.month();
- return os << ss.str();
-}
-std::ostream& operator<<(std::ostream& os, const civil_day& d) {
- std::stringstream ss;
- ss << civil_month(d) << '-';
- ss << std::setfill('0') << std::setw(2) << d.day();
- return os << ss.str();
-}
-std::ostream& operator<<(std::ostream& os, const civil_hour& h) {
- std::stringstream ss;
- ss << civil_day(h) << 'T';
- ss << std::setfill('0') << std::setw(2) << h.hour();
- return os << ss.str();
-}
-std::ostream& operator<<(std::ostream& os, const civil_minute& m) {
- std::stringstream ss;
- ss << civil_hour(m) << ':';
- ss << std::setfill('0') << std::setw(2) << m.minute();
- return os << ss.str();
-}
-std::ostream& operator<<(std::ostream& os, const civil_second& s) {
- std::stringstream ss;
- ss << civil_minute(s) << ':';
- ss << std::setfill('0') << std::setw(2) << s.second();
- return os << ss.str();
-}
-
-////////////////////////////////////////////////////////////////////////
-
-std::ostream& operator<<(std::ostream& os, weekday wd) {
- switch (wd) {
- case weekday::monday:
- return os << "Monday";
- case weekday::tuesday:
- return os << "Tuesday";
- case weekday::wednesday:
- return os << "Wednesday";
- case weekday::thursday:
- return os << "Thursday";
- case weekday::friday:
- return os << "Friday";
- case weekday::saturday:
- return os << "Saturday";
- case weekday::sunday:
- return os << "Sunday";
- }
- return os; // Should never get here, but -Wreturn-type may warn without this.
-}
-
-} // namespace detail
-} // namespace cctz
+#include <iomanip>
+#include <ostream>
+#include <sstream>
+
+namespace cctz {
+namespace detail {
+
+// Output stream operators output a format matching YYYY-MM-DDThh:mm:ss,
+// while omitting fields inferior to the type's alignment. For example,
+// civil_day is formatted only as YYYY-MM-DD.
+std::ostream& operator<<(std::ostream& os, const civil_year& y) {
+ std::stringstream ss;
+ ss << y.year(); // No padding.
+ return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_month& m) {
+ std::stringstream ss;
+ ss << civil_year(m) << '-';
+ ss << std::setfill('0') << std::setw(2) << m.month();
+ return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_day& d) {
+ std::stringstream ss;
+ ss << civil_month(d) << '-';
+ ss << std::setfill('0') << std::setw(2) << d.day();
+ return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_hour& h) {
+ std::stringstream ss;
+ ss << civil_day(h) << 'T';
+ ss << std::setfill('0') << std::setw(2) << h.hour();
+ return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_minute& m) {
+ std::stringstream ss;
+ ss << civil_hour(m) << ':';
+ ss << std::setfill('0') << std::setw(2) << m.minute();
+ return os << ss.str();
+}
+std::ostream& operator<<(std::ostream& os, const civil_second& s) {
+ std::stringstream ss;
+ ss << civil_minute(s) << ':';
+ ss << std::setfill('0') << std::setw(2) << s.second();
+ return os << ss.str();
+}
+
+////////////////////////////////////////////////////////////////////////
+
+std::ostream& operator<<(std::ostream& os, weekday wd) {
+ switch (wd) {
+ case weekday::monday:
+ return os << "Monday";
+ case weekday::tuesday:
+ return os << "Tuesday";
+ case weekday::wednesday:
+ return os << "Wednesday";
+ case weekday::thursday:
+ return os << "Thursday";
+ case weekday::friday:
+ return os << "Friday";
+ case weekday::saturday:
+ return os << "Saturday";
+ case weekday::sunday:
+ return os << "Sunday";
+ }
+ return os; // Should never get here, but -Wreturn-type may warn without this.
+}
+
+} // namespace detail
+} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_fixed.cc b/contrib/libs/cctz/src/time_zone_fixed.cc
index ce79822ada..427bc050e0 100644
--- a/contrib/libs/cctz/src/time_zone_fixed.cc
+++ b/contrib/libs/cctz/src/time_zone_fixed.cc
@@ -1,32 +1,32 @@
-// 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
-//
+// 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 "time_zone_fixed.h"
-
-#include <algorithm>
+//
+// 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 "time_zone_fixed.h"
+
+#include <algorithm>
#include <cassert>
-#include <chrono>
-#include <cstring>
-#include <string>
-
-namespace cctz {
-
-namespace {
-
-// The prefix used for the internal names of fixed-offset zones.
+#include <chrono>
+#include <cstring>
+#include <string>
+
+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) {
@@ -35,69 +35,69 @@ char* Format02d(char* p, int v) {
return p;
}
-int Parse02d(const char* p) {
- if (const char* ap = std::strchr(kDigits, *p)) {
- int v = static_cast<int>(ap - kDigits);
- if (const char* bp = std::strchr(kDigits, *++p)) {
- return (v * 10) + static_cast<int>(bp - kDigits);
- }
- }
- return -1;
-}
-
-} // namespace
-
+int Parse02d(const char* p) {
+ if (const char* ap = std::strchr(kDigits, *p)) {
+ int v = static_cast<int>(ap - kDigits);
+ if (const char* bp = std::strchr(kDigits, *++p)) {
+ return (v * 10) + static_cast<int>(bp - kDigits);
+ }
+ }
+ return -1;
+}
+
+} // namespace
+
bool FixedOffsetFromName(const std::string& name, seconds* offset) {
- if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
+ if (name.compare(0, std::string::npos, "UTC", 3) == 0) {
*offset = seconds::zero();
- return true;
- }
-
+ 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
- return false;
+ return false;
if (!std::equal(kFixedZonePrefix, ep, name.begin()))
- return false;
- const char* np = name.data() + prefix_len;
- if (np[0] != '+' && np[0] != '-')
- return false;
- if (np[3] != ':' || np[6] != ':') // see note below about large offsets
- return false;
-
- int hours = Parse02d(np + 1);
- if (hours == -1) return false;
- int mins = Parse02d(np + 4);
- if (mins == -1) return false;
- int secs = Parse02d(np + 7);
- if (secs == -1) return false;
-
- secs += ((hours * 60) + mins) * 60;
- if (secs > 24 * 60 * 60) return false; // outside supported offset range
+ return false;
+ const char* np = name.data() + prefix_len;
+ if (np[0] != '+' && np[0] != '-')
+ return false;
+ if (np[3] != ':' || np[6] != ':') // see note below about large offsets
+ return false;
+
+ int hours = Parse02d(np + 1);
+ if (hours == -1) return false;
+ int mins = Parse02d(np + 4);
+ if (mins == -1) return false;
+ int secs = Parse02d(np + 7);
+ if (secs == -1) return false;
+
+ 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
- return true;
-}
-
+ return true;
+}
+
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";
- }
+ 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;
- if (sign == '-') {
+ if (sign == '-') {
if (offset_seconds > 0) {
offset_seconds -= 60;
offset_minutes += 1;
- }
+ }
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;
@@ -111,11 +111,11 @@ std::string FixedOffsetToName(const seconds& offset) {
ep = Format02d(ep, offset_seconds);
*ep++ = '\0';
assert(ep == buf + sizeof(buf));
- return buf;
-}
-
+ return buf;
+}
+
std::string FixedOffsetToAbbr(const seconds& offset) {
- std::string abbr = FixedOffsetToName(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
@@ -125,10 +125,10 @@ std::string FixedOffsetToAbbr(const seconds& offset) {
abbr.erase(5, 2); // +9999
if (abbr[3] == '0' && abbr[4] == '0') { // +9900
abbr.erase(3, 2); // +99
- }
- }
- }
- return abbr;
-}
-
-} // namespace cctz
+ }
+ }
+ }
+ return abbr;
+}
+
+} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_fixed.h b/contrib/libs/cctz/src/time_zone_fixed.h
index f37226ff46..1bf07cb258 100644
--- a/contrib/libs/cctz/src/time_zone_fixed.h
+++ b/contrib/libs/cctz/src/time_zone_fixed.h
@@ -1,45 +1,45 @@
-// 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
-//
+// 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.
-
-#ifndef CCTZ_TIME_ZONE_FIXED_H_
-#define CCTZ_TIME_ZONE_FIXED_H_
-
-#include <string>
-
+//
+// 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.
+
+#ifndef CCTZ_TIME_ZONE_FIXED_H_
+#define CCTZ_TIME_ZONE_FIXED_H_
+
+#include <string>
+
#include "cctz/time_zone.h"
-
-namespace cctz {
-
-// Helper functions for dealing with the names and abbreviations
-// of time zones that are a fixed offset (seconds east) from UTC.
-// FixedOffsetFromName() extracts the offset from a valid fixed-offset
-// name, while FixedOffsetToName() and FixedOffsetToAbbr() generate
-// the canonical zone name and abbreviation respectively for the given
-// offset.
-//
-// A fixed-offset name looks like "Fixed/UTC<+-><hours>:<mins>:<secs>".
-// Its abbreviation is of the form "UTC(<+->H?H(MM(SS)?)?)?" where the
-// optional pieces are omitted when their values are zero. (Note that
-// the sign is the opposite of that used in a POSIX TZ specification.)
-//
-// 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.
+
+namespace cctz {
+
+// Helper functions for dealing with the names and abbreviations
+// of time zones that are a fixed offset (seconds east) from UTC.
+// FixedOffsetFromName() extracts the offset from a valid fixed-offset
+// name, while FixedOffsetToName() and FixedOffsetToAbbr() generate
+// the canonical zone name and abbreviation respectively for the given
+// offset.
+//
+// A fixed-offset name looks like "Fixed/UTC<+-><hours>:<mins>:<secs>".
+// Its abbreviation is of the form "UTC(<+->H?H(MM(SS)?)?)?" where the
+// optional pieces are omitted when their values are zero. (Note that
+// the sign is the opposite of that used in a POSIX TZ specification.)
+//
+// 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);
-
-} // namespace cctz
-
-#endif // CCTZ_TIME_ZONE_FIXED_H_
+
+} // namespace cctz
+
+#endif // CCTZ_TIME_ZONE_FIXED_H_
diff --git a/contrib/libs/cctz/src/time_zone_format.cc b/contrib/libs/cctz/src/time_zone_format.cc
index b57371314e..21f000955f 100644
--- a/contrib/libs/cctz/src/time_zone_format.cc
+++ b/contrib/libs/cctz/src/time_zone_format.cc
@@ -1,68 +1,68 @@
-// 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
-//
+// 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.
-
-#if !defined(HAS_STRPTIME)
+//
+// 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.
+
+#if !defined(HAS_STRPTIME)
# if !defined(_MSC_VER) && !defined(__MINGW32__)
-# define HAS_STRPTIME 1 // assume everyone has strptime() except windows
-# endif
-#endif
-
+# 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>
-#include <cctype>
-#include <chrono>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <ctime>
-#include <limits>
-#include <string>
-#include <vector>
-#if !HAS_STRPTIME
-#include <iomanip>
-#include <sstream>
-#endif
-
+#include <cctype>
+#include <chrono>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <ctime>
+#include <limits>
+#include <string>
+#include <vector>
+#if !HAS_STRPTIME
+#include <iomanip>
+#include <sstream>
+#endif
+
#include "cctz/civil_time.h"
-#include "time_zone_if.h"
-
-namespace cctz {
-namespace detail {
-
-namespace {
-
-#if !HAS_STRPTIME
-// Build a strptime() using C++11's std::get_time().
-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;
+#include "time_zone_if.h"
+
+namespace cctz {
+namespace detail {
+
+namespace {
+
+#if !HAS_STRPTIME
+// Build a strptime() using C++11's std::get_time().
+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()));
-}
-#endif
-
+}
+#endif
+
// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
int ToTmWday(weekday wd) {
switch (wd) {
@@ -105,29 +105,29 @@ weekday FromTmWday(int tm_wday) {
return weekday::sunday; /*NOTREACHED*/
}
-std::tm ToTM(const time_zone::absolute_lookup& al) {
- std::tm tm{};
- tm.tm_sec = al.cs.second();
- tm.tm_min = al.cs.minute();
- tm.tm_hour = al.cs.hour();
- tm.tm_mday = al.cs.day();
- tm.tm_mon = al.cs.month() - 1;
-
- // Saturate tm.tm_year is cases of over/underflow.
- if (al.cs.year() < std::numeric_limits<int>::min() + 1900) {
- tm.tm_year = std::numeric_limits<int>::min();
- } else if (al.cs.year() - 1900 > std::numeric_limits<int>::max()) {
- tm.tm_year = std::numeric_limits<int>::max();
- } else {
- tm.tm_year = static_cast<int>(al.cs.year() - 1900);
- }
-
+std::tm ToTM(const time_zone::absolute_lookup& al) {
+ std::tm tm{};
+ tm.tm_sec = al.cs.second();
+ tm.tm_min = al.cs.minute();
+ tm.tm_hour = al.cs.hour();
+ tm.tm_mday = al.cs.day();
+ tm.tm_mon = al.cs.month() - 1;
+
+ // Saturate tm.tm_year is cases of over/underflow.
+ if (al.cs.year() < std::numeric_limits<int>::min() + 1900) {
+ tm.tm_year = std::numeric_limits<int>::min();
+ } else if (al.cs.year() - 1900 > std::numeric_limits<int>::max()) {
+ tm.tm_year = std::numeric_limits<int>::max();
+ } else {
+ 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_isdst = al.is_dst ? 1 : 0;
- return tm;
-}
-
+ 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) {
@@ -135,55 +135,55 @@ int ToWeek(const civil_day& cd, weekday week_start) {
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
-// to the caller of Format64() [and Format02d()/FormatOffset()] to ensure
-// that there is sufficient space before ep to hold the conversion.
-char* Format64(char* ep, int width, std::int_fast64_t v) {
- bool neg = false;
- if (v < 0) {
- --width;
- neg = true;
- if (v == std::numeric_limits<std::int_fast64_t>::min()) {
- // Avoid negating minimum value.
- std::int_fast64_t last_digit = -(v % 10);
- v /= 10;
- if (last_digit < 0) {
- ++v;
- last_digit += 10;
- }
- --width;
- *--ep = kDigits[last_digit];
- }
- v = -v;
- }
- do {
- --width;
- *--ep = kDigits[v % 10];
- } while (v /= 10);
- while (--width >= 0) *--ep = '0'; // zero pad
- if (neg) *--ep = '-';
- return ep;
-}
-
-// Formats [0 .. 99] as %02d.
-char* Format02d(char* ep, int v) {
- *--ep = kDigits[v % 10];
- *--ep = kDigits[(v / 10) % 10];
- return ep;
-}
-
-// Formats a UTC offset, like +00:00.
+const char kDigits[] = "0123456789";
+
+// Formats a 64-bit integer in the given field width. Note that it is up
+// to the caller of Format64() [and Format02d()/FormatOffset()] to ensure
+// that there is sufficient space before ep to hold the conversion.
+char* Format64(char* ep, int width, std::int_fast64_t v) {
+ bool neg = false;
+ if (v < 0) {
+ --width;
+ neg = true;
+ if (v == std::numeric_limits<std::int_fast64_t>::min()) {
+ // Avoid negating minimum value.
+ std::int_fast64_t last_digit = -(v % 10);
+ v /= 10;
+ if (last_digit < 0) {
+ ++v;
+ last_digit += 10;
+ }
+ --width;
+ *--ep = kDigits[last_digit];
+ }
+ v = -v;
+ }
+ do {
+ --width;
+ *--ep = kDigits[v % 10];
+ } while (v /= 10);
+ while (--width >= 0) *--ep = '0'; // zero pad
+ if (neg) *--ep = '-';
+ return ep;
+}
+
+// Formats [0 .. 99] as %02d.
+char* Format02d(char* ep, int v) {
+ *--ep = kDigits[v % 10];
+ *--ep = kDigits[(v / 10) % 10];
+ return ep;
+}
+
+// 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 sign = '+';
+ char sign = '+';
if (offset < 0) {
offset = -offset; // bounded by 24h so no overflow
- sign = '-';
- }
+ sign = '-';
+ }
const int seconds = offset % 60;
const int minutes = (offset /= 60) % 60;
const int hours = offset /= 60;
@@ -203,202 +203,202 @@ char* FormatOffset(char* ep, int offset, const char* mode) {
if (sep != '\0') *--ep = sep;
}
ep = Format02d(ep, hours);
- *--ep = sign;
- return ep;
-}
-
-// Formats a std::tm using strftime(3).
-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
+ *--ep = sign;
+ return ep;
+}
+
+// Formats a std::tm using strftime(3).
+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,
- // 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) {
- std::size_t buf_size = fmt.size() * i;
- std::vector<char> buf(buf_size);
- if (std::size_t len = strftime(&buf[0], buf_size, fmt.c_str(), &tm)) {
- out->append(&buf[0], len);
- return;
- }
- }
-}
-
-// Used for %E#S/%E#f specifiers and for data values in parse().
-template <typename T>
-const char* ParseInt(const char* dp, int width, T min, T max, T* vp) {
- if (dp != nullptr) {
- const T kmin = std::numeric_limits<T>::min();
- bool erange = false;
- bool neg = false;
- T value = 0;
- if (*dp == '-') {
- neg = true;
- if (width <= 0 || --width != 0) {
- ++dp;
- } else {
- dp = nullptr; // width was 1
- }
- }
- if (const char* const bp = dp) {
- while (const char* cp = strchr(kDigits, *dp)) {
- int d = static_cast<int>(cp - kDigits);
- if (d >= 10) break;
- if (value < kmin / 10) {
- erange = true;
- break;
- }
- value *= 10;
- if (value < kmin + d) {
- erange = true;
- break;
- }
- value -= d;
- dp += 1;
- if (width > 0 && --width == 0) break;
- }
- if (dp != bp && !erange && (neg || value != kmin)) {
- if (!neg || value != 0) {
- if (!neg) value = -value; // make positive
- if (min <= value && value <= max) {
- *vp = value;
- } else {
- dp = nullptr;
- }
- } else {
- dp = nullptr;
- }
- } else {
- dp = nullptr;
- }
- }
- }
- return dp;
-}
-
-// The number of base-10 digits that can be represented by a signed 64-bit
-// integer. That is, 10^kDigits10_64 <= 2^63 - 1 < 10^(kDigits10_64 + 1).
-const int kDigits10_64 = 18;
-
-// 10^n for everything that can be represented by a signed 64-bit integer.
-const std::int_fast64_t kExp10[kDigits10_64 + 1] = {
- 1,
- 10,
- 100,
- 1000,
- 10000,
- 100000,
- 1000000,
- 10000000,
- 100000000,
- 1000000000,
- 10000000000,
- 100000000000,
- 1000000000000,
- 10000000000000,
- 100000000000000,
- 1000000000000000,
- 10000000000000000,
- 100000000000000000,
- 1000000000000000000,
-};
-
-} // namespace
-
-// Uses strftime(3) to format the given Time. The following extended format
-// specifiers are also supported:
-//
+ // 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) {
+ std::size_t buf_size = fmt.size() * i;
+ std::vector<char> buf(buf_size);
+ if (std::size_t len = strftime(&buf[0], buf_size, fmt.c_str(), &tm)) {
+ out->append(&buf[0], len);
+ return;
+ }
+ }
+}
+
+// Used for %E#S/%E#f specifiers and for data values in parse().
+template <typename T>
+const char* ParseInt(const char* dp, int width, T min, T max, T* vp) {
+ if (dp != nullptr) {
+ const T kmin = std::numeric_limits<T>::min();
+ bool erange = false;
+ bool neg = false;
+ T value = 0;
+ if (*dp == '-') {
+ neg = true;
+ if (width <= 0 || --width != 0) {
+ ++dp;
+ } else {
+ dp = nullptr; // width was 1
+ }
+ }
+ if (const char* const bp = dp) {
+ while (const char* cp = strchr(kDigits, *dp)) {
+ int d = static_cast<int>(cp - kDigits);
+ if (d >= 10) break;
+ if (value < kmin / 10) {
+ erange = true;
+ break;
+ }
+ value *= 10;
+ if (value < kmin + d) {
+ erange = true;
+ break;
+ }
+ value -= d;
+ dp += 1;
+ if (width > 0 && --width == 0) break;
+ }
+ if (dp != bp && !erange && (neg || value != kmin)) {
+ if (!neg || value != 0) {
+ if (!neg) value = -value; // make positive
+ if (min <= value && value <= max) {
+ *vp = value;
+ } else {
+ dp = nullptr;
+ }
+ } else {
+ dp = nullptr;
+ }
+ } else {
+ dp = nullptr;
+ }
+ }
+ }
+ return dp;
+}
+
+// The number of base-10 digits that can be represented by a signed 64-bit
+// integer. That is, 10^kDigits10_64 <= 2^63 - 1 < 10^(kDigits10_64 + 1).
+const int kDigits10_64 = 18;
+
+// 10^n for everything that can be represented by a signed 64-bit integer.
+const std::int_fast64_t kExp10[kDigits10_64 + 1] = {
+ 1,
+ 10,
+ 100,
+ 1000,
+ 10000,
+ 100000,
+ 1000000,
+ 10000000,
+ 100000000,
+ 1000000000,
+ 10000000000,
+ 100000000000,
+ 1000000000000,
+ 10000000000000,
+ 100000000000000,
+ 1000000000000000,
+ 10000000000000000,
+ 100000000000000000,
+ 1000000000000000000,
+};
+
+} // namespace
+
+// 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)
-// - %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)
+// - %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"
-//
-// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
-// handled internally for performance reasons. strftime(3) is slow due to
-// a POSIX requirement to respect changes to ${TZ}.
-//
-// The TZ/GNU %s extension is handled internally because strftime() has
-// to use mktime() to generate it, and that assumes the local time zone.
-//
-// We also handle the %z and %Z specifiers to accommodate platforms that do
-// not support the tm_gmtoff and tm_zone extensions to std::tm.
-//
-// Requires that zero() <= fs < seconds(1).
+//
+// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
+// handled internally for performance reasons. strftime(3) is slow due to
+// a POSIX requirement to respect changes to ${TZ}.
+//
+// The TZ/GNU %s extension is handled internally because strftime() has
+// to use mktime() to generate it, and that assumes the local time zone.
+//
+// We also handle the %z and %Z specifiers to accommodate platforms that do
+// 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,
- const detail::femtoseconds& fs, const time_zone& tz) {
- std::string result;
- result.reserve(format.size()); // A reasonable guess for the result size.
- const time_zone::absolute_lookup al = tz.lookup(tp);
- const std::tm tm = ToTM(al);
-
- // Scratch buffer for internal conversions.
- char buf[3 + kDigits10_64]; // enough for longest conversion
- char* const ep = buf + sizeof(buf);
- char* bp; // works back from ep
-
- // Maintain three, disjoint subsequences that span format.
- // [format.begin() ... pending) : already formatted into result
- // [pending ... cur) : formatting pending, but no special cases
- // [cur ... format.end()) : unexamined
- // Initially, everything is in the unexamined part.
- const char* pending = format.c_str(); // NUL terminated
- const char* cur = pending;
- const char* end = pending + format.length();
-
- while (cur != end) { // while something is unexamined
- // Moves cur to the next percent sign.
- const char* start = cur;
- while (cur != end && *cur != '%') ++cur;
-
- // If the new pending text is all ordinary, copy it out.
- if (cur != start && pending == start) {
- result.append(pending, static_cast<std::size_t>(cur - pending));
- pending = start = cur;
- }
-
- // Span the sequential percent signs.
- const char* percent = cur;
- while (cur != end && *cur == '%') ++cur;
-
- // If the new pending text is all percents, copy out one
- // percent for every matched pair, then skip those pairs.
- if (cur != start && pending == start) {
- std::size_t escaped = static_cast<std::size_t>(cur - pending) / 2;
- result.append(pending, escaped);
- pending += escaped * 2;
- // Also copy out a single trailing percent.
- if (pending != cur && cur == end) {
- result.push_back(*pending++);
- }
- }
-
- // Loop unless we have an unescaped percent.
- if (cur == end || (cur - percent) % 2 == 0) continue;
-
- // Simple specifiers that we handle ourselves.
+ const detail::femtoseconds& fs, const time_zone& tz) {
+ std::string result;
+ result.reserve(format.size()); // A reasonable guess for the result size.
+ const time_zone::absolute_lookup al = tz.lookup(tp);
+ const std::tm tm = ToTM(al);
+
+ // Scratch buffer for internal conversions.
+ char buf[3 + kDigits10_64]; // enough for longest conversion
+ char* const ep = buf + sizeof(buf);
+ char* bp; // works back from ep
+
+ // Maintain three, disjoint subsequences that span format.
+ // [format.begin() ... pending) : already formatted into result
+ // [pending ... cur) : formatting pending, but no special cases
+ // [cur ... format.end()) : unexamined
+ // Initially, everything is in the unexamined part.
+ const char* pending = format.c_str(); // NUL terminated
+ const char* cur = pending;
+ const char* end = pending + format.length();
+
+ while (cur != end) { // while something is unexamined
+ // Moves cur to the next percent sign.
+ const char* start = cur;
+ while (cur != end && *cur != '%') ++cur;
+
+ // If the new pending text is all ordinary, copy it out.
+ if (cur != start && pending == start) {
+ result.append(pending, static_cast<std::size_t>(cur - pending));
+ pending = start = cur;
+ }
+
+ // Span the sequential percent signs.
+ const char* percent = cur;
+ while (cur != end && *cur == '%') ++cur;
+
+ // If the new pending text is all percents, copy out one
+ // percent for every matched pair, then skip those pairs.
+ if (cur != start && pending == start) {
+ std::size_t escaped = static_cast<std::size_t>(cur - pending) / 2;
+ result.append(pending, escaped);
+ pending += escaped * 2;
+ // Also copy out a single trailing percent.
+ if (pending != cur && cur == end) {
+ result.push_back(*pending++);
+ }
+ }
+
+ // Loop unless we have an unescaped percent.
+ if (cur == end || (cur - percent) % 2 == 0) continue;
+
+ // Simple specifiers that we handle ourselves.
if (strchr("YmdeUuWwHMSzZs%", *cur)) {
- if (cur - 1 != pending) {
- FormatTM(&result, std::string(pending, cur - 1), tm);
- }
- switch (*cur) {
- case 'Y':
- // This avoids the tm.tm_year overflow problem for %Y, however
- // tm.tm_year will still be used by other specifiers like %D.
- bp = Format64(ep, 0, al.cs.year());
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
- case 'm':
- bp = Format02d(ep, al.cs.month());
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
- case 'd':
- case 'e':
- bp = Format02d(ep, al.cs.day());
- if (*cur == 'e' && *bp == '0') *bp = ' '; // for Windows
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
+ if (cur - 1 != pending) {
+ FormatTM(&result, std::string(pending, cur - 1), tm);
+ }
+ switch (*cur) {
+ case 'Y':
+ // This avoids the tm.tm_year overflow problem for %Y, however
+ // tm.tm_year will still be used by other specifiers like %D.
+ bp = Format64(ep, 0, al.cs.year());
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'm':
+ bp = Format02d(ep, al.cs.month());
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'd':
+ case 'e':
+ bp = Format02d(ep, al.cs.day());
+ 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));
@@ -415,37 +415,37 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
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));
- break;
- case 'M':
- bp = Format02d(ep, al.cs.minute());
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
- case 'S':
- bp = Format02d(ep, al.cs.second());
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
- case 'z':
+ case 'H':
+ bp = Format02d(ep, al.cs.hour());
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'M':
+ bp = Format02d(ep, al.cs.minute());
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'S':
+ bp = Format02d(ep, al.cs.second());
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'z':
bp = FormatOffset(ep, al.offset, "");
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
- case 'Z':
- result.append(al.abbr);
- break;
- case 's':
- bp = Format64(ep, 0, ToUnixSeconds(tp));
- result.append(bp, static_cast<std::size_t>(ep - bp));
- break;
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
+ case 'Z':
+ result.append(al.abbr);
+ break;
+ case 's':
+ bp = Format64(ep, 0, ToUnixSeconds(tp));
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ break;
case '%':
result.push_back('%');
break;
- }
- pending = ++cur;
- continue;
- }
-
+ }
+ pending = ++cur;
+ continue;
+ }
+
// More complex specifiers that we handle ourselves.
if (*cur == ':' && cur + 1 != end) {
if (*(cur + 1) == 'z') {
@@ -484,10 +484,10 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
}
}
- // Loop if there is no E modifier.
- if (*cur != 'E' || ++cur == end) continue;
-
- // Format our extensions.
+ // 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) {
@@ -496,13 +496,13 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
result.append("T");
pending = ++cur;
} else if (*cur == 'z') {
- // Formats %Ez.
- if (cur - 2 != pending) {
- FormatTM(&result, std::string(pending, cur - 2), tm);
- }
+ // Formats %Ez.
+ 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;
+ 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) {
@@ -511,81 +511,81 @@ std::string format(const std::string& format, const time_point<seconds>& tp,
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.
- if (cur - 2 != pending) {
- FormatTM(&result, std::string(pending, cur - 2), tm);
- }
- char* cp = ep;
- bp = Format64(cp, 15, fs.count());
- while (cp != bp && cp[-1] == '0') --cp;
- switch (*(cur + 1)) {
- case 'S':
- if (cp != bp) *--bp = '.';
- bp = Format02d(bp, al.cs.second());
- break;
- case 'f':
- if (cp == bp) *--bp = '0';
- break;
- }
- result.append(bp, static_cast<std::size_t>(cp - bp));
- pending = cur += 2;
- } else if (*cur == '4' && cur + 1 != end && *(cur + 1) == 'Y') {
- // Formats %E4Y.
- if (cur - 2 != pending) {
- FormatTM(&result, std::string(pending, cur - 2), tm);
- }
- bp = Format64(ep, 4, al.cs.year());
- result.append(bp, static_cast<std::size_t>(ep - bp));
- pending = cur += 2;
- } else if (std::isdigit(*cur)) {
- // Possibly found %E#S or %E#f.
- int n = 0;
- if (const char* np = ParseInt(cur, 0, 0, 1024, &n)) {
- if (*np == 'S' || *np == 'f') {
- // Formats %E#S or %E#f.
- if (cur - 2 != pending) {
- FormatTM(&result, std::string(pending, cur - 2), tm);
- }
- bp = ep;
- if (n > 0) {
- if (n > kDigits10_64) n = kDigits10_64;
- bp = Format64(bp, n, (n > 15) ? fs.count() * kExp10[n - 15]
- : fs.count() / kExp10[15 - n]);
- if (*np == 'S') *--bp = '.';
- }
- if (*np == 'S') bp = Format02d(bp, al.cs.second());
- result.append(bp, static_cast<std::size_t>(ep - bp));
- pending = cur = ++np;
- }
- }
- }
- }
-
- // Formats any remaining data.
- if (end != pending) {
- FormatTM(&result, std::string(pending, end), tm);
- }
-
- return result;
-}
-
-namespace {
-
+ } else if (*cur == '*' && cur + 1 != end &&
+ (*(cur + 1) == 'S' || *(cur + 1) == 'f')) {
+ // Formats %E*S or %E*F.
+ if (cur - 2 != pending) {
+ FormatTM(&result, std::string(pending, cur - 2), tm);
+ }
+ char* cp = ep;
+ bp = Format64(cp, 15, fs.count());
+ while (cp != bp && cp[-1] == '0') --cp;
+ switch (*(cur + 1)) {
+ case 'S':
+ if (cp != bp) *--bp = '.';
+ bp = Format02d(bp, al.cs.second());
+ break;
+ case 'f':
+ if (cp == bp) *--bp = '0';
+ break;
+ }
+ result.append(bp, static_cast<std::size_t>(cp - bp));
+ pending = cur += 2;
+ } else if (*cur == '4' && cur + 1 != end && *(cur + 1) == 'Y') {
+ // Formats %E4Y.
+ if (cur - 2 != pending) {
+ FormatTM(&result, std::string(pending, cur - 2), tm);
+ }
+ bp = Format64(ep, 4, al.cs.year());
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur += 2;
+ } else if (std::isdigit(*cur)) {
+ // Possibly found %E#S or %E#f.
+ int n = 0;
+ if (const char* np = ParseInt(cur, 0, 0, 1024, &n)) {
+ if (*np == 'S' || *np == 'f') {
+ // Formats %E#S or %E#f.
+ if (cur - 2 != pending) {
+ FormatTM(&result, std::string(pending, cur - 2), tm);
+ }
+ bp = ep;
+ if (n > 0) {
+ if (n > kDigits10_64) n = kDigits10_64;
+ bp = Format64(bp, n, (n > 15) ? fs.count() * kExp10[n - 15]
+ : fs.count() / kExp10[15 - n]);
+ if (*np == 'S') *--bp = '.';
+ }
+ if (*np == 'S') bp = Format02d(bp, al.cs.second());
+ result.append(bp, static_cast<std::size_t>(ep - bp));
+ pending = cur = ++np;
+ }
+ }
+ }
+ }
+
+ // Formats any remaining data.
+ if (end != pending) {
+ FormatTM(&result, std::string(pending, end), tm);
+ }
+
+ return result;
+}
+
+namespace {
+
const char* ParseOffset(const char* dp, const char* mode, int* offset) {
- if (dp != nullptr) {
+ if (dp != nullptr) {
const char first = *dp++;
if (first == '+' || first == '-') {
char sep = mode[0];
- int hours = 0;
+ int hours = 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);
+ 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;
@@ -594,60 +594,60 @@ const char* ParseOffset(const char* dp, const char* mode, int* offset) {
}
*offset = ((hours * 60 + minutes) * 60) + seconds;
if (first == '-') *offset = -*offset;
- } else {
- dp = nullptr;
- }
+ } else {
+ dp = nullptr;
+ }
} else if (first == 'Z' || first == 'z') { // Zulu
*offset = 0;
- } else {
- dp = nullptr;
- }
- }
- return dp;
-}
-
-const char* ParseZone(const char* dp, std::string* zone) {
- zone->clear();
- if (dp != nullptr) {
- while (*dp != '\0' && !std::isspace(*dp)) zone->push_back(*dp++);
- if (zone->empty()) dp = nullptr;
- }
- return dp;
-}
-
-const char* ParseSubSeconds(const char* dp, detail::femtoseconds* subseconds) {
- if (dp != nullptr) {
- std::int_fast64_t v = 0;
- std::int_fast64_t exp = 0;
- const char* const bp = dp;
- while (const char* cp = strchr(kDigits, *dp)) {
- int d = static_cast<int>(cp - kDigits);
- if (d >= 10) break;
- if (exp < 15) {
- exp += 1;
- v *= 10;
- v += d;
- }
- ++dp;
- }
- if (dp != bp) {
- v *= kExp10[15 - exp];
- *subseconds = detail::femtoseconds(v);
- } else {
- dp = nullptr;
- }
- }
- return dp;
-}
-
-// Parses a string into a std::tm using strptime(3).
-const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
- if (dp != nullptr) {
- dp = strptime(dp, fmt, tm);
- }
- return dp;
-}
-
+ } else {
+ dp = nullptr;
+ }
+ }
+ return dp;
+}
+
+const char* ParseZone(const char* dp, std::string* zone) {
+ zone->clear();
+ if (dp != nullptr) {
+ while (*dp != '\0' && !std::isspace(*dp)) zone->push_back(*dp++);
+ if (zone->empty()) dp = nullptr;
+ }
+ return dp;
+}
+
+const char* ParseSubSeconds(const char* dp, detail::femtoseconds* subseconds) {
+ if (dp != nullptr) {
+ std::int_fast64_t v = 0;
+ std::int_fast64_t exp = 0;
+ const char* const bp = dp;
+ while (const char* cp = strchr(kDigits, *dp)) {
+ int d = static_cast<int>(cp - kDigits);
+ if (d >= 10) break;
+ if (exp < 15) {
+ exp += 1;
+ v *= 10;
+ v += d;
+ }
+ ++dp;
+ }
+ if (dp != bp) {
+ v *= kExp10[15 - exp];
+ *subseconds = detail::femtoseconds(v);
+ } else {
+ dp = nullptr;
+ }
+ }
+ return dp;
+}
+
+// Parses a string into a std::tm using strptime(3).
+const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) {
+ if (dp != nullptr) {
+ dp = strptime(dp, fmt, 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.
@@ -668,102 +668,102 @@ bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
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
+} // 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'.
-//
-// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
-// handled internally so that we can normally avoid strptime() altogether
-// (which is particularly helpful when the native implementation is broken).
-//
-// The TZ/GNU %s extension is handled internally because strptime() has to
-// use localtime_r() to generate it, and that assumes the local time zone.
-//
-// 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,
+//
+// The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are
+// handled internally so that we can normally avoid strptime() altogether
+// (which is particularly helpful when the native implementation is broken).
+//
+// The TZ/GNU %s extension is handled internally because strptime() has to
+// use localtime_r() to generate it, and that assumes the local time zone.
+//
+// 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,
- detail::femtoseconds* fs, std::string* err) {
- // The unparsed input.
- const char* data = input.c_str(); // NUL terminated
-
- // Skips leading whitespace.
- while (std::isspace(*data)) ++data;
-
- const year_t kyearmax = std::numeric_limits<year_t>::max();
- const year_t kyearmin = std::numeric_limits<year_t>::min();
-
- // Sets default values for unspecified fields.
- bool saw_year = false;
- year_t year = 1970;
- std::tm tm{};
- tm.tm_year = 1970 - 1900;
- tm.tm_mon = 1 - 1; // Jan
- tm.tm_mday = 1;
- tm.tm_hour = 0;
- tm.tm_min = 0;
- tm.tm_sec = 0;
- tm.tm_wday = 4; // Thu
- tm.tm_yday = 0;
- tm.tm_isdst = 0;
- auto subseconds = detail::femtoseconds::zero();
- bool saw_offset = false;
- int offset = 0; // No offset from passed tz.
- std::string zone = "UTC";
-
- const char* fmt = format.c_str(); // NUL terminated
- bool twelve_hour = false;
- bool afternoon = false;
+ detail::femtoseconds* fs, std::string* err) {
+ // The unparsed input.
+ const char* data = input.c_str(); // NUL terminated
+
+ // Skips leading whitespace.
+ while (std::isspace(*data)) ++data;
+
+ const year_t kyearmax = std::numeric_limits<year_t>::max();
+ const year_t kyearmin = std::numeric_limits<year_t>::min();
+
+ // Sets default values for unspecified fields.
+ bool saw_year = false;
+ year_t year = 1970;
+ std::tm tm{};
+ tm.tm_year = 1970 - 1900;
+ tm.tm_mon = 1 - 1; // Jan
+ tm.tm_mday = 1;
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ tm.tm_wday = 4; // Thu
+ tm.tm_yday = 0;
+ tm.tm_isdst = 0;
+ auto subseconds = detail::femtoseconds::zero();
+ bool saw_offset = false;
+ int offset = 0; // No offset from passed tz.
+ std::string zone = "UTC";
+
+ const char* fmt = format.c_str(); // NUL terminated
+ bool twelve_hour = false;
+ bool afternoon = false;
int week_num = -1;
weekday week_start = weekday::sunday;
-
- bool saw_percent_s = false;
- std::int_fast64_t percent_s = 0;
-
- // Steps through format, one specifier at a time.
- while (data != nullptr && *fmt != '\0') {
- if (std::isspace(*fmt)) {
- while (std::isspace(*data)) ++data;
- while (std::isspace(*++fmt)) continue;
- continue;
- }
-
- if (*fmt != '%') {
- if (*data == *fmt) {
- ++data;
- ++fmt;
- } else {
- data = nullptr;
- }
- continue;
- }
-
- const char* percent = fmt;
- if (*++fmt == '\0') {
- data = nullptr;
- continue;
- }
- switch (*fmt++) {
- case 'Y':
- // Symmetrically with FormatTime(), directly handing %Y avoids the
- // tm.tm_year overflow problem. However, tm.tm_year will still be
- // used by other specifiers like %D.
- data = ParseInt(data, 0, kyearmin, kyearmax, &year);
- if (data != nullptr) saw_year = true;
- continue;
- case 'm':
- data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
- if (data != nullptr) tm.tm_mon -= 1;
+
+ bool saw_percent_s = false;
+ std::int_fast64_t percent_s = 0;
+
+ // Steps through format, one specifier at a time.
+ while (data != nullptr && *fmt != '\0') {
+ if (std::isspace(*fmt)) {
+ while (std::isspace(*data)) ++data;
+ while (std::isspace(*++fmt)) continue;
+ continue;
+ }
+
+ if (*fmt != '%') {
+ if (*data == *fmt) {
+ ++data;
+ ++fmt;
+ } else {
+ data = nullptr;
+ }
+ continue;
+ }
+
+ const char* percent = fmt;
+ if (*++fmt == '\0') {
+ data = nullptr;
+ continue;
+ }
+ switch (*fmt++) {
+ case 'Y':
+ // Symmetrically with FormatTime(), directly handing %Y avoids the
+ // tm.tm_year overflow problem. However, tm.tm_year will still be
+ // used by other specifiers like %D.
+ data = ParseInt(data, 0, kyearmin, kyearmax, &year);
+ if (data != nullptr) saw_year = true;
+ continue;
+ case 'm':
+ data = ParseInt(data, 2, 1, 12, &tm.tm_mon);
+ if (data != nullptr) tm.tm_mon -= 1;
week_num = -1;
- continue;
- case 'd':
+ continue;
+ case 'd':
case 'e':
- data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
+ data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
week_num = -1;
- continue;
+ continue;
case 'U':
data = ParseInt(data, 0, 0, 53, &week_num);
week_start = weekday::sunday;
@@ -779,41 +779,41 @@ bool parse(const std::string& format, const std::string& input,
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;
- continue;
- case 'M':
- data = ParseInt(data, 2, 0, 59, &tm.tm_min);
- continue;
- case 'S':
- data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
- continue;
- case 'I':
- case 'l':
- case 'r': // probably uses %I
- twelve_hour = true;
- break;
- case 'R': // uses %H
- case 'T': // uses %H
- case 'c': // probably uses %H
- case 'X': // probably uses %H
- twelve_hour = false;
- break;
- case 'z':
+ case 'H':
+ data = ParseInt(data, 2, 0, 23, &tm.tm_hour);
+ twelve_hour = false;
+ continue;
+ case 'M':
+ data = ParseInt(data, 2, 0, 59, &tm.tm_min);
+ continue;
+ case 'S':
+ data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+ continue;
+ case 'I':
+ case 'l':
+ case 'r': // probably uses %I
+ twelve_hour = true;
+ break;
+ case 'R': // uses %H
+ case 'T': // uses %H
+ case 'c': // probably uses %H
+ case 'X': // probably uses %H
+ twelve_hour = false;
+ break;
+ case 'z':
data = ParseOffset(data, "", &offset);
- if (data != nullptr) saw_offset = true;
- continue;
- case 'Z': // ignored; zone abbreviations are ambiguous
- data = ParseZone(data, &zone);
- continue;
- case 's':
- data = ParseInt(data, 0,
- std::numeric_limits<std::int_fast64_t>::min(),
- std::numeric_limits<std::int_fast64_t>::max(),
- &percent_s);
- if (data != nullptr) saw_percent_s = true;
- continue;
+ if (data != nullptr) saw_offset = true;
+ continue;
+ case 'Z': // ignored; zone abbreviations are ambiguous
+ data = ParseZone(data, &zone);
+ continue;
+ case 's':
+ data = ParseInt(data, 0,
+ std::numeric_limits<std::int_fast64_t>::min(),
+ std::numeric_limits<std::int_fast64_t>::max(),
+ &percent_s);
+ if (data != nullptr) saw_percent_s = true;
+ continue;
case ':':
if (fmt[0] == 'z' ||
(fmt[0] == ':' &&
@@ -827,148 +827,148 @@ bool parse(const std::string& format, const std::string& input,
case '%':
data = (*data == '%' ? data + 1 : nullptr);
continue;
- case 'E':
+ case 'E':
if (fmt[0] == 'T') {
if (*data == 'T' || *data == 't') {
++data;
++fmt;
- } else {
+ } else {
data = nullptr;
- }
+ }
continue;
}
if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
data = ParseOffset(data, ":", &offset);
- if (data != nullptr) saw_offset = true;
+ if (data != nullptr) saw_offset = true;
fmt += (fmt[0] == 'z') ? 1 : 2;
- continue;
- }
+ continue;
+ }
if (fmt[0] == '*' && fmt[1] == 'S') {
- data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
- if (data != nullptr && *data == '.') {
- data = ParseSubSeconds(data + 1, &subseconds);
- }
- fmt += 2;
- continue;
- }
+ data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+ if (data != nullptr && *data == '.') {
+ data = ParseSubSeconds(data + 1, &subseconds);
+ }
+ fmt += 2;
+ continue;
+ }
if (fmt[0] == '*' && fmt[1] == 'f') {
- if (data != nullptr && std::isdigit(*data)) {
- data = ParseSubSeconds(data, &subseconds);
- }
- fmt += 2;
- continue;
- }
+ if (data != nullptr && std::isdigit(*data)) {
+ data = ParseSubSeconds(data, &subseconds);
+ }
+ fmt += 2;
+ continue;
+ }
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) {
- if (data - bp == 4) {
- saw_year = true;
- } else {
- data = nullptr; // stopped too soon
- }
- }
- fmt += 2;
- continue;
- }
- if (std::isdigit(*fmt)) {
- int n = 0; // value ignored
- if (const char* np = ParseInt(fmt, 0, 0, 1024, &n)) {
- if (*np == 'S') {
- data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
- if (data != nullptr && *data == '.') {
- data = ParseSubSeconds(data + 1, &subseconds);
- }
- fmt = ++np;
- continue;
- }
- if (*np == 'f') {
- if (data != nullptr && std::isdigit(*data)) {
- data = ParseSubSeconds(data, &subseconds);
- }
- fmt = ++np;
- continue;
- }
- }
- }
- if (*fmt == 'c') twelve_hour = false; // probably uses %H
- if (*fmt == 'X') twelve_hour = false; // probably uses %H
- if (*fmt != '\0') ++fmt;
- break;
- case 'O':
- if (*fmt == 'H') twelve_hour = false;
- if (*fmt == 'I') twelve_hour = true;
- if (*fmt != '\0') ++fmt;
- break;
- }
-
- // Parses the current specifier.
- const char* orig_data = data;
- std::string spec(percent, static_cast<std::size_t>(fmt - percent));
- data = ParseTM(data, spec.c_str(), &tm);
-
- // If we successfully parsed %p we need to remember whether the result
+ const char* bp = data;
+ data = ParseInt(data, 4, year_t{-999}, year_t{9999}, &year);
+ if (data != nullptr) {
+ if (data - bp == 4) {
+ saw_year = true;
+ } else {
+ data = nullptr; // stopped too soon
+ }
+ }
+ fmt += 2;
+ continue;
+ }
+ if (std::isdigit(*fmt)) {
+ int n = 0; // value ignored
+ if (const char* np = ParseInt(fmt, 0, 0, 1024, &n)) {
+ if (*np == 'S') {
+ data = ParseInt(data, 2, 0, 60, &tm.tm_sec);
+ if (data != nullptr && *data == '.') {
+ data = ParseSubSeconds(data + 1, &subseconds);
+ }
+ fmt = ++np;
+ continue;
+ }
+ if (*np == 'f') {
+ if (data != nullptr && std::isdigit(*data)) {
+ data = ParseSubSeconds(data, &subseconds);
+ }
+ fmt = ++np;
+ continue;
+ }
+ }
+ }
+ if (*fmt == 'c') twelve_hour = false; // probably uses %H
+ if (*fmt == 'X') twelve_hour = false; // probably uses %H
+ if (*fmt != '\0') ++fmt;
+ break;
+ case 'O':
+ if (*fmt == 'H') twelve_hour = false;
+ if (*fmt == 'I') twelve_hour = true;
+ if (*fmt != '\0') ++fmt;
+ break;
+ }
+
+ // Parses the current specifier.
+ const char* orig_data = data;
+ std::string spec(percent, static_cast<std::size_t>(fmt - percent));
+ 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().
- // So reparse the input with a known AM hour, and check if it is shifted
- // to a PM hour.
- if (spec == "%p" && data != nullptr) {
- std::string test_input = "1";
- test_input.append(orig_data, static_cast<std::size_t>(data - orig_data));
- const char* test_data = test_input.c_str();
- std::tm tmp{};
- ParseTM(test_data, "%I%p", &tmp);
- afternoon = (tmp.tm_hour == 13);
- }
- }
-
- // Adjust a 12-hour tm_hour value if it should be in the afternoon.
- if (twelve_hour && afternoon && tm.tm_hour < 12) {
- tm.tm_hour += 12;
- }
-
- if (data == nullptr) {
- if (err != nullptr) *err = "Failed to parse input";
- return false;
- }
-
- // Skip any remaining whitespace.
- while (std::isspace(*data)) ++data;
-
- // parse() must consume the entire input string.
- if (*data != '\0') {
- if (err != nullptr) *err = "Illegal trailing data in input string";
- return false;
- }
-
- // If we saw %s then we ignore anything else and return that time.
- if (saw_percent_s) {
- *sec = FromUnixSeconds(percent_s);
- *fs = detail::femtoseconds::zero();
- return true;
- }
-
+ // So reparse the input with a known AM hour, and check if it is shifted
+ // to a PM hour.
+ if (spec == "%p" && data != nullptr) {
+ std::string test_input = "1";
+ test_input.append(orig_data, static_cast<std::size_t>(data - orig_data));
+ const char* test_data = test_input.c_str();
+ std::tm tmp{};
+ ParseTM(test_data, "%I%p", &tmp);
+ afternoon = (tmp.tm_hour == 13);
+ }
+ }
+
+ // Adjust a 12-hour tm_hour value if it should be in the afternoon.
+ if (twelve_hour && afternoon && tm.tm_hour < 12) {
+ tm.tm_hour += 12;
+ }
+
+ if (data == nullptr) {
+ if (err != nullptr) *err = "Failed to parse input";
+ return false;
+ }
+
+ // Skip any remaining whitespace.
+ while (std::isspace(*data)) ++data;
+
+ // parse() must consume the entire input string.
+ if (*data != '\0') {
+ if (err != nullptr) *err = "Illegal trailing data in input string";
+ return false;
+ }
+
+ // If we saw %s then we ignore anything else and return that time.
+ if (saw_percent_s) {
+ *sec = FromUnixSeconds(percent_s);
+ *fs = detail::femtoseconds::zero();
+ 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
- // the fields directly in the passed time_zone.
- time_zone ptz = saw_offset ? utc_time_zone() : tz;
-
- // Allows a leap second of 60 to normalize forward to the following ":00".
- if (tm.tm_sec == 60) {
- tm.tm_sec -= 1;
- offset -= 1;
- subseconds = detail::femtoseconds::zero();
- }
-
- if (!saw_year) {
- year = year_t{tm.tm_year};
- if (year > kyearmax - 1900) {
- // Platform-dependent, maybe unreachable.
- if (err != nullptr) *err = "Out-of-range year";
- return false;
- }
- year += 1900;
- }
-
+ // the fields directly in the passed time_zone.
+ time_zone ptz = saw_offset ? utc_time_zone() : tz;
+
+ // Allows a leap second of 60 to normalize forward to the following ":00".
+ if (tm.tm_sec == 60) {
+ tm.tm_sec -= 1;
+ offset -= 1;
+ subseconds = detail::femtoseconds::zero();
+ }
+
+ if (!saw_year) {
+ year = year_t{tm.tm_year};
+ if (year > kyearmax - 1900) {
+ // Platform-dependent, maybe unreachable.
+ if (err != nullptr) *err = "Out-of-range year";
+ return false;
+ }
+ 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)) {
@@ -977,46 +977,46 @@ bool parse(const std::string& format, const std::string& input,
}
}
- const int month = tm.tm_mon + 1;
- civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
-
- // parse() should not allow normalization. Due to the restricted field
- // ranges above (see ParseInt()), the only possibility is for days to roll
- // into months. That is, parsing "Sep 31" should not produce "Oct 1".
- if (cs.month() != month || cs.day() != tm.tm_mday) {
- if (err != nullptr) *err = "Out-of-range field";
- return false;
- }
-
- // Accounts for the offset adjustment before converting to absolute time.
- if ((offset < 0 && cs > civil_second::max() + offset) ||
- (offset > 0 && cs < civil_second::min() + offset)) {
- if (err != nullptr) *err = "Out-of-range field";
- return false;
- }
- cs -= offset;
-
- const auto tp = ptz.lookup(cs).pre;
- // Checks for overflow/underflow and returns an error as necessary.
+ const int month = tm.tm_mon + 1;
+ civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ // parse() should not allow normalization. Due to the restricted field
+ // ranges above (see ParseInt()), the only possibility is for days to roll
+ // into months. That is, parsing "Sep 31" should not produce "Oct 1".
+ if (cs.month() != month || cs.day() != tm.tm_mday) {
+ if (err != nullptr) *err = "Out-of-range field";
+ return false;
+ }
+
+ // Accounts for the offset adjustment before converting to absolute time.
+ if ((offset < 0 && cs > civil_second::max() + offset) ||
+ (offset > 0 && cs < civil_second::min() + offset)) {
+ if (err != nullptr) *err = "Out-of-range field";
+ return false;
+ }
+ cs -= offset;
+
+ 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 (cs > al.cs) {
- if (err != nullptr) *err = "Out-of-range field";
- return false;
- }
- }
+ 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 (cs < al.cs) {
- if (err != nullptr) *err = "Out-of-range field";
- return false;
- }
- }
-
- *sec = tp;
- *fs = subseconds;
- return true;
-}
-
-} // namespace detail
-} // namespace cctz
+ if (cs < al.cs) {
+ if (err != nullptr) *err = "Out-of-range field";
+ return false;
+ }
+ }
+
+ *sec = tp;
+ *fs = subseconds;
+ return true;
+}
+
+} // namespace detail
+} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_if.cc b/contrib/libs/cctz/src/time_zone_if.cc
index a80dbcd60d..e2b5381e2c 100644
--- a/contrib/libs/cctz/src/time_zone_if.cc
+++ b/contrib/libs/cctz/src/time_zone_if.cc
@@ -1,36 +1,36 @@
-// 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
-//
+// 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 "time_zone_if.h"
-#include "time_zone_info.h"
-#include "time_zone_libc.h"
-
-namespace cctz {
-
-std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) {
- // Support "libc:localtime" and "libc:*" to access the legacy
- // localtime and UTC support respectively from the C library.
- if (name.compare(0, 5, "libc:") == 0) {
- return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5)));
- }
-
- // Otherwise use the "zoneinfo" implementation by default.
- std::unique_ptr<TimeZoneInfo> tz(new TimeZoneInfo);
- if (!tz->Load(name)) tz.reset();
- return std::unique_ptr<TimeZoneIf>(tz.release());
-}
-
+//
+// 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 "time_zone_if.h"
+#include "time_zone_info.h"
+#include "time_zone_libc.h"
+
+namespace cctz {
+
+std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) {
+ // Support "libc:localtime" and "libc:*" to access the legacy
+ // localtime and UTC support respectively from the C library.
+ if (name.compare(0, 5, "libc:") == 0) {
+ return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5)));
+ }
+
+ // Otherwise use the "zoneinfo" implementation by default.
+ std::unique_ptr<TimeZoneInfo> tz(new TimeZoneInfo);
+ if (!tz->Load(name)) tz.reset();
+ return std::unique_ptr<TimeZoneIf>(tz.release());
+}
+
// Defined out-of-line to avoid emitting a weak vtable in all TUs.
TimeZoneIf::~TimeZoneIf() {}
@@ -42,4 +42,4 @@ std::int_fast64_t TimePointToUnixSeconds(const time_point<seconds>& tp) {
return ToUnixSeconds(tp);
}
-} // namespace cctz
+} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_if.h b/contrib/libs/cctz/src/time_zone_if.h
index f925c6c55a..c7d7f9ae69 100644
--- a/contrib/libs/cctz/src/time_zone_if.h
+++ b/contrib/libs/cctz/src/time_zone_if.h
@@ -1,68 +1,68 @@
-// 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
-//
+// 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.
-
-#ifndef CCTZ_TIME_ZONE_IF_H_
-#define CCTZ_TIME_ZONE_IF_H_
-
-#include <chrono>
-#include <cstdint>
-#include <memory>
-#include <string>
-
+//
+// 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.
+
+#ifndef CCTZ_TIME_ZONE_IF_H_
+#define CCTZ_TIME_ZONE_IF_H_
+
+#include <chrono>
+#include <cstdint>
+#include <memory>
+#include <string>
+
#include "cctz/civil_time.h"
#include "cctz/time_zone.h"
-
-namespace cctz {
-
-// A simple interface used to hide time-zone complexities from time_zone::Impl.
-// Subclasses implement the functions for civil-time conversions in the zone.
-class TimeZoneIf {
- public:
- // A factory function for TimeZoneIf implementations.
- static std::unique_ptr<TimeZoneIf> Load(const std::string& name);
-
+
+namespace cctz {
+
+// A simple interface used to hide time-zone complexities from time_zone::Impl.
+// Subclasses implement the functions for civil-time conversions in the zone.
+class TimeZoneIf {
+ public:
+ // A factory function for TimeZoneIf implementations.
+ static std::unique_ptr<TimeZoneIf> Load(const std::string& name);
+
virtual ~TimeZoneIf();
-
- virtual time_zone::absolute_lookup BreakTime(
+
+ virtual time_zone::absolute_lookup BreakTime(
const time_point<seconds>& tp) const = 0;
- virtual time_zone::civil_lookup MakeTime(
- const civil_second& cs) 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 std::string Description() const = 0;
-
- protected:
- TimeZoneIf() {}
-};
-
+ 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
-// Unix clock are second aligned, but not that they share an epoch.
+// 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 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
-
-#endif // CCTZ_TIME_ZONE_IF_H_
+}
+
+} // namespace cctz
+
+#endif // CCTZ_TIME_ZONE_IF_H_
diff --git a/contrib/libs/cctz/src/time_zone_impl.cc b/contrib/libs/cctz/src/time_zone_impl.cc
index 6e077505c1..1df9d33a3f 100644
--- a/contrib/libs/cctz/src/time_zone_impl.cc
+++ b/contrib/libs/cctz/src/time_zone_impl.cc
@@ -1,90 +1,90 @@
-// 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
-//
+// 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 "time_zone_impl.h"
-
+//
+// 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 "time_zone_impl.h"
+
#include <deque>
#include <memory>
-#include <mutex>
-#include <string>
-#include <unordered_map>
-#include <utility>
-
-#include "time_zone_fixed.h"
-
-namespace cctz {
-
-namespace {
-
-// time_zone::Impls are linked into a map to support fast lookup by name.
-using TimeZoneImplByName =
- std::unordered_map<std::string, const time_zone::Impl*>;
-TimeZoneImplByName* time_zone_map = nullptr;
-
-// Mutual exclusion for time_zone_map.
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <utility>
+
+#include "time_zone_fixed.h"
+
+namespace cctz {
+
+namespace {
+
+// time_zone::Impls are linked into a map to support fast lookup by name.
+using TimeZoneImplByName =
+ std::unordered_map<std::string, const time_zone::Impl*>;
+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;
}
-
-} // namespace
-
-time_zone time_zone::Impl::UTC() {
- return time_zone(UTCImpl());
-}
-
-bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
+
+} // namespace
+
+time_zone time_zone::Impl::UTC() {
+ return time_zone(UTCImpl());
+}
+
+bool time_zone::Impl::LoadTimeZone(const std::string& name, time_zone* tz) {
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()) {
- *tz = time_zone(utc_impl);
- return true;
- }
-
+ *tz = time_zone(utc_impl);
+ return true;
+ }
+
// Check whether the time zone has already been loaded.
- {
+ {
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()) {
- *tz = time_zone(itr->second);
- return itr->second != utc_impl;
- }
- }
- }
-
+ if (time_zone_map != nullptr) {
+ TimeZoneImplByName::const_iterator itr = time_zone_map->find(name);
+ if (itr != time_zone_map->end()) {
+ *tz = time_zone(itr->second);
+ return itr->second != utc_impl;
+ }
+ }
+ }
+
// 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 (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;
- }
- *tz = time_zone(impl);
- return impl != utc_impl;
-}
-
-void time_zone::Impl::ClearTimeZoneMapTestOnly() {
+ }
+ *tz = time_zone(impl);
+ return impl != utc_impl;
+}
+
+void time_zone::Impl::ClearTimeZoneMapTestOnly() {
std::lock_guard<std::mutex> lock(TimeZoneMutex());
- if (time_zone_map != nullptr) {
+ 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
@@ -93,16 +93,16 @@ void time_zone::Impl::ClearTimeZoneMapTestOnly() {
for (const auto& element : *time_zone_map) {
cleared->push_back(element.second);
}
- time_zone_map->clear();
- }
-}
-
+ time_zone_map->clear();
+ }
+}
+
time_zone::Impl::Impl(const std::string& name)
: name_(name), zone_(TimeZoneIf::Load(name_)) {}
-
-const time_zone::Impl* time_zone::Impl::UTCImpl() {
+
+const time_zone::Impl* time_zone::Impl::UTCImpl() {
static const Impl* utc_impl = new Impl("UTC"); // never fails
- return utc_impl;
-}
-
-} // namespace cctz
+ return utc_impl;
+}
+
+} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_impl.h b/contrib/libs/cctz/src/time_zone_impl.h
index 23fcddb690..00341c4d82 100644
--- a/contrib/libs/cctz/src/time_zone_impl.h
+++ b/contrib/libs/cctz/src/time_zone_impl.h
@@ -1,86 +1,86 @@
-// 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
-//
+// 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.
-
-#ifndef CCTZ_TIME_ZONE_IMPL_H_
-#define CCTZ_TIME_ZONE_IMPL_H_
-
-#include <memory>
-#include <string>
-
+//
+// 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.
+
+#ifndef CCTZ_TIME_ZONE_IMPL_H_
+#define CCTZ_TIME_ZONE_IMPL_H_
+
+#include <memory>
+#include <string>
+
#include "cctz/civil_time.h"
#include "cctz/time_zone.h"
-#include "time_zone_if.h"
-#include "time_zone_info.h"
-
-namespace cctz {
-
-// time_zone::Impl is the internal object referenced by a cctz::time_zone.
-class time_zone::Impl {
- public:
- // The UTC time zone. Also used for other time zones that fail to load.
- static time_zone UTC();
-
- // Load a named time zone. Returns false if the name is invalid, or if
- // some other kind of error occurs. Note that loading "UTC" never fails.
- static bool LoadTimeZone(const std::string& name, time_zone* tz);
-
- // Clears the map of cached time zones. Primarily for use in benchmarks
- // that gauge the performance of loading/parsing the time-zone data.
- static void ClearTimeZoneMapTestOnly();
-
- // The primary key is the time-zone ID (e.g., "America/New_York").
+#include "time_zone_if.h"
+#include "time_zone_info.h"
+
+namespace cctz {
+
+// time_zone::Impl is the internal object referenced by a cctz::time_zone.
+class time_zone::Impl {
+ public:
+ // The UTC time zone. Also used for other time zones that fail to load.
+ static time_zone UTC();
+
+ // Load a named time zone. Returns false if the name is invalid, or if
+ // some other kind of error occurs. Note that loading "UTC" never fails.
+ static bool LoadTimeZone(const std::string& name, time_zone* tz);
+
+ // Clears the map of cached time zones. Primarily for use in benchmarks
+ // that gauge the performance of loading/parsing the time-zone data.
+ 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_;
}
-
- // Breaks a time_point down to civil-time components in this time zone.
+
+ // Breaks a time_point down to civil-time components in this time zone.
time_zone::absolute_lookup BreakTime(const time_point<seconds>& tp) const {
- return zone_->BreakTime(tp);
- }
-
- // Converts the civil-time components in this time zone into a time_point.
- // That is, the opposite of BreakTime(). The requested civil time may be
- // ambiguous or illegal due to a change of UTC offset.
- time_zone::civil_lookup MakeTime(const civil_second& cs) const {
- return zone_->MakeTime(cs);
- }
-
- // Finds the time of the next/previous offset change in this time zone.
+ return zone_->BreakTime(tp);
+ }
+
+ // Converts the civil-time components in this time zone into a time_point.
+ // That is, the opposite of BreakTime(). The requested civil time may be
+ // ambiguous or illegal due to a change of UTC offset.
+ time_zone::civil_lookup MakeTime(const civil_second& cs) const {
+ return zone_->MakeTime(cs);
+ }
+
+ // 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 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(); }
- private:
- explicit Impl(const std::string& name);
- static const Impl* UTCImpl();
-
- const std::string name_;
- std::unique_ptr<TimeZoneIf> zone_;
-};
-
-} // namespace cctz
-
-#endif // CCTZ_TIME_ZONE_IMPL_H_
+ private:
+ explicit Impl(const std::string& name);
+ static const Impl* UTCImpl();
+
+ const std::string name_;
+ std::unique_ptr<TimeZoneIf> zone_;
+};
+
+} // namespace cctz
+
+#endif // CCTZ_TIME_ZONE_IMPL_H_
diff --git a/contrib/libs/cctz/src/time_zone_info.cc b/contrib/libs/cctz/src/time_zone_info.cc
index 1b3dc15cf1..17ca9e50f2 100644
--- a/contrib/libs/cctz/src/time_zone_info.cc
+++ b/contrib/libs/cctz/src/time_zone_info.cc
@@ -1,83 +1,83 @@
-// 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
-//
+// 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.
-
-// This file implements the TimeZoneIf interface using the "zoneinfo"
-// data provided by the IANA Time Zone Database (i.e., the only real game
-// in town).
-//
-// TimeZoneInfo represents the history of UTC-offset changes within a time
-// zone. Most changes are due to daylight-saving rules, but occasionally
-// shifts are made to the time-zone's base offset. The database only attempts
-// to be definitive for times since 1970, so be wary of local-time conversions
-// before that. Also, rule and zone-boundary changes are made at the whim
-// of governments, so the conversion of future times needs to be taken with
-// a grain of salt.
-//
-// For more information see tzfile(5), http://www.iana.org/time-zones, or
+//
+// 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.
+
+// This file implements the TimeZoneIf interface using the "zoneinfo"
+// data provided by the IANA Time Zone Database (i.e., the only real game
+// in town).
+//
+// TimeZoneInfo represents the history of UTC-offset changes within a time
+// zone. Most changes are due to daylight-saving rules, but occasionally
+// shifts are made to the time-zone's base offset. The database only attempts
+// to be definitive for times since 1970, so be wary of local-time conversions
+// before that. Also, rule and zone-boundary changes are made at the whim
+// of governments, so the conversion of future times needs to be taken with
+// a grain of salt.
+//
+// For more information see tzfile(5), http://www.iana.org/time-zones, or
// https://en.wikipedia.org/wiki/Zoneinfo.
-//
-// Note that we assume the proleptic Gregorian calendar and 60-second
-// minutes throughout.
-
-#include "time_zone_info.h"
-
-#include <algorithm>
-#include <cassert>
-#include <chrono>
-#include <cstdint>
-#include <cstdio>
-#include <cstdlib>
-#include <cstring>
-#include <functional>
-#include <memory>
-#include <sstream>
-#include <string>
-
+//
+// Note that we assume the proleptic Gregorian calendar and 60-second
+// minutes throughout.
+
+#include "time_zone_info.h"
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <functional>
+#include <memory>
+#include <sstream>
+#include <string>
+
#include "cctz/civil_time.h"
-#include "time_zone_fixed.h"
-#include "time_zone_posix.h"
-
-namespace cctz {
-
-namespace {
-
+#include "time_zone_fixed.h"
+#include "time_zone_posix.h"
+
+namespace cctz {
+
+namespace {
+
inline bool IsLeap(year_t year) {
- return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
-}
-
-// The number of days in non-leap and leap years respectively.
-const std::int_least32_t kDaysPerYear[2] = {365, 366};
-
-// The day offsets of the beginning of each (1-based) month in non-leap and
-// leap years respectively (e.g., 335 days before December in a leap year).
-const std::int_least16_t kMonthOffsets[2][1 + 12 + 1] = {
- {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
- {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
-};
-
-// We reject leap-second encoded zoneinfo and so assume 60-second minutes.
-const std::int_least32_t kSecsPerDay = 24 * 60 * 60;
-
-// 400-year chunks always have 146097 days (20871 weeks).
-const std::int_least64_t kSecsPer400Years = 146097LL * kSecsPerDay;
-
-// Like kDaysPerYear[] but scaled up by a factor of kSecsPerDay.
-const std::int_least32_t kSecsPerYear[2] = {
- 365 * kSecsPerDay,
- 366 * kSecsPerDay,
-};
-
+ return (year % 4) == 0 && ((year % 100) != 0 || (year % 400) == 0);
+}
+
+// The number of days in non-leap and leap years respectively.
+const std::int_least32_t kDaysPerYear[2] = {365, 366};
+
+// The day offsets of the beginning of each (1-based) month in non-leap and
+// leap years respectively (e.g., 335 days before December in a leap year).
+const std::int_least16_t kMonthOffsets[2][1 + 12 + 1] = {
+ {-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
+ {-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366},
+};
+
+// We reject leap-second encoded zoneinfo and so assume 60-second minutes.
+const std::int_least32_t kSecsPerDay = 24 * 60 * 60;
+
+// 400-year chunks always have 146097 days (20871 weeks).
+const std::int_least64_t kSecsPer400Years = 146097LL * kSecsPerDay;
+
+// Like kDaysPerYear[] but scaled up by a factor of kSecsPerDay.
+const std::int_least32_t kSecsPerYear[2] = {
+ 365 * kSecsPerDay,
+ 366 * kSecsPerDay,
+};
+
// Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat).
inline int ToPosixWeekday(weekday wd) {
switch (wd) {
@@ -99,195 +99,195 @@ inline int ToPosixWeekday(weekday wd) {
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;
-}
-
-// Multi-byte, numeric values are encoded using a MSB first,
-// twos-complement representation. These helpers decode, from
-// the given address, 4-byte and 8-byte values respectively.
-// Note: If int_fastXX_t == intXX_t and this machine is not
-// twos complement, then there will be at least one input value
-// we cannot represent.
-std::int_fast32_t Decode32(const char* cp) {
- std::uint_fast32_t v = 0;
- for (int i = 0; i != (32 / 8); ++i) v = (v << 8) | Decode8(cp++);
- const std::int_fast32_t s32max = 0x7fffffff;
- const auto s32maxU = static_cast<std::uint_fast32_t>(s32max);
- if (v <= s32maxU) return static_cast<std::int_fast32_t>(v);
- return static_cast<std::int_fast32_t>(v - s32maxU - 1) - s32max - 1;
-}
-
-std::int_fast64_t Decode64(const char* cp) {
- std::uint_fast64_t v = 0;
- for (int i = 0; i != (64 / 8); ++i) v = (v << 8) | Decode8(cp++);
- const std::int_fast64_t s64max = 0x7fffffffffffffff;
- const auto s64maxU = static_cast<std::uint_fast64_t>(s64max);
- if (v <= s64maxU) return static_cast<std::int_fast64_t>(v);
- return static_cast<std::int_fast64_t>(v - s64maxU - 1) - s64max - 1;
-}
-
-// Generate a year-relative offset for a PosixTransition.
-std::int_fast64_t TransOffset(bool leap_year, int jan1_weekday,
- const PosixTransition& pt) {
- std::int_fast64_t days = 0;
- switch (pt.date.fmt) {
- case PosixTransition::J: {
- days = pt.date.j.day;
- if (!leap_year || days < kMonthOffsets[1][3]) days -= 1;
- break;
- }
- case PosixTransition::N: {
- days = pt.date.n.day;
- break;
- }
- case PosixTransition::M: {
- const bool last_week = (pt.date.m.week == 5);
- days = kMonthOffsets[leap_year][pt.date.m.month + last_week];
- const std::int_fast64_t weekday = (jan1_weekday + days) % 7;
- if (last_week) {
- days -= (weekday + 7 - 1 - pt.date.m.weekday) % 7 + 1;
- } else {
- days += (pt.date.m.weekday + 7 - weekday) % 7;
- days += (pt.date.m.week - 1) * 7;
- }
- break;
- }
- }
- return (days * kSecsPerDay) + pt.time.offset;
-}
-
+// 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;
+}
+
+// Multi-byte, numeric values are encoded using a MSB first,
+// twos-complement representation. These helpers decode, from
+// the given address, 4-byte and 8-byte values respectively.
+// Note: If int_fastXX_t == intXX_t and this machine is not
+// twos complement, then there will be at least one input value
+// we cannot represent.
+std::int_fast32_t Decode32(const char* cp) {
+ std::uint_fast32_t v = 0;
+ for (int i = 0; i != (32 / 8); ++i) v = (v << 8) | Decode8(cp++);
+ const std::int_fast32_t s32max = 0x7fffffff;
+ const auto s32maxU = static_cast<std::uint_fast32_t>(s32max);
+ if (v <= s32maxU) return static_cast<std::int_fast32_t>(v);
+ return static_cast<std::int_fast32_t>(v - s32maxU - 1) - s32max - 1;
+}
+
+std::int_fast64_t Decode64(const char* cp) {
+ std::uint_fast64_t v = 0;
+ for (int i = 0; i != (64 / 8); ++i) v = (v << 8) | Decode8(cp++);
+ const std::int_fast64_t s64max = 0x7fffffffffffffff;
+ const auto s64maxU = static_cast<std::uint_fast64_t>(s64max);
+ if (v <= s64maxU) return static_cast<std::int_fast64_t>(v);
+ return static_cast<std::int_fast64_t>(v - s64maxU - 1) - s64max - 1;
+}
+
+// Generate a year-relative offset for a PosixTransition.
+std::int_fast64_t TransOffset(bool leap_year, int jan1_weekday,
+ const PosixTransition& pt) {
+ std::int_fast64_t days = 0;
+ switch (pt.date.fmt) {
+ case PosixTransition::J: {
+ days = pt.date.j.day;
+ if (!leap_year || days < kMonthOffsets[1][3]) days -= 1;
+ break;
+ }
+ case PosixTransition::N: {
+ days = pt.date.n.day;
+ break;
+ }
+ case PosixTransition::M: {
+ const bool last_week = (pt.date.m.week == 5);
+ days = kMonthOffsets[leap_year][pt.date.m.month + last_week];
+ const std::int_fast64_t weekday = (jan1_weekday + days) % 7;
+ if (last_week) {
+ days -= (weekday + 7 - 1 - pt.date.m.weekday) % 7 + 1;
+ } else {
+ days += (pt.date.m.weekday + 7 - weekday) % 7;
+ days += (pt.date.m.week - 1) * 7;
+ }
+ break;
+ }
+ }
+ return (days * kSecsPerDay) + pt.time.offset;
+}
+
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;
- return cl;
-}
-
-inline time_zone::civil_lookup MakeUnique(std::int_fast64_t unix_time) {
- return MakeUnique(FromUnixSeconds(unix_time));
-}
-
-inline time_zone::civil_lookup MakeSkipped(const Transition& tr,
- const civil_second& cs) {
- time_zone::civil_lookup cl;
- cl.kind = time_zone::civil_lookup::SKIPPED;
- cl.pre = FromUnixSeconds(tr.unix_time - 1 + (cs - tr.prev_civil_sec));
- cl.trans = FromUnixSeconds(tr.unix_time);
- cl.post = FromUnixSeconds(tr.unix_time - (tr.civil_sec - cs));
- return cl;
-}
-
-inline time_zone::civil_lookup MakeRepeated(const Transition& tr,
- const civil_second& cs) {
- time_zone::civil_lookup cl;
- cl.kind = time_zone::civil_lookup::REPEATED;
- cl.pre = FromUnixSeconds(tr.unix_time - 1 - (tr.prev_civil_sec - cs));
- cl.trans = FromUnixSeconds(tr.unix_time);
- cl.post = FromUnixSeconds(tr.unix_time + (cs - tr.civil_sec));
- return cl;
-}
-
+ time_zone::civil_lookup cl;
+ cl.kind = time_zone::civil_lookup::UNIQUE;
+ cl.pre = cl.trans = cl.post = tp;
+ return cl;
+}
+
+inline time_zone::civil_lookup MakeUnique(std::int_fast64_t unix_time) {
+ return MakeUnique(FromUnixSeconds(unix_time));
+}
+
+inline time_zone::civil_lookup MakeSkipped(const Transition& tr,
+ const civil_second& cs) {
+ time_zone::civil_lookup cl;
+ cl.kind = time_zone::civil_lookup::SKIPPED;
+ cl.pre = FromUnixSeconds(tr.unix_time - 1 + (cs - tr.prev_civil_sec));
+ cl.trans = FromUnixSeconds(tr.unix_time);
+ cl.post = FromUnixSeconds(tr.unix_time - (tr.civil_sec - cs));
+ return cl;
+}
+
+inline time_zone::civil_lookup MakeRepeated(const Transition& tr,
+ const civil_second& cs) {
+ time_zone::civil_lookup cl;
+ cl.kind = time_zone::civil_lookup::REPEATED;
+ cl.pre = FromUnixSeconds(tr.unix_time - 1 - (tr.prev_civil_sec - cs));
+ cl.trans = FromUnixSeconds(tr.unix_time);
+ cl.post = FromUnixSeconds(tr.unix_time + (cs - tr.civil_sec));
+ return cl;
+}
+
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());
-}
-
-} // namespace
-
-// What (no leap-seconds) UTC+seconds zoneinfo would look like.
+ return civil_second(cs.year() + shift, cs.month(), cs.day(),
+ cs.hour(), cs.minute(), cs.second());
+}
+
+} // namespace
+
+// What (no leap-seconds) UTC+seconds zoneinfo would look like.
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;
-
+ 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)
- // 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 : {
+ // 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
- 1420070400LL, // 2015-01-01T00:00:00+00:00
- 1451606400LL, // 2016-01-01T00:00:00+00:00
- 1483228800LL, // 2017-01-01T00:00:00+00:00
- 1514764800LL, // 2018-01-01T00:00:00+00:00
- 1546300800LL, // 2019-01-01T00:00:00+00:00
- 1577836800LL, // 2020-01-01T00:00:00+00:00
- 1609459200LL, // 2021-01-01T00:00:00+00:00
+ 1420070400LL, // 2015-01-01T00:00:00+00:00
+ 1451606400LL, // 2016-01-01T00:00:00+00:00
+ 1483228800LL, // 2017-01-01T00:00:00+00:00
+ 1514764800LL, // 2018-01-01T00:00:00+00:00
+ 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
- }) {
- Transition& tr(*transitions_.emplace(transitions_.end()));
- tr.unix_time = unix_time;
- tr.type_index = 0;
- tr.civil_sec = LocalTime(tr.unix_time, tt).cs;
- tr.prev_civil_sec = tr.civil_sec - 1;
- }
-
- default_transition_type_ = 0;
- abbreviations_ = FixedOffsetToAbbr(offset);
+ }) {
+ Transition& tr(*transitions_.emplace(transitions_.end()));
+ tr.unix_time = unix_time;
+ tr.type_index = 0;
+ tr.civil_sec = LocalTime(tr.unix_time, tt).cs;
+ tr.prev_civil_sec = tr.civil_sec - 1;
+ }
+
+ default_transition_type_ = 0;
+ abbreviations_ = FixedOffsetToAbbr(offset);
abbreviations_.append(1, '\0');
- future_spec_.clear(); // never needed for a fixed-offset zone
- extended_ = false;
-
+ 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;
-
- transitions_.shrink_to_fit();
- return true;
-}
-
-// Builds the in-memory header using the raw bytes from the file.
-bool TimeZoneInfo::Header::Build(const tzhead& tzh) {
- std::int_fast32_t v;
- if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false;
- timecnt = static_cast<std::size_t>(v);
- if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false;
- typecnt = static_cast<std::size_t>(v);
- if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false;
- charcnt = static_cast<std::size_t>(v);
- if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false;
- leapcnt = static_cast<std::size_t>(v);
- if ((v = Decode32(tzh.tzh_ttisstdcnt)) < 0) return false;
- ttisstdcnt = static_cast<std::size_t>(v);
+
+ transitions_.shrink_to_fit();
+ return true;
+}
+
+// Builds the in-memory header using the raw bytes from the file.
+bool TimeZoneInfo::Header::Build(const tzhead& tzh) {
+ std::int_fast32_t v;
+ if ((v = Decode32(tzh.tzh_timecnt)) < 0) return false;
+ timecnt = static_cast<std::size_t>(v);
+ if ((v = Decode32(tzh.tzh_typecnt)) < 0) return false;
+ typecnt = static_cast<std::size_t>(v);
+ if ((v = Decode32(tzh.tzh_charcnt)) < 0) return false;
+ charcnt = static_cast<std::size_t>(v);
+ if ((v = Decode32(tzh.tzh_leapcnt)) < 0) return false;
+ 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);
- return true;
-}
-
-// How many bytes of data are associated with this header. The result
-// depends upon whether this is a section with 4-byte or 8-byte times.
-std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const {
- std::size_t len = 0;
- len += (time_len + 1) * timecnt; // unix_time + type_index
- len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index
- len += 1 * charcnt; // abbreviations
- len += (time_len + 4) * leapcnt; // leap-time + TAI-UTC
- len += 1 * ttisstdcnt; // UTC/local indicators
+ return true;
+}
+
+// How many bytes of data are associated with this header. The result
+// depends upon whether this is a section with 4-byte or 8-byte times.
+std::size_t TimeZoneInfo::Header::DataLength(std::size_t time_len) const {
+ std::size_t len = 0;
+ len += (time_len + 1) * timecnt; // unix_time + type_index
+ len += (4 + 1 + 1) * typecnt; // utc_offset + is_dst + abbr_index
+ 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
- return len;
-}
-
-// zic(8) can generate no-op transitions when a zone changes rules at an
-// instant when there is actually no discontinuity. So we check whether
-// two transitions have equivalent types (same offset/is_dst/abbr).
-bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index,
- std::uint_fast8_t tt2_index) const {
- if (tt1_index == tt2_index) return true;
- const TransitionType& tt1(transition_types_[tt1_index]);
- const TransitionType& tt2(transition_types_[tt2_index]);
+ return len;
+}
+
+// zic(8) can generate no-op transitions when a zone changes rules at an
+// instant when there is actually no discontinuity. So we check whether
+// two transitions have equivalent types (same offset/is_dst/abbr).
+bool TimeZoneInfo::EquivTransitions(std::uint_fast8_t tt1_index,
+ std::uint_fast8_t tt2_index) const {
+ 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.is_dst != tt2.is_dst) return false;
- if (tt1.abbr_index != tt2.abbr_index) return false;
- return true;
-}
-
+ 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,
@@ -320,38 +320,38 @@ bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
return true;
}
-// Use the POSIX-TZ-environment-variable-style string to handle times
-// in years after the last transition stored in the zoneinfo data.
+// 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() {
- extended_ = false;
+ extended_ = false;
if (future_spec_.empty()) return true; // last transition prevails
-
- PosixTimeZone posix;
+
+ PosixTimeZone posix;
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;
-
+
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;
-
- // 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.
+
+ // 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);
- extended_ = true;
-
+ 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]);
@@ -360,7 +360,7 @@ bool TimeZoneInfo::ExtendTransitions() {
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_) {
@@ -375,146 +375,146 @@ bool TimeZoneInfo::ExtendTransitions() {
transitions_.push_back(*tb);
}
if (last_year_ == limit) break;
- jan1_time += kSecsPerYear[leap_year];
- jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
+ jan1_time += kSecsPerYear[leap_year];
+ jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
leap_year = !leap_year && IsLeap(last_year_ + 1);
- }
+ }
return true;
-}
-
+}
+
bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
- // Read and validate the header.
- tzhead tzh;
- if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
- return false;
- if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
- return false;
- Header hdr;
- if (!hdr.Build(tzh))
- return false;
- std::size_t time_len = 4;
- if (tzh.tzh_version[0] != '\0') {
- // Skip the 4-byte data.
- if (zip->Skip(hdr.DataLength(time_len)) != 0)
- return false;
- // Read and validate the header for the 8-byte data.
- if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
- return false;
- if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
- return false;
- if (tzh.tzh_version[0] == '\0')
- return false;
- if (!hdr.Build(tzh))
- return false;
- time_len = 8;
- }
- if (hdr.typecnt == 0)
- return false;
- if (hdr.leapcnt != 0) {
- // This code assumes 60-second minutes so we do not want
- // the leap-second encoded zoneinfo. We could reverse the
- // compensation, but the "right" encoding is rarely used
- // so currently we simply reject such data.
- return false;
- }
- if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt)
- return false;
+ // Read and validate the header.
+ tzhead tzh;
+ if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
+ return false;
+ if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
+ return false;
+ Header hdr;
+ if (!hdr.Build(tzh))
+ return false;
+ std::size_t time_len = 4;
+ if (tzh.tzh_version[0] != '\0') {
+ // Skip the 4-byte data.
+ if (zip->Skip(hdr.DataLength(time_len)) != 0)
+ return false;
+ // Read and validate the header for the 8-byte data.
+ if (zip->Read(&tzh, sizeof(tzh)) != sizeof(tzh))
+ return false;
+ if (strncmp(tzh.tzh_magic, TZ_MAGIC, sizeof(tzh.tzh_magic)) != 0)
+ return false;
+ if (tzh.tzh_version[0] == '\0')
+ return false;
+ if (!hdr.Build(tzh))
+ return false;
+ time_len = 8;
+ }
+ if (hdr.typecnt == 0)
+ return false;
+ if (hdr.leapcnt != 0) {
+ // This code assumes 60-second minutes so we do not want
+ // the leap-second encoded zoneinfo. We could reverse the
+ // compensation, but the "right" encoding is rarely used
+ // so currently we simply reject such data.
+ return false;
+ }
+ if (hdr.ttisstdcnt != 0 && hdr.ttisstdcnt != hdr.typecnt)
+ return false;
if (hdr.ttisutcnt != 0 && hdr.ttisutcnt != hdr.typecnt)
- return false;
-
- // Read the data into a local buffer.
- std::size_t len = hdr.DataLength(time_len);
- std::vector<char> tbuf(len);
- if (zip->Read(tbuf.data(), len) != len)
- return false;
- const char* bp = tbuf.data();
-
- // Decode and validate the transitions.
+ return false;
+
+ // Read the data into a local buffer.
+ std::size_t len = hdr.DataLength(time_len);
+ std::vector<char> tbuf(len);
+ if (zip->Read(tbuf.data(), len) != len)
+ return false;
+ const char* bp = tbuf.data();
+
+ // Decode and validate the transitions.
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);
- bp += time_len;
- if (i != 0) {
- // Check that the transitions are ordered by time (as zic guarantees).
- if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i]))
- return false; // out of order
- }
- }
- bool seen_type_0 = false;
- for (std::size_t i = 0; i != hdr.timecnt; ++i) {
- transitions_[i].type_index = Decode8(bp++);
- if (transitions_[i].type_index >= hdr.typecnt)
- return false;
- if (transitions_[i].type_index == 0)
- seen_type_0 = true;
- }
-
- // Decode and validate the transition types.
+ 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);
+ bp += time_len;
+ if (i != 0) {
+ // Check that the transitions are ordered by time (as zic guarantees).
+ if (!Transition::ByUnixTime()(transitions_[i - 1], transitions_[i]))
+ return false; // out of order
+ }
+ }
+ bool seen_type_0 = false;
+ for (std::size_t i = 0; i != hdr.timecnt; ++i) {
+ transitions_[i].type_index = Decode8(bp++);
+ if (transitions_[i].type_index >= hdr.typecnt)
+ return false;
+ if (transitions_[i].type_index == 0)
+ seen_type_0 = true;
+ }
+
+ // Decode and validate the transition types.
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 =
- static_cast<std::int_least32_t>(Decode32(bp));
- if (transition_types_[i].utc_offset >= kSecsPerDay ||
- transition_types_[i].utc_offset <= -kSecsPerDay)
- return false;
- bp += 4;
- transition_types_[i].is_dst = (Decode8(bp++) != 0);
- transition_types_[i].abbr_index = Decode8(bp++);
- if (transition_types_[i].abbr_index >= hdr.charcnt)
- return false;
- }
-
- // Determine the before-first-transition type.
- default_transition_type_ = 0;
- if (seen_type_0 && hdr.timecnt != 0) {
- std::uint_fast8_t index = 0;
- if (transition_types_[0].is_dst) {
- index = transitions_[0].type_index;
- while (index != 0 && transition_types_[index].is_dst)
- --index;
- }
- while (index != hdr.typecnt && transition_types_[index].is_dst)
- ++index;
- if (index != hdr.typecnt)
- default_transition_type_ = index;
- }
-
- // Copy all the abbreviations.
+ transition_types_.resize(hdr.typecnt);
+ for (std::size_t i = 0; i != hdr.typecnt; ++i) {
+ transition_types_[i].utc_offset =
+ static_cast<std::int_least32_t>(Decode32(bp));
+ if (transition_types_[i].utc_offset >= kSecsPerDay ||
+ transition_types_[i].utc_offset <= -kSecsPerDay)
+ return false;
+ bp += 4;
+ transition_types_[i].is_dst = (Decode8(bp++) != 0);
+ transition_types_[i].abbr_index = Decode8(bp++);
+ if (transition_types_[i].abbr_index >= hdr.charcnt)
+ return false;
+ }
+
+ // Determine the before-first-transition type.
+ default_transition_type_ = 0;
+ if (seen_type_0 && hdr.timecnt != 0) {
+ std::uint_fast8_t index = 0;
+ if (transition_types_[0].is_dst) {
+ index = transitions_[0].type_index;
+ while (index != 0 && transition_types_[index].is_dst)
+ --index;
+ }
+ while (index != hdr.typecnt && transition_types_[index].is_dst)
+ ++index;
+ if (index != hdr.typecnt)
+ default_transition_type_ = index;
+ }
+
+ // Copy all the abbreviations.
abbreviations_.reserve(hdr.charcnt + 10);
- abbreviations_.assign(bp, hdr.charcnt);
- bp += hdr.charcnt;
-
- // Skip the unused portions. We've already dispensed with leap-second
- // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when
- // interpreting a POSIX spec that does not include start/end rules, and
- // 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
+ abbreviations_.assign(bp, hdr.charcnt);
+ bp += hdr.charcnt;
+
+ // Skip the unused portions. We've already dispensed with leap-second
+ // encoded zoneinfo. The ttisstd/ttisgmt indicators only apply when
+ // interpreting a POSIX spec that does not include start/end rules, and
+ // 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
- 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.
+ 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 {
- unsigned char ch; // all non-EOF results are positive
+ unsigned char ch; // all non-EOF results are positive
return (azip->Read(&ch, 1) == 1) ? ch : EOF;
- };
- if (get_char(zip) != '\n')
- return false;
- for (int c = get_char(zip); c != '\n'; c = get_char(zip)) {
- if (c == EOF)
- return false;
- future_spec_.push_back(static_cast<char>(c));
- }
- }
-
- // We don't check for EOF so that we're forwards compatible.
-
+ };
+ if (get_char(zip) != '\n')
+ return false;
+ for (int c = get_char(zip); c != '\n'; c = get_char(zip)) {
+ if (c == EOF)
+ return false;
+ future_spec_.push_back(static_cast<char>(c));
+ }
+ }
+
+ // 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.
@@ -522,32 +522,32 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
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).
- // For us, they just get in the way when we do future_spec_ extension.
- while (hdr.timecnt > 1) {
- if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index,
- transitions_[hdr.timecnt - 2].type_index)) {
- break;
- }
- hdr.timecnt -= 1;
- }
- transitions_.resize(hdr.timecnt);
-
- // Ensure that there is always a transition in the first half of the
+ // 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).
+ // For us, they just get in the way when we do future_spec_ extension.
+ while (hdr.timecnt > 1) {
+ if (!EquivTransitions(transitions_[hdr.timecnt - 1].type_index,
+ transitions_[hdr.timecnt - 2].type_index)) {
+ break;
+ }
+ hdr.timecnt -= 1;
+ }
+ 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.
- if (transitions_.empty() || transitions_.front().unix_time >= 0) {
- Transition& tr(*transitions_.emplace(transitions_.begin()));
+ 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.type_index = default_transition_type_;
- }
-
- // Extend the transitions using the future specification.
+ 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
@@ -561,35 +561,35 @@ bool TimeZoneInfo::Load(ZoneInfoSource* zip) {
}
// 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) {
- Transition& tr(transitions_[i]);
- tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1;
- ttp = &transition_types_[tr.type_index];
- tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs;
- if (i != 0) {
- // Check that the transitions are ordered by civil time. Essentially
- // this means that an offset change cannot cross another such change.
- // No one does this in practice, and we depend on it in MakeTime().
- if (!Transition::ByCivilTime()(transitions_[i - 1], tr))
- return false; // out of order
- }
- }
-
- // Compute the maximum/minimum civil times that can be converted to a
+ // 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) {
+ Transition& tr(transitions_[i]);
+ tr.prev_civil_sec = LocalTime(tr.unix_time, *ttp).cs - 1;
+ ttp = &transition_types_[tr.type_index];
+ tr.civil_sec = LocalTime(tr.unix_time, *ttp).cs;
+ if (i != 0) {
+ // Check that the transitions are ordered by civil time. Essentially
+ // this means that an offset change cannot cross another such change.
+ // No one does this in practice, and we depend on it in MakeTime().
+ if (!Transition::ByCivilTime()(transitions_[i - 1], tr))
+ return false; // out of order
+ }
+ }
+
+ // Compute the maximum/minimum civil times that can be converted to a
// time_point<seconds> for each of the zone's transition types.
- for (auto& tt : 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;
- }
-
- transitions_.shrink_to_fit();
- return true;
-}
-
-namespace {
-
+ }
+
+ transitions_.shrink_to_fit();
+ return true;
+}
+
+namespace {
+
// fopen(3) adaptor.
inline FILE* FOpen(const char* path, const char* mode) {
#if defined(_MSC_VER)
@@ -601,65 +601,65 @@ inline FILE* FOpen(const char* path, const char* mode) {
#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 {
+// 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;
- }
- int Skip(std::size_t offset) override {
+ }
+ 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) {}
- private:
+ private:
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.
+};
+
+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;
-
- // Map the time-zone name to a path name.
- std::string path;
+
+ // Map the time-zone name to a path name.
+ std::string path;
if (pos == name.size() || name[pos] != '/') {
- const char* tzdir = "/usr/share/zoneinfo";
- char* tzdir_env = nullptr;
-#if defined(_MSC_VER)
- _dupenv_s(&tzdir_env, nullptr, "TZDIR");
-#else
- tzdir_env = std::getenv("TZDIR");
-#endif
- if (tzdir_env && *tzdir_env) tzdir = tzdir_env;
- path += tzdir;
- path += '/';
-#if defined(_MSC_VER)
- free(tzdir_env);
-#endif
- }
+ const char* tzdir = "/usr/share/zoneinfo";
+ char* tzdir_env = nullptr;
+#if defined(_MSC_VER)
+ _dupenv_s(&tzdir_env, nullptr, "TZDIR");
+#else
+ tzdir_env = std::getenv("TZDIR");
+#endif
+ if (tzdir_env && *tzdir_env) tzdir = tzdir_env;
+ path += tzdir;
+ path += '/';
+#if defined(_MSC_VER)
+ free(tzdir_env);
+#endif
+ }
path.append(name, pos, std::string::npos);
-
- // Open the zoneinfo file.
+
+ // Open the zoneinfo file.
FILE* fp = FOpen(path.c_str(), "rb");
- if (fp == nullptr) return nullptr;
+ if (fp == nullptr) return nullptr;
std::size_t length = 0;
if (fseek(fp, 0, SEEK_END) == 0) {
long offset = ftell(fp);
@@ -669,8 +669,8 @@ std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open(
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);
@@ -725,254 +725,254 @@ std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
return nullptr;
}
-} // namespace
-
-bool TimeZoneInfo::Load(const std::string& name) {
- // We can ensure that the loading of UTC or any other fixed-offset
- // 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.
+} // namespace
+
+bool TimeZoneInfo::Load(const std::string& name) {
+ // We can ensure that the loading of UTC or any other fixed-offset
+ // 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();
- 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(
+ 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;
- });
+ });
return zip != nullptr && Load(zip.get());
-}
-
-// BreakTime() translation for a particular transition type.
-time_zone::absolute_lookup TimeZoneInfo::LocalTime(
- std::int_fast64_t unix_time, const TransitionType& tt) const {
- // A civil time in "+offset" looks like (time+offset) in UTC.
- // Note: We perform two additions in the civil_second domain to
- // sidestep the chance of overflow in (unix_time + tt.utc_offset).
- return {(civil_second() + unix_time) + tt.utc_offset,
- tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
-}
-
-// BreakTime() translation for a particular transition.
-time_zone::absolute_lookup TimeZoneInfo::LocalTime(
- std::int_fast64_t unix_time, const Transition& tr) const {
- const TransitionType& tt = transition_types_[tr.type_index];
- // Note: (unix_time - tr.unix_time) will never overflow as we
- // have ensured that there is always a "nearby" transition.
- return {tr.civil_sec + (unix_time - tr.unix_time), // TODO: Optimize.
- tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
-}
-
-// MakeTime() translation with a conversion-preserving +N * 400-year shift.
-time_zone::civil_lookup TimeZoneInfo::TimeLocal(const civil_second& cs,
+}
+
+// BreakTime() translation for a particular transition type.
+time_zone::absolute_lookup TimeZoneInfo::LocalTime(
+ std::int_fast64_t unix_time, const TransitionType& tt) const {
+ // A civil time in "+offset" looks like (time+offset) in UTC.
+ // Note: We perform two additions in the civil_second domain to
+ // sidestep the chance of overflow in (unix_time + tt.utc_offset).
+ return {(civil_second() + unix_time) + tt.utc_offset,
+ tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
+}
+
+// BreakTime() translation for a particular transition.
+time_zone::absolute_lookup TimeZoneInfo::LocalTime(
+ std::int_fast64_t unix_time, const Transition& tr) const {
+ const TransitionType& tt = transition_types_[tr.type_index];
+ // Note: (unix_time - tr.unix_time) will never overflow as we
+ // have ensured that there is always a "nearby" transition.
+ return {tr.civil_sec + (unix_time - tr.unix_time), // TODO: Optimize.
+ tt.utc_offset, tt.is_dst, &abbreviations_[tt.abbr_index]};
+}
+
+// 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 {
- assert(last_year_ - 400 < cs.year() && cs.year() <= last_year_);
- time_zone::civil_lookup cl = MakeTime(cs);
+ 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();
- } else {
+ } else {
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) {
+ for (auto* tp : {&cl.pre, &cl.trans, &cl.post}) {
+ if (*tp > limit) {
*tp = time_point<seconds>::max();
- } else {
- *tp += offset;
- }
- }
- }
- return cl;
-}
-
-time_zone::absolute_lookup TimeZoneInfo::BreakTime(
+ } else {
+ *tp += offset;
+ }
+ }
+ }
+ return cl;
+}
+
+time_zone::absolute_lookup TimeZoneInfo::BreakTime(
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.
-
- if (unix_time < transitions_[0].unix_time) {
- return LocalTime(unix_time, transition_types_[default_transition_type_]);
- }
- if (unix_time >= transitions_[timecnt - 1].unix_time) {
- // After the last transition. If we extended the transitions using
- // future_spec_, shift back to a supported year using the 400-year
- // cycle of calendaric equivalence and then compensate accordingly.
- if (extended_) {
- const std::int_fast64_t diff =
- unix_time - transitions_[timecnt - 1].unix_time;
+ std::int_fast64_t unix_time = ToUnixSeconds(tp);
+ const std::size_t timecnt = transitions_.size();
+ assert(timecnt != 0); // We always add a transition.
+
+ if (unix_time < transitions_[0].unix_time) {
+ return LocalTime(unix_time, transition_types_[default_transition_type_]);
+ }
+ if (unix_time >= transitions_[timecnt - 1].unix_time) {
+ // After the last transition. If we extended the transitions using
+ // future_spec_, shift back to a supported year using the 400-year
+ // cycle of calendaric equivalence and then compensate accordingly.
+ 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);
- time_zone::absolute_lookup al = BreakTime(tp - d);
- al.cs = YearShift(al.cs, shift * 400);
- return al;
- }
- return LocalTime(unix_time, transitions_[timecnt - 1]);
- }
-
- const std::size_t hint = local_time_hint_.load(std::memory_order_relaxed);
- if (0 < hint && hint < timecnt) {
- if (transitions_[hint - 1].unix_time <= unix_time) {
- if (unix_time < transitions_[hint].unix_time) {
- return LocalTime(unix_time, transitions_[hint - 1]);
- }
- }
- }
-
- const Transition target = {unix_time, 0, civil_second(), civil_second()};
- const Transition* begin = &transitions_[0];
- const Transition* tr = std::upper_bound(begin, begin + timecnt, target,
- Transition::ByUnixTime());
- local_time_hint_.store(static_cast<std::size_t>(tr - begin),
- std::memory_order_relaxed);
- return LocalTime(unix_time, *--tr);
-}
-
-time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const {
- const std::size_t timecnt = transitions_.size();
- assert(timecnt != 0); // We always add a transition.
-
- // Find the first transition after our target civil time.
- const Transition* tr = nullptr;
- const Transition* begin = &transitions_[0];
- const Transition* end = begin + timecnt;
- if (cs < begin->civil_sec) {
- tr = begin;
- } else if (cs >= transitions_[timecnt - 1].civil_sec) {
- tr = end;
- } else {
- const std::size_t hint = time_local_hint_.load(std::memory_order_relaxed);
- if (0 < hint && hint < timecnt) {
- if (transitions_[hint - 1].civil_sec <= cs) {
- if (cs < transitions_[hint].civil_sec) {
- tr = begin + hint;
- }
- }
- }
- if (tr == nullptr) {
- const Transition target = {0, 0, cs, civil_second()};
- tr = std::upper_bound(begin, end, target, Transition::ByCivilTime());
- time_local_hint_.store(static_cast<std::size_t>(tr - begin),
- std::memory_order_relaxed);
- }
- }
-
- if (tr == begin) {
- if (tr->prev_civil_sec >= cs) {
- // Before first transition, so use the default offset.
- const TransitionType& tt(transition_types_[default_transition_type_]);
+ time_zone::absolute_lookup al = BreakTime(tp - d);
+ al.cs = YearShift(al.cs, shift * 400);
+ return al;
+ }
+ return LocalTime(unix_time, transitions_[timecnt - 1]);
+ }
+
+ const std::size_t hint = local_time_hint_.load(std::memory_order_relaxed);
+ if (0 < hint && hint < timecnt) {
+ if (transitions_[hint - 1].unix_time <= unix_time) {
+ if (unix_time < transitions_[hint].unix_time) {
+ return LocalTime(unix_time, transitions_[hint - 1]);
+ }
+ }
+ }
+
+ const Transition target = {unix_time, 0, civil_second(), civil_second()};
+ const Transition* begin = &transitions_[0];
+ const Transition* tr = std::upper_bound(begin, begin + timecnt, target,
+ Transition::ByUnixTime());
+ local_time_hint_.store(static_cast<std::size_t>(tr - begin),
+ std::memory_order_relaxed);
+ return LocalTime(unix_time, *--tr);
+}
+
+time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const {
+ const std::size_t timecnt = transitions_.size();
+ assert(timecnt != 0); // We always add a transition.
+
+ // Find the first transition after our target civil time.
+ const Transition* tr = nullptr;
+ const Transition* begin = &transitions_[0];
+ const Transition* end = begin + timecnt;
+ if (cs < begin->civil_sec) {
+ tr = begin;
+ } else if (cs >= transitions_[timecnt - 1].civil_sec) {
+ tr = end;
+ } else {
+ const std::size_t hint = time_local_hint_.load(std::memory_order_relaxed);
+ if (0 < hint && hint < timecnt) {
+ if (transitions_[hint - 1].civil_sec <= cs) {
+ if (cs < transitions_[hint].civil_sec) {
+ tr = begin + hint;
+ }
+ }
+ }
+ if (tr == nullptr) {
+ const Transition target = {0, 0, cs, civil_second()};
+ tr = std::upper_bound(begin, end, target, Transition::ByCivilTime());
+ time_local_hint_.store(static_cast<std::size_t>(tr - begin),
+ std::memory_order_relaxed);
+ }
+ }
+
+ if (tr == begin) {
+ 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());
- return MakeUnique(cs - (civil_second() + tt.utc_offset));
- }
- // tr->prev_civil_sec < cs < tr->civil_sec
- return MakeSkipped(*tr, cs);
- }
-
- if (tr == end) {
- if (cs > (--tr)->prev_civil_sec) {
- // After the last transition. If we extended the transitions using
- // 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_) {
+ return MakeUnique(cs - (civil_second() + tt.utc_offset));
+ }
+ // tr->prev_civil_sec < cs < tr->civil_sec
+ return MakeSkipped(*tr, cs);
+ }
+
+ if (tr == end) {
+ if (cs > (--tr)->prev_civil_sec) {
+ // After the last transition. If we extended the transitions using
+ // 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;
- return TimeLocal(YearShift(cs, shift * -400), shift);
- }
- const TransitionType& tt(transition_types_[tr->type_index]);
+ 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());
- return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
- }
- // tr->civil_sec <= cs <= tr->prev_civil_sec
- return MakeRepeated(*tr, cs);
- }
-
- if (tr->prev_civil_sec < cs) {
- // tr->prev_civil_sec < cs < tr->civil_sec
- return MakeSkipped(*tr, cs);
- }
-
- if (cs <= (--tr)->prev_civil_sec) {
- // tr->civil_sec <= cs <= tr->prev_civil_sec
- return MakeRepeated(*tr, cs);
- }
-
- // In between transitions.
- return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
-}
-
+ return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
+ }
+ // tr->civil_sec <= cs <= tr->prev_civil_sec
+ return MakeRepeated(*tr, cs);
+ }
+
+ if (tr->prev_civil_sec < cs) {
+ // tr->prev_civil_sec < cs < tr->civil_sec
+ return MakeSkipped(*tr, cs);
+ }
+
+ if (cs <= (--tr)->prev_civil_sec) {
+ // tr->civil_sec <= cs <= tr->prev_civil_sec
+ return MakeRepeated(*tr, cs);
+ }
+
+ // In between transitions.
+ return MakeUnique(tr->unix_time + (cs - tr->civil_sec));
+}
+
std::string TimeZoneInfo::Version() const {
return version_;
}
-std::string TimeZoneInfo::Description() const {
- std::ostringstream oss;
- oss << "#trans=" << transitions_.size();
- oss << " #types=" << transition_types_.size();
- oss << " spec='" << future_spec_ << "'";
- return oss.str();
-}
-
+std::string TimeZoneInfo::Description() const {
+ std::ostringstream oss;
+ oss << "#trans=" << transitions_.size();
+ oss << " #types=" << transition_types_.size();
+ oss << " spec='" << future_spec_ << "'";
+ return oss.str();
+}
+
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)) {
+ 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.
- ++begin;
- }
+ ++begin;
+ }
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());
+ 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;
- }
- // When tr == end we return false, ignoring future_spec_.
- if (tr == end) return false;
+ }
+ // 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;
- return true;
-}
-
+ return true;
+}
+
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)) {
+ 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.
- ++begin;
- }
+ ++begin;
+ }
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_.
+ 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;
- return true;
- }
- unix_time += 1; // ceils
- }
+ return true;
+ }
+ unix_time += 1; // ceils
+ }
const Transition target = {unix_time, 0, civil_second(), civil_second()};
- const Transition* tr = std::lower_bound(begin, end, target,
- Transition::ByUnixTime());
+ 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;
- }
- // When tr == end we return the "last" transition, ignoring future_spec_.
- if (tr == begin) return false;
+ }
+ // 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;
- return true;
-}
-
-} // namespace cctz
+ return true;
+}
+
+} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_info.h b/contrib/libs/cctz/src/time_zone_info.h
index 431dc5b71b..009fe0b2a0 100644
--- a/contrib/libs/cctz/src/time_zone_info.h
+++ b/contrib/libs/cctz/src/time_zone_info.h
@@ -1,131 +1,131 @@
-// 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
-//
+// 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.
-
-#ifndef CCTZ_TIME_ZONE_INFO_H_
-#define CCTZ_TIME_ZONE_INFO_H_
-
-#include <atomic>
-#include <cstddef>
-#include <cstdint>
-#include <string>
-#include <vector>
-
+//
+// 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.
+
+#ifndef CCTZ_TIME_ZONE_INFO_H_
+#define CCTZ_TIME_ZONE_INFO_H_
+
+#include <atomic>
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
#include "cctz/civil_time.h"
#include "cctz/time_zone.h"
#include "cctz/zone_info_source.h"
-#include "time_zone_if.h"
-#include "tzfile.h"
-
-namespace cctz {
-
-// A transition to a new UTC offset.
-struct Transition {
- std::int_least64_t unix_time; // the instant of this transition
- std::uint_least8_t type_index; // index of the transition type
- civil_second civil_sec; // local civil time of transition
- civil_second prev_civil_sec; // local civil time one second earlier
-
- struct ByUnixTime {
- inline bool operator()(const Transition& lhs, const Transition& rhs) const {
- return lhs.unix_time < rhs.unix_time;
- }
- };
- struct ByCivilTime {
- inline bool operator()(const Transition& lhs, const Transition& rhs) const {
- return lhs.civil_sec < rhs.civil_sec;
- }
- };
-};
-
-// The characteristics of a particular transition.
-struct TransitionType {
- std::int_least32_t utc_offset; // the new prevailing UTC offset
- civil_second civil_max; // max convertible civil time for offset
- civil_second civil_min; // min convertible civil time for offset
- bool is_dst; // did we move into daylight-saving time
- std::uint_least8_t abbr_index; // index of the new abbreviation
-};
-
-// A time zone backed by the IANA Time Zone Database (zoneinfo).
-class TimeZoneInfo : public TimeZoneIf {
- public:
- TimeZoneInfo() = default;
- TimeZoneInfo(const TimeZoneInfo&) = delete;
- TimeZoneInfo& operator=(const TimeZoneInfo&) = delete;
-
- // Loads the zoneinfo for the given name, returning true if successful.
- bool Load(const std::string& name);
-
- // TimeZoneIf implementations.
- time_zone::absolute_lookup BreakTime(
+#include "time_zone_if.h"
+#include "tzfile.h"
+
+namespace cctz {
+
+// A transition to a new UTC offset.
+struct Transition {
+ std::int_least64_t unix_time; // the instant of this transition
+ std::uint_least8_t type_index; // index of the transition type
+ civil_second civil_sec; // local civil time of transition
+ civil_second prev_civil_sec; // local civil time one second earlier
+
+ struct ByUnixTime {
+ inline bool operator()(const Transition& lhs, const Transition& rhs) const {
+ return lhs.unix_time < rhs.unix_time;
+ }
+ };
+ struct ByCivilTime {
+ inline bool operator()(const Transition& lhs, const Transition& rhs) const {
+ return lhs.civil_sec < rhs.civil_sec;
+ }
+ };
+};
+
+// The characteristics of a particular transition.
+struct TransitionType {
+ std::int_least32_t utc_offset; // the new prevailing UTC offset
+ civil_second civil_max; // max convertible civil time for offset
+ civil_second civil_min; // min convertible civil time for offset
+ bool is_dst; // did we move into daylight-saving time
+ std::uint_least8_t abbr_index; // index of the new abbreviation
+};
+
+// A time zone backed by the IANA Time Zone Database (zoneinfo).
+class TimeZoneInfo : public TimeZoneIf {
+ public:
+ TimeZoneInfo() = default;
+ TimeZoneInfo(const TimeZoneInfo&) = delete;
+ TimeZoneInfo& operator=(const TimeZoneInfo&) = delete;
+
+ // Loads the zoneinfo for the given name, returning true if successful.
+ bool Load(const std::string& name);
+
+ // TimeZoneIf implementations.
+ time_zone::absolute_lookup BreakTime(
const time_point<seconds>& tp) const override;
- time_zone::civil_lookup MakeTime(
- const civil_second& cs) 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;
- std::string Description() const override;
-
- private:
- struct Header { // counts of:
- std::size_t timecnt; // transition times
- std::size_t typecnt; // transition types
- 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::string Description() const override;
+
+ private:
+ struct Header { // counts of:
+ std::size_t timecnt; // transition times
+ std::size_t typecnt; // transition types
+ 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)
-
- bool Build(const tzhead& tzh);
- std::size_t DataLength(std::size_t time_len) const;
- };
-
+
+ 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 EquivTransitions(std::uint_fast8_t tt1_index,
- std::uint_fast8_t tt2_index) const;
+ bool EquivTransitions(std::uint_fast8_t tt1_index,
+ std::uint_fast8_t tt2_index) const;
bool ExtendTransitions();
-
+
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,
- const TransitionType& tt) const;
- time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
- const Transition& tr) const;
- time_zone::civil_lookup TimeLocal(const civil_second& cs,
+
+ // Helpers for BreakTime() and MakeTime().
+ time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
+ const TransitionType& tt) const;
+ 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;
-
- 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::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 future_spec_; // for after the last zic transition
- bool extended_; // future_spec_ was used to generate transitions
+ 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
-
- // We remember the transitions found during the last BreakTime() and
- // MakeTime() calls. If the next request is for the same transition we
- // will avoid re-searching.
- mutable std::atomic<std::size_t> local_time_hint_ = {}; // BreakTime() hint
- mutable std::atomic<std::size_t> time_local_hint_ = {}; // MakeTime() hint
-};
-
-} // namespace cctz
-
-#endif // CCTZ_TIME_ZONE_INFO_H_
+
+ // We remember the transitions found during the last BreakTime() and
+ // MakeTime() calls. If the next request is for the same transition we
+ // will avoid re-searching.
+ mutable std::atomic<std::size_t> local_time_hint_ = {}; // BreakTime() hint
+ mutable std::atomic<std::size_t> time_local_hint_ = {}; // MakeTime() hint
+};
+
+} // namespace cctz
+
+#endif // CCTZ_TIME_ZONE_INFO_H_
diff --git a/contrib/libs/cctz/src/time_zone_libc.cc b/contrib/libs/cctz/src/time_zone_libc.cc
index f185b957b6..142fd792df 100644
--- a/contrib/libs/cctz/src/time_zone_libc.cc
+++ b/contrib/libs/cctz/src/time_zone_libc.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
-//
+// 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.
-
-#if defined(_WIN32) || defined(_WIN64)
+//
+// 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.
+
+#if defined(_WIN32) || defined(_WIN64)
#define _CRT_SECURE_NO_WARNINGS 1
-#endif
-
-#include "time_zone_libc.h"
-
-#include <chrono>
-#include <ctime>
+#endif
+
+#include "time_zone_libc.h"
+
+#include <chrono>
+#include <ctime>
#include <limits>
-#include <utility>
-
+#include <utility>
+
#include "cctz/civil_time.h"
#include "cctz/time_zone.h"
-
+
#if defined(_AIX)
extern "C" {
extern long altzone;
}
#endif
-namespace cctz {
-
-namespace {
-
-#if defined(_WIN32) || defined(_WIN64)
-// Uses the globals: '_timezone', '_dstbias' and '_tzname'.
+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) {
- const bool is_dst = tm.tm_isdst > 0;
+ const bool is_dst = tm.tm_isdst > 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)
-// Uses the globals: 'timezone', 'altzone' and 'tzname'.
+// Uses the globals: 'timezone', 'altzone' and 'tzname'.
auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
- const bool is_dst = tm.tm_isdst > 0;
+ 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 tzname[is_dst];
}
#elif defined(__native_client__) || defined(__myriad2__) || \
defined(__EMSCRIPTEN__)
-// Uses the globals: 'timezone' and 'tzname'.
+// Uses the globals: 'timezone' and 'tzname'.
auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) {
- const bool is_dst = tm.tm_isdst > 0;
+ const bool is_dst = tm.tm_isdst > 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
+#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) {
@@ -78,14 +78,14 @@ auto tm_gmtoff(const std::tm& tm) -> decltype(tm.__tm_gmtoff) {
return tm.__tm_gmtoff;
}
#else
-template <typename T>
+template <typename T>
auto tm_gmtoff(const T& tm) -> decltype(tm.tm_gmtoff) {
return tm.tm_gmtoff;
-}
-template <typename T>
+}
+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) {
@@ -105,8 +105,8 @@ auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) {
return tm.__tm_zone;
}
#endif // tm_zone
-#endif
-
+#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;
@@ -179,14 +179,14 @@ std::time_t find_trans(std::time_t lo, std::time_t hi, int offset) {
return hi;
}
-} // namespace
-
-TimeZoneLibC::TimeZoneLibC(const std::string& name)
- : local_(name == "localtime") {}
-
-time_zone::absolute_lookup TimeZoneLibC::BreakTime(
+} // namespace
+
+TimeZoneLibC::TimeZoneLibC(const std::string& name)
+ : local_(name == "localtime") {}
+
+time_zone::absolute_lookup TimeZoneLibC::BreakTime(
const time_point<seconds>& tp) const {
- time_zone::absolute_lookup al;
+ time_zone::absolute_lookup al;
al.offset = 0;
al.is_dst = false;
al.abbr = "-00";
@@ -204,14 +204,14 @@ time_zone::absolute_lookup TimeZoneLibC::BreakTime(
}
const std::time_t t = static_cast<std::time_t>(s);
- std::tm tm;
+ 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;
- }
+ }
const year_t year = tmp->tm_year + year_t{1900};
al.cs = civil_second(year, tmp->tm_mon + 1, tmp->tm_mday,
@@ -219,10 +219,10 @@ time_zone::absolute_lookup TimeZoneLibC::BreakTime(
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 {
+ 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 =
@@ -243,13 +243,13 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
const time_point<seconds> tp = time_point<seconds>::min();
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
}
- } else {
+ } 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};
}
- }
-
+ }
+
// 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.
@@ -288,18 +288,18 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
? 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 {
- return false;
-}
-
+ return false;
+}
+
bool TimeZoneLibC::PrevTransition(const time_point<seconds>&,
time_zone::civil_transition*) const {
- return false;
-}
-
+ return false;
+}
+
std::string TimeZoneLibC::Version() const {
return std::string(); // unknown
}
@@ -308,4 +308,4 @@ std::string TimeZoneLibC::Description() const {
return local_ ? "localtime" : "UTC";
}
-} // namespace cctz
+} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_libc.h b/contrib/libs/cctz/src/time_zone_libc.h
index 4cfe6dae31..5b39e37ab0 100644
--- a/contrib/libs/cctz/src/time_zone_libc.h
+++ b/contrib/libs/cctz/src/time_zone_libc.h
@@ -1,49 +1,49 @@
-// 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
-//
+// 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.
-
-#ifndef CCTZ_TIME_ZONE_LIBC_H_
-#define CCTZ_TIME_ZONE_LIBC_H_
-
-#include <string>
-
-#include "time_zone_if.h"
-
-namespace cctz {
-
-// A time zone backed by gmtime_r(3), localtime_r(3), and mktime(3),
-// and which therefore only supports UTC and the local time zone.
-// TODO: Add support for fixed offsets from UTC.
-class TimeZoneLibC : public TimeZoneIf {
- public:
- explicit TimeZoneLibC(const std::string& name);
-
- // TimeZoneIf implementations.
- time_zone::absolute_lookup BreakTime(
+//
+// 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.
+
+#ifndef CCTZ_TIME_ZONE_LIBC_H_
+#define CCTZ_TIME_ZONE_LIBC_H_
+
+#include <string>
+
+#include "time_zone_if.h"
+
+namespace cctz {
+
+// A time zone backed by gmtime_r(3), localtime_r(3), and mktime(3),
+// and which therefore only supports UTC and the local time zone.
+// TODO: Add support for fixed offsets from UTC.
+class TimeZoneLibC : public TimeZoneIf {
+ public:
+ explicit TimeZoneLibC(const std::string& name);
+
+ // TimeZoneIf implementations.
+ time_zone::absolute_lookup BreakTime(
const time_point<seconds>& tp) const override;
- time_zone::civil_lookup MakeTime(
- const civil_second& cs) 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;
- std::string Description() const override;
-
- private:
- const bool local_; // localtime or UTC
-};
-
-} // namespace cctz
-
-#endif // CCTZ_TIME_ZONE_LIBC_H_
+ std::string Description() const override;
+
+ private:
+ const bool local_; // localtime or UTC
+};
+
+} // namespace cctz
+
+#endif // CCTZ_TIME_ZONE_LIBC_H_
diff --git a/contrib/libs/cctz/src/time_zone_lookup.cc b/contrib/libs/cctz/src/time_zone_lookup.cc
index 92eb2ae763..fd656dcb46 100644
--- a/contrib/libs/cctz/src/time_zone_lookup.cc
+++ b/contrib/libs/cctz/src/time_zone_lookup.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
-//
+// 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.
-
+//
+// 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"
-
+
#if defined(__ANDROID__)
#include <sys/system_properties.h>
#if defined(__ANDROID_API__) && __ANDROID_API__ >= 21
@@ -26,15 +26,15 @@
#include <vector>
#endif
-#include <cstdlib>
-#include <cstring>
-#include <string>
-
-#include "time_zone_fixed.h"
-#include "time_zone_impl.h"
-
-namespace cctz {
-
+#include <cstdlib>
+#include <cstring>
+#include <string>
+
+#include "time_zone_fixed.h"
+#include "time_zone_impl.h"
+
+namespace cctz {
+
#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21
namespace {
// Android 'L' removes __system_property_get() from the NDK, however
@@ -64,24 +64,24 @@ int __system_property_get(const char* name, char* value) {
} // namespace
#endif
-std::string time_zone::name() const {
+std::string time_zone::name() const {
return effective_impl().Name();
-}
-
-time_zone::absolute_lookup time_zone::lookup(
+}
+
+time_zone::absolute_lookup time_zone::lookup(
const time_point<seconds>& tp) const {
return effective_impl().BreakTime(tp);
-}
-
-time_zone::civil_lookup time_zone::lookup(const civil_second& cs) const {
+}
+
+time_zone::civil_lookup time_zone::lookup(const civil_second& cs) const {
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);
@@ -104,22 +104,22 @@ const time_zone::Impl& time_zone::effective_impl() const {
return *impl_;
}
-bool load_time_zone(const std::string& name, time_zone* tz) {
- return time_zone::Impl::LoadTimeZone(name, tz);
-}
-
-time_zone utc_time_zone() {
- return time_zone::Impl::UTC(); // avoid name lookup
-}
-
+bool load_time_zone(const std::string& name, time_zone* tz) {
+ return time_zone::Impl::LoadTimeZone(name, tz);
+}
+
+time_zone utc_time_zone() {
+ return time_zone::Impl::UTC(); // avoid name lookup
+}
+
time_zone fixed_time_zone(const seconds& offset) {
- time_zone tz;
- load_time_zone(FixedOffsetToName(offset), &tz);
- return tz;
-}
-
-time_zone local_time_zone() {
- const char* zone = ":localtime";
+ time_zone tz;
+ load_time_zone(FixedOffsetToName(offset), &tz);
+ return tz;
+}
+
+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) {
@@ -139,45 +139,45 @@ time_zone local_time_zone() {
}
CFRelease(tz_default);
#endif
-
- // Allow ${TZ} to override to default zone.
- char* tz_env = nullptr;
-#if defined(_MSC_VER)
- _dupenv_s(&tz_env, nullptr, "TZ");
-#else
- tz_env = std::getenv("TZ");
-#endif
- if (tz_env) zone = tz_env;
-
- // We only support the "[:]<zone-name>" form.
- if (*zone == ':') ++zone;
-
- // Map "localtime" to a system-specific name, but
- // allow ${LOCALTIME} to override the default name.
- char* localtime_env = nullptr;
- if (strcmp(zone, "localtime") == 0) {
-#if defined(_MSC_VER)
- // System-specific default is just "localtime".
- _dupenv_s(&localtime_env, nullptr, "LOCALTIME");
-#else
- zone = "/etc/localtime"; // System-specific default.
- localtime_env = std::getenv("LOCALTIME");
-#endif
- if (localtime_env) zone = localtime_env;
- }
-
- const std::string name = zone;
-#if defined(_MSC_VER)
- free(localtime_env);
- free(tz_env);
-#endif
-
- time_zone tz;
- load_time_zone(name, &tz); // Falls back to UTC.
+
+ // Allow ${TZ} to override to default zone.
+ char* tz_env = nullptr;
+#if defined(_MSC_VER)
+ _dupenv_s(&tz_env, nullptr, "TZ");
+#else
+ tz_env = std::getenv("TZ");
+#endif
+ if (tz_env) zone = tz_env;
+
+ // We only support the "[:]<zone-name>" form.
+ if (*zone == ':') ++zone;
+
+ // Map "localtime" to a system-specific name, but
+ // allow ${LOCALTIME} to override the default name.
+ char* localtime_env = nullptr;
+ if (strcmp(zone, "localtime") == 0) {
+#if defined(_MSC_VER)
+ // System-specific default is just "localtime".
+ _dupenv_s(&localtime_env, nullptr, "LOCALTIME");
+#else
+ zone = "/etc/localtime"; // System-specific default.
+ localtime_env = std::getenv("LOCALTIME");
+#endif
+ if (localtime_env) zone = localtime_env;
+ }
+
+ const std::string name = zone;
+#if defined(_MSC_VER)
+ free(localtime_env);
+ free(tz_env);
+#endif
+
+ 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.
- return tz;
-}
-
-} // namespace cctz
+ return tz;
+}
+
+} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_posix.cc b/contrib/libs/cctz/src/time_zone_posix.cc
index 847db17cbc..9a4a38ace4 100644
--- a/contrib/libs/cctz/src/time_zone_posix.cc
+++ b/contrib/libs/cctz/src/time_zone_posix.cc
@@ -1,151 +1,151 @@
-// 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
-//
+// 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 "time_zone_posix.h"
-
-#include <cstddef>
-#include <cstring>
-#include <limits>
-#include <string>
-
-namespace cctz {
-
-namespace {
-
-const char kDigits[] = "0123456789";
-
-const char* ParseInt(const char* p, int min, int max, int* vp) {
- int value = 0;
- const char* op = p;
- const int kMaxInt = std::numeric_limits<int>::max();
- for (; const char* dp = strchr(kDigits, *p); ++p) {
- int d = static_cast<int>(dp - kDigits);
- if (d >= 10) break; // '\0'
- if (value > kMaxInt / 10) return nullptr;
- value *= 10;
- if (value > kMaxInt - d) return nullptr;
- value += d;
- }
- if (p == op || value < min || value > max) return nullptr;
- *vp = value;
- return p;
-}
-
-// abbr = <.*?> | [^-+,\d]{3,}
-const char* ParseAbbr(const char* p, std::string* abbr) {
- const char* op = p;
- if (*p == '<') { // special zoneinfo <...> form
- while (*++p != '>') {
- if (*p == '\0') return nullptr;
- }
- abbr->assign(op + 1, static_cast<std::size_t>(p - op) - 1);
- return ++p;
- }
- while (*p != '\0') {
- if (strchr("-+,", *p)) break;
- if (strchr(kDigits, *p)) break;
- ++p;
- }
- if (p - op < 3) return nullptr;
- abbr->assign(op, static_cast<std::size_t>(p - op));
- return p;
-}
-
-// offset = [+|-]hh[:mm[:ss]] (aggregated into single seconds value)
-const char* ParseOffset(const char* p, int min_hour, int max_hour, int sign,
- std::int_fast32_t* offset) {
- if (p == nullptr) return nullptr;
- if (*p == '+' || *p == '-') {
- if (*p++ == '-') sign = -sign;
- }
- int hours = 0;
- int minutes = 0;
- int seconds = 0;
-
- p = ParseInt(p, min_hour, max_hour, &hours);
- if (p == nullptr) return nullptr;
- if (*p == ':') {
- p = ParseInt(p + 1, 0, 59, &minutes);
- if (p == nullptr) return nullptr;
- if (*p == ':') {
- p = ParseInt(p + 1, 0, 59, &seconds);
- if (p == nullptr) return nullptr;
- }
- }
- *offset = sign * ((((hours * 60) + minutes) * 60) + seconds);
- return p;
-}
-
-// datetime = ( Jn | n | Mm.w.d ) [ / offset ]
-const char* ParseDateTime(const char* p, PosixTransition* res) {
- if (p != nullptr && *p == ',') {
- if (*++p == 'M') {
- int month = 0;
- if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') {
- int week = 0;
- if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') {
- int weekday = 0;
- if ((p = ParseInt(p + 1, 0, 6, &weekday)) != nullptr) {
- res->date.fmt = PosixTransition::M;
+//
+// 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 "time_zone_posix.h"
+
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <string>
+
+namespace cctz {
+
+namespace {
+
+const char kDigits[] = "0123456789";
+
+const char* ParseInt(const char* p, int min, int max, int* vp) {
+ int value = 0;
+ const char* op = p;
+ const int kMaxInt = std::numeric_limits<int>::max();
+ for (; const char* dp = strchr(kDigits, *p); ++p) {
+ int d = static_cast<int>(dp - kDigits);
+ if (d >= 10) break; // '\0'
+ if (value > kMaxInt / 10) return nullptr;
+ value *= 10;
+ if (value > kMaxInt - d) return nullptr;
+ value += d;
+ }
+ if (p == op || value < min || value > max) return nullptr;
+ *vp = value;
+ return p;
+}
+
+// abbr = <.*?> | [^-+,\d]{3,}
+const char* ParseAbbr(const char* p, std::string* abbr) {
+ const char* op = p;
+ if (*p == '<') { // special zoneinfo <...> form
+ while (*++p != '>') {
+ if (*p == '\0') return nullptr;
+ }
+ abbr->assign(op + 1, static_cast<std::size_t>(p - op) - 1);
+ return ++p;
+ }
+ while (*p != '\0') {
+ if (strchr("-+,", *p)) break;
+ if (strchr(kDigits, *p)) break;
+ ++p;
+ }
+ if (p - op < 3) return nullptr;
+ abbr->assign(op, static_cast<std::size_t>(p - op));
+ return p;
+}
+
+// offset = [+|-]hh[:mm[:ss]] (aggregated into single seconds value)
+const char* ParseOffset(const char* p, int min_hour, int max_hour, int sign,
+ std::int_fast32_t* offset) {
+ if (p == nullptr) return nullptr;
+ if (*p == '+' || *p == '-') {
+ if (*p++ == '-') sign = -sign;
+ }
+ int hours = 0;
+ int minutes = 0;
+ int seconds = 0;
+
+ p = ParseInt(p, min_hour, max_hour, &hours);
+ if (p == nullptr) return nullptr;
+ if (*p == ':') {
+ p = ParseInt(p + 1, 0, 59, &minutes);
+ if (p == nullptr) return nullptr;
+ if (*p == ':') {
+ p = ParseInt(p + 1, 0, 59, &seconds);
+ if (p == nullptr) return nullptr;
+ }
+ }
+ *offset = sign * ((((hours * 60) + minutes) * 60) + seconds);
+ return p;
+}
+
+// datetime = ( Jn | n | Mm.w.d ) [ / offset ]
+const char* ParseDateTime(const char* p, PosixTransition* res) {
+ if (p != nullptr && *p == ',') {
+ if (*++p == 'M') {
+ int month = 0;
+ if ((p = ParseInt(p + 1, 1, 12, &month)) != nullptr && *p == '.') {
+ int week = 0;
+ if ((p = ParseInt(p + 1, 1, 5, &week)) != nullptr && *p == '.') {
+ 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);
- }
- }
- }
- } else if (*p == 'J') {
- int day = 0;
- if ((p = ParseInt(p + 1, 1, 365, &day)) != nullptr) {
- res->date.fmt = PosixTransition::J;
+ }
+ }
+ }
+ } else if (*p == 'J') {
+ 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);
- }
- } else {
- int day = 0;
- if ((p = ParseInt(p, 0, 365, &day)) != nullptr) {
- res->date.fmt = PosixTransition::N;
+ }
+ } 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);
- }
- }
- }
- if (p != nullptr) {
- res->time.offset = 2 * 60 * 60; // default offset is 02:00:00
- if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
- }
- return p;
-}
-
-} // namespace
-
-// spec = std offset [ dst [ offset ] , datetime , datetime ]
-bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
- const char* p = spec.c_str();
- if (*p == ':') return false;
-
- p = ParseAbbr(p, &res->std_abbr);
- p = ParseOffset(p, 0, 24, -1, &res->std_offset);
- if (p == nullptr) return false;
- if (*p == '\0') return true;
-
- p = ParseAbbr(p, &res->dst_abbr);
- if (p == nullptr) return false;
- res->dst_offset = res->std_offset + (60 * 60); // default
- if (*p != ',') p = ParseOffset(p, 0, 24, -1, &res->dst_offset);
-
- p = ParseDateTime(p, &res->dst_start);
- p = ParseDateTime(p, &res->dst_end);
-
- return p != nullptr && *p == '\0';
-}
-
-} // namespace cctz
+ }
+ }
+ }
+ if (p != nullptr) {
+ res->time.offset = 2 * 60 * 60; // default offset is 02:00:00
+ if (*p == '/') p = ParseOffset(p + 1, -167, 167, 1, &res->time.offset);
+ }
+ return p;
+}
+
+} // namespace
+
+// spec = std offset [ dst [ offset ] , datetime , datetime ]
+bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res) {
+ const char* p = spec.c_str();
+ if (*p == ':') return false;
+
+ p = ParseAbbr(p, &res->std_abbr);
+ p = ParseOffset(p, 0, 24, -1, &res->std_offset);
+ if (p == nullptr) return false;
+ if (*p == '\0') return true;
+
+ p = ParseAbbr(p, &res->dst_abbr);
+ if (p == nullptr) return false;
+ res->dst_offset = res->std_offset + (60 * 60); // default
+ if (*p != ',') p = ParseOffset(p, 0, 24, -1, &res->dst_offset);
+
+ p = ParseDateTime(p, &res->dst_start);
+ p = ParseDateTime(p, &res->dst_end);
+
+ return p != nullptr && *p == '\0';
+}
+
+} // namespace cctz
diff --git a/contrib/libs/cctz/src/time_zone_posix.h b/contrib/libs/cctz/src/time_zone_posix.h
index aea93efdff..96e66b9f34 100644
--- a/contrib/libs/cctz/src/time_zone_posix.h
+++ b/contrib/libs/cctz/src/time_zone_posix.h
@@ -1,71 +1,71 @@
-// 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
-//
+// 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.
-
-// Parsing of a POSIX zone spec as described in the TZ part of section 8.3 in
-// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html.
-//
-// The current POSIX spec for America/Los_Angeles is "PST8PDT,M3.2.0,M11.1.0",
-// which would be broken down as ...
-//
-// PosixTimeZone {
-// std_abbr = "PST"
-// std_offset = -28800
-// dst_abbr = "PDT"
-// dst_offset = -25200
-// dst_start = PosixTransition {
-// date {
-// m {
-// month = 3
-// week = 2
-// weekday = 0
-// }
-// }
-// time {
-// offset = 7200
-// }
-// }
-// dst_end = PosixTransition {
-// date {
-// m {
-// month = 11
-// week = 1
-// weekday = 0
-// }
-// }
-// time {
-// offset = 7200
-// }
-// }
-// }
-
-#ifndef CCTZ_TIME_ZONE_POSIX_H_
-#define CCTZ_TIME_ZONE_POSIX_H_
-
-#include <cstdint>
-#include <string>
-
-namespace cctz {
-
-// The date/time of the transition. The date is specified as either:
-// (J) the Nth day of the year (1 <= N <= 365), excluding leap days, or
-// (N) the Nth day of the year (0 <= N <= 365), including leap days, or
-// (M) the Nth weekday of a month (e.g., the 2nd Sunday in March).
-// The time, specified as a day offset, identifies the particular moment
-// of the transition, and may be negative or >= 24h, and in which case
-// it would take us to another day, and perhaps week, or even month.
-struct PosixTransition {
- enum DateFormat { J, N, M };
+//
+// 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.
+
+// Parsing of a POSIX zone spec as described in the TZ part of section 8.3 in
+// http://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html.
+//
+// The current POSIX spec for America/Los_Angeles is "PST8PDT,M3.2.0,M11.1.0",
+// which would be broken down as ...
+//
+// PosixTimeZone {
+// std_abbr = "PST"
+// std_offset = -28800
+// dst_abbr = "PDT"
+// dst_offset = -25200
+// dst_start = PosixTransition {
+// date {
+// m {
+// month = 3
+// week = 2
+// weekday = 0
+// }
+// }
+// time {
+// offset = 7200
+// }
+// }
+// dst_end = PosixTransition {
+// date {
+// m {
+// month = 11
+// week = 1
+// weekday = 0
+// }
+// }
+// time {
+// offset = 7200
+// }
+// }
+// }
+
+#ifndef CCTZ_TIME_ZONE_POSIX_H_
+#define CCTZ_TIME_ZONE_POSIX_H_
+
+#include <cstdint>
+#include <string>
+
+namespace cctz {
+
+// The date/time of the transition. The date is specified as either:
+// (J) the Nth day of the year (1 <= N <= 365), excluding leap days, or
+// (N) the Nth day of the year (0 <= N <= 365), including leap days, or
+// (M) the Nth weekday of a month (e.g., the 2nd Sunday in March).
+// The time, specified as a day offset, identifies the particular moment
+// of the transition, and may be negative or >= 24h, and in which case
+// it would take us to another day, and perhaps week, or even month.
+struct PosixTransition {
+ enum DateFormat { J, N, M };
struct Date {
struct NonLeapDay {
@@ -80,45 +80,45 @@ struct PosixTransition {
std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat
};
- DateFormat fmt;
+ DateFormat fmt;
- union {
+ union {
NonLeapDay j;
Day n;
MonthWeekWeekday m;
- };
+ };
};
struct Time {
- std::int_fast32_t offset; // seconds before/after 00:00:00
+ std::int_fast32_t offset; // seconds before/after 00:00:00
};
Date date;
Time time;
-};
-
-// The entirety of a POSIX-string specified time-zone rule. The standard
-// abbreviation and offset are always given. If the time zone includes
-// daylight saving, then the daylight abbrevation is non-empty and the
-// remaining fields are also valid. Note that the start/end transitions
-// are not ordered---in the southern hemisphere the transition to end
-// daylight time occurs first in any particular year.
-struct PosixTimeZone {
- std::string std_abbr;
- std::int_fast32_t std_offset;
-
- std::string dst_abbr;
- std::int_fast32_t dst_offset;
- PosixTransition dst_start;
- PosixTransition dst_end;
-};
-
-// Breaks down a POSIX time-zone specification into its constituent pieces,
-// filling in any missing values (DST offset, or start/end transition times)
-// with the standard-defined defaults. Returns false if the specification
-// could not be parsed (although some fields of *res may have been altered).
-bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res);
-
-} // namespace cctz
-
-#endif // CCTZ_TIME_ZONE_POSIX_H_
+};
+
+// The entirety of a POSIX-string specified time-zone rule. The standard
+// abbreviation and offset are always given. If the time zone includes
+// daylight saving, then the daylight abbrevation is non-empty and the
+// remaining fields are also valid. Note that the start/end transitions
+// are not ordered---in the southern hemisphere the transition to end
+// daylight time occurs first in any particular year.
+struct PosixTimeZone {
+ std::string std_abbr;
+ std::int_fast32_t std_offset;
+
+ std::string dst_abbr;
+ std::int_fast32_t dst_offset;
+ PosixTransition dst_start;
+ PosixTransition dst_end;
+};
+
+// Breaks down a POSIX time-zone specification into its constituent pieces,
+// filling in any missing values (DST offset, or start/end transition times)
+// with the standard-defined defaults. Returns false if the specification
+// could not be parsed (although some fields of *res may have been altered).
+bool ParsePosixSpec(const std::string& spec, PosixTimeZone* res);
+
+} // namespace cctz
+
+#endif // CCTZ_TIME_ZONE_POSIX_H_
diff --git a/contrib/libs/cctz/src/tzfile.h b/contrib/libs/cctz/src/tzfile.h
index ee91104443..b86ce475c8 100644
--- a/contrib/libs/cctz/src/tzfile.h
+++ b/contrib/libs/cctz/src/tzfile.h
@@ -1,9 +1,9 @@
/* Layout and location of TZif files. */
-#ifndef TZFILE_H
-
-#define TZFILE_H
+#ifndef TZFILE_H
+#define TZFILE_H
+
/*
** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.
@@ -30,7 +30,7 @@
#endif /* !defined TZDEFAULT */
#ifndef TZDEFRULES
-#define TZDEFRULES "posixrules"
+#define TZDEFRULES "posixrules"
#endif /* !defined TZDEFRULES */
@@ -40,38 +40,38 @@
** Each file begins with. . .
*/
-#define TZ_MAGIC "TZif"
+#define TZ_MAGIC "TZif"
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_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_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 */
- char tzh_typecnt[4]; /* coded number of local time types */
- char tzh_charcnt[4]; /* coded number of abbr. chars */
+ 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 */
+ char tzh_typecnt[4]; /* coded number of local time types */
+ char tzh_charcnt[4]; /* coded number of abbr. chars */
};
/*
** . . .followed by. . .
**
-** tzh_timecnt (char [4])s coded transition times a la time(2)
-** tzh_timecnt (unsigned char)s types of local time starting at above
-** tzh_typecnt repetitions of
-** one (char [4]) coded UT offset in seconds
-** one (unsigned char) used to set tm_isdst
-** one (unsigned char) that's an abbreviation list index
-** tzh_charcnt (char)s '\0'-terminated zone abbreviations
-** tzh_leapcnt repetitions of
-** one (char [4]) coded leap second transition times
-** one (char [4]) total correction after above
-** tzh_ttisstdcnt (char)s indexed by type; if 1, transition
-** time is standard time, if 0,
+** tzh_timecnt (char [4])s coded transition times a la time(2)
+** tzh_timecnt (unsigned char)s types of local time starting at above
+** tzh_typecnt repetitions of
+** one (char [4]) coded UT offset in seconds
+** one (unsigned char) used to set tm_isdst
+** one (unsigned char) that's an abbreviation list index
+** tzh_charcnt (char)s '\0'-terminated zone abbreviations
+** tzh_leapcnt repetitions of
+** one (char [4]) coded leap second transition times
+** 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
-** assumed to be local time
+** 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
@@ -103,21 +103,21 @@ struct tzhead {
*/
#ifndef TZ_MAX_TIMES
-#define TZ_MAX_TIMES 2000
+#define TZ_MAX_TIMES 2000
#endif /* !defined TZ_MAX_TIMES */
#ifndef TZ_MAX_TYPES
/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */
-#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
#endif /* !defined TZ_MAX_TYPES */
#ifndef TZ_MAX_CHARS
-#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
- /* (limited by what unsigned chars can hold) */
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+ /* (limited by what unsigned chars can hold) */
#endif /* !defined TZ_MAX_CHARS */
#ifndef TZ_MAX_LEAPS
-#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
#endif /* !defined TZ_MAX_LEAPS */
-#endif /* !defined TZFILE_H */
+#endif /* !defined TZFILE_H */
diff --git a/contrib/libs/cctz/tzdata/factory.cpp b/contrib/libs/cctz/tzdata/factory.cpp
index 5a4b4a27b6..d7e1acc8b9 100644
--- a/contrib/libs/cctz/tzdata/factory.cpp
+++ b/contrib/libs/cctz/tzdata/factory.cpp
@@ -1,60 +1,60 @@
#include <contrib/libs/cctz/include/cctz/zone_info_source.h>
-
+
#include <library/cpp/resource/resource.h>
-
-#include <util/generic/string.h>
-#include <util/stream/str.h>
+
+#include <util/generic/string.h>
+#include <util/stream/str.h>
#include <util/string/builder.h>
-
-namespace cctz_extension {
- namespace {
-
- class TZoneInfoSource: public cctz::ZoneInfoSource {
- private:
- TZoneInfoSource(TString&& data)
- : TimeZoneData_(data)
- , Stream_(TimeZoneData_)
- {
- }
-
- public:
- static std::unique_ptr<cctz::ZoneInfoSource> LoadZone(const std::string& zoneName) {
+
+namespace cctz_extension {
+ namespace {
+
+ class TZoneInfoSource: public cctz::ZoneInfoSource {
+ private:
+ TZoneInfoSource(TString&& data)
+ : TimeZoneData_(data)
+ , Stream_(TimeZoneData_)
+ {
+ }
+
+ public:
+ static std::unique_ptr<cctz::ZoneInfoSource> LoadZone(const std::string& zoneName) {
TString resourceName = TStringBuilder() << "/cctz/tzdata/"sv << zoneName;
- TString tzData;
+ TString tzData;
if (!NResource::FindExact(resourceName, &tzData)) {
- return nullptr;
- }
- return std::unique_ptr<cctz::ZoneInfoSource>(new TZoneInfoSource(std::move(tzData)));
- }
-
- size_t Read(void* buf, size_t size) override {
- return Stream_.Read(buf, size);
- }
-
- int Skip(size_t offset) override {
- Stream_.Skip(offset);
- return 0;
- }
-
- private:
- const TString TimeZoneData_;
- TStringInput Stream_;
- };
-
- std::unique_ptr<cctz::ZoneInfoSource> CustomFactory(
- const std::string& name,
- const std::function<std::unique_ptr<cctz::ZoneInfoSource>(const std::string& name)>& /*fallback*/
- )
- {
- std::unique_ptr<cctz::ZoneInfoSource> zis = TZoneInfoSource::LoadZone(name);
- if (zis) {
- return zis;
- }
- return nullptr;
- }
-
- } // namespace
-
- ZoneInfoSourceFactory zone_info_source_factory = CustomFactory;
-
-} // namespace cctz_extension
+ return nullptr;
+ }
+ return std::unique_ptr<cctz::ZoneInfoSource>(new TZoneInfoSource(std::move(tzData)));
+ }
+
+ size_t Read(void* buf, size_t size) override {
+ return Stream_.Read(buf, size);
+ }
+
+ int Skip(size_t offset) override {
+ Stream_.Skip(offset);
+ return 0;
+ }
+
+ private:
+ const TString TimeZoneData_;
+ TStringInput Stream_;
+ };
+
+ std::unique_ptr<cctz::ZoneInfoSource> CustomFactory(
+ const std::string& name,
+ const std::function<std::unique_ptr<cctz::ZoneInfoSource>(const std::string& name)>& /*fallback*/
+ )
+ {
+ std::unique_ptr<cctz::ZoneInfoSource> zis = TZoneInfoSource::LoadZone(name);
+ if (zis) {
+ return zis;
+ }
+ return nullptr;
+ }
+
+ } // namespace
+
+ ZoneInfoSourceFactory zone_info_source_factory = CustomFactory;
+
+} // namespace cctz_extension
diff --git a/contrib/libs/cctz/tzdata/update_tzdata.py b/contrib/libs/cctz/tzdata/update_tzdata.py
index 9c3cd07352..2f741ce1b8 100755
--- a/contrib/libs/cctz/tzdata/update_tzdata.py
+++ b/contrib/libs/cctz/tzdata/update_tzdata.py
@@ -50,7 +50,7 @@ def create_cmakelists(zoneinfo_dir):
cmd = 'add' if os.path.basename(fn) in all_hashes else 'remove'
subprocess.check_call(['svn', cmd, '--force', fn])
- with open('ya.make.resources', 'w') as f:
+ with open('ya.make.resources', 'w') as f:
print >>f, yamake_template.format(resources)
def get_latest_iana_version():
@@ -61,11 +61,11 @@ def get_latest_iana_version():
return version_match.group(1)
def get_current_version():
- try:
- with open('VERSION') as f:
- return f.read()
- except:
- return 0
+ try:
+ with open('VERSION') as f:
+ return f.read()
+ except:
+ return 0
def prepare_tzdata(version):
temp_dir = tempfile.mkdtemp()
@@ -86,7 +86,7 @@ def prepare_tzdata(version):
print 'Converting tzdata to binary format'
subprocess.check_call(['make', '-s', '-C', temp_dir, 'TOPDIR={}'.format(temp_dir), 'install'])
- print 'Preparing ya.make.resources'
+ print 'Preparing ya.make.resources'
zoneinfo_dir = os.path.join(temp_dir, 'usr', 'share', 'zoneinfo')
create_cmakelists(zoneinfo_dir)
finally:
diff --git a/contrib/libs/cctz/tzdata/ya.make b/contrib/libs/cctz/tzdata/ya.make
index 3b9ff5cc67..1173cf0627 100644
--- a/contrib/libs/cctz/tzdata/ya.make
+++ b/contrib/libs/cctz/tzdata/ya.make
@@ -13,10 +13,10 @@ PEERDIR(
contrib/libs/cctz
)
-INCLUDE(ya.make.resources)
+INCLUDE(ya.make.resources)
-SRCS(
- GLOBAL factory.cpp
+SRCS(
+ GLOBAL factory.cpp
)
END()
diff --git a/contrib/libs/cctz/tzdata/ya.make.resources b/contrib/libs/cctz/tzdata/ya.make.resources
index 5c7575f3bd..0e38f3df1d 100644
--- a/contrib/libs/cctz/tzdata/ya.make.resources
+++ b/contrib/libs/cctz/tzdata/ya.make.resources
@@ -1,4 +1,4 @@
-RESOURCE(
+RESOURCE(
generated/58543f30ac34b6510b552b9b3e82b772 /cctz/tzdata/posixrules
generated/796a57137d718e4fa3db8ef611f18e61 /cctz/tzdata/Africa/Abidjan
generated/33cffb9ac13285f945f3c4ef6ce13585 /cctz/tzdata/Africa/Accra
@@ -594,4 +594,4 @@ RESOURCE(
generated/39b47bf37a27f7bcd5d3f7c51343c7fc /cctz/tzdata/W-SU
generated/0124cd65b22dfd92129cb0a43719c717 /cctz/tzdata/WET
generated/51d8a0e68892ebf0854a1b4250ffb26b /cctz/tzdata/Zulu
-)
+)