create
This commit is contained in:
199
Pods/abseil/absl/time/civil_time.cc
generated
Normal file
199
Pods/abseil/absl/time/civil_time.cc
generated
Normal file
@@ -0,0 +1,199 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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 "absl/time/civil_time.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
namespace {
|
||||
|
||||
// Since a civil time has a larger year range than absl::Time (64-bit years vs
|
||||
// 64-bit seconds, respectively) we normalize years to roughly +/- 400 years
|
||||
// around the year 2400, which will produce an equivalent year in a range that
|
||||
// absl::Time can handle.
|
||||
inline civil_year_t NormalizeYear(civil_year_t year) {
|
||||
return 2400 + year % 400;
|
||||
}
|
||||
|
||||
// Formats the given CivilSecond according to the given format.
|
||||
std::string FormatYearAnd(string_view fmt, CivilSecond cs) {
|
||||
const CivilSecond ncs(NormalizeYear(cs.year()), cs.month(), cs.day(),
|
||||
cs.hour(), cs.minute(), cs.second());
|
||||
const TimeZone utc = UTCTimeZone();
|
||||
return StrCat(cs.year(), FormatTime(fmt, FromCivil(ncs, utc), utc));
|
||||
}
|
||||
|
||||
template <typename CivilT>
|
||||
bool ParseYearAnd(string_view fmt, string_view s, CivilT* c) {
|
||||
// Civil times support a larger year range than absl::Time, so we need to
|
||||
// parse the year separately, normalize it, then use absl::ParseTime on the
|
||||
// normalized string.
|
||||
const std::string ss = std::string(s); // TODO(absl-team): Avoid conversion.
|
||||
const char* const np = ss.c_str();
|
||||
char* endp;
|
||||
errno = 0;
|
||||
const civil_year_t y =
|
||||
std::strtoll(np, &endp, 10); // NOLINT(runtime/deprecated_fn)
|
||||
if (endp == np || errno == ERANGE) return false;
|
||||
const std::string norm = StrCat(NormalizeYear(y), endp);
|
||||
|
||||
const TimeZone utc = UTCTimeZone();
|
||||
Time t;
|
||||
if (ParseTime(StrCat("%Y", fmt), norm, utc, &t, nullptr)) {
|
||||
const auto cs = ToCivilSecond(t, utc);
|
||||
*c = CivilT(y, cs.month(), cs.day(), cs.hour(), cs.minute(), cs.second());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tries to parse the type as a CivilT1, but then assigns the result to the
|
||||
// argument of type CivilT2.
|
||||
template <typename CivilT1, typename CivilT2>
|
||||
bool ParseAs(string_view s, CivilT2* c) {
|
||||
CivilT1 t1;
|
||||
if (ParseCivilTime(s, &t1)) {
|
||||
*c = CivilT2(t1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename CivilT>
|
||||
bool ParseLenient(string_view s, CivilT* c) {
|
||||
// A fastpath for when the given string data parses exactly into the given
|
||||
// type T (e.g., s="YYYY-MM-DD" and CivilT=CivilDay).
|
||||
if (ParseCivilTime(s, c)) return true;
|
||||
// Try parsing as each of the 6 types, trying the most common types first
|
||||
// (based on csearch results).
|
||||
if (ParseAs<CivilDay>(s, c)) return true;
|
||||
if (ParseAs<CivilSecond>(s, c)) return true;
|
||||
if (ParseAs<CivilHour>(s, c)) return true;
|
||||
if (ParseAs<CivilMonth>(s, c)) return true;
|
||||
if (ParseAs<CivilMinute>(s, c)) return true;
|
||||
if (ParseAs<CivilYear>(s, c)) return true;
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string FormatCivilTime(CivilSecond c) {
|
||||
return FormatYearAnd("-%m-%d%ET%H:%M:%S", c);
|
||||
}
|
||||
std::string FormatCivilTime(CivilMinute c) {
|
||||
return FormatYearAnd("-%m-%d%ET%H:%M", c);
|
||||
}
|
||||
std::string FormatCivilTime(CivilHour c) {
|
||||
return FormatYearAnd("-%m-%d%ET%H", c);
|
||||
}
|
||||
std::string FormatCivilTime(CivilDay c) { return FormatYearAnd("-%m-%d", c); }
|
||||
std::string FormatCivilTime(CivilMonth c) { return FormatYearAnd("-%m", c); }
|
||||
std::string FormatCivilTime(CivilYear c) { return FormatYearAnd("", c); }
|
||||
|
||||
bool ParseCivilTime(string_view s, CivilSecond* c) {
|
||||
return ParseYearAnd("-%m-%d%ET%H:%M:%S", s, c);
|
||||
}
|
||||
bool ParseCivilTime(string_view s, CivilMinute* c) {
|
||||
return ParseYearAnd("-%m-%d%ET%H:%M", s, c);
|
||||
}
|
||||
bool ParseCivilTime(string_view s, CivilHour* c) {
|
||||
return ParseYearAnd("-%m-%d%ET%H", s, c);
|
||||
}
|
||||
bool ParseCivilTime(string_view s, CivilDay* c) {
|
||||
return ParseYearAnd("-%m-%d", s, c);
|
||||
}
|
||||
bool ParseCivilTime(string_view s, CivilMonth* c) {
|
||||
return ParseYearAnd("-%m", s, c);
|
||||
}
|
||||
bool ParseCivilTime(string_view s, CivilYear* c) {
|
||||
return ParseYearAnd("", s, c);
|
||||
}
|
||||
|
||||
bool ParseLenientCivilTime(string_view s, CivilSecond* c) {
|
||||
return ParseLenient(s, c);
|
||||
}
|
||||
bool ParseLenientCivilTime(string_view s, CivilMinute* c) {
|
||||
return ParseLenient(s, c);
|
||||
}
|
||||
bool ParseLenientCivilTime(string_view s, CivilHour* c) {
|
||||
return ParseLenient(s, c);
|
||||
}
|
||||
bool ParseLenientCivilTime(string_view s, CivilDay* c) {
|
||||
return ParseLenient(s, c);
|
||||
}
|
||||
bool ParseLenientCivilTime(string_view s, CivilMonth* c) {
|
||||
return ParseLenient(s, c);
|
||||
}
|
||||
bool ParseLenientCivilTime(string_view s, CivilYear* c) {
|
||||
return ParseLenient(s, c);
|
||||
}
|
||||
|
||||
namespace time_internal {
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, CivilYear y) {
|
||||
return os << FormatCivilTime(y);
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, CivilMonth m) {
|
||||
return os << FormatCivilTime(m);
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, CivilDay d) {
|
||||
return os << FormatCivilTime(d);
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, CivilHour h) {
|
||||
return os << FormatCivilTime(h);
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, CivilMinute m) {
|
||||
return os << FormatCivilTime(m);
|
||||
}
|
||||
std::ostream& operator<<(std::ostream& os, CivilSecond s) {
|
||||
return os << FormatCivilTime(s);
|
||||
}
|
||||
|
||||
bool AbslParseFlag(string_view s, CivilSecond* c, std::string*) {
|
||||
return ParseLenientCivilTime(s, c);
|
||||
}
|
||||
bool AbslParseFlag(string_view s, CivilMinute* c, std::string*) {
|
||||
return ParseLenientCivilTime(s, c);
|
||||
}
|
||||
bool AbslParseFlag(string_view s, CivilHour* c, std::string*) {
|
||||
return ParseLenientCivilTime(s, c);
|
||||
}
|
||||
bool AbslParseFlag(string_view s, CivilDay* c, std::string*) {
|
||||
return ParseLenientCivilTime(s, c);
|
||||
}
|
||||
bool AbslParseFlag(string_view s, CivilMonth* c, std::string*) {
|
||||
return ParseLenientCivilTime(s, c);
|
||||
}
|
||||
bool AbslParseFlag(string_view s, CivilYear* c, std::string*) {
|
||||
return ParseLenientCivilTime(s, c);
|
||||
}
|
||||
std::string AbslUnparseFlag(CivilSecond c) { return FormatCivilTime(c); }
|
||||
std::string AbslUnparseFlag(CivilMinute c) { return FormatCivilTime(c); }
|
||||
std::string AbslUnparseFlag(CivilHour c) { return FormatCivilTime(c); }
|
||||
std::string AbslUnparseFlag(CivilDay c) { return FormatCivilTime(c); }
|
||||
std::string AbslUnparseFlag(CivilMonth c) { return FormatCivilTime(c); }
|
||||
std::string AbslUnparseFlag(CivilYear c) { return FormatCivilTime(c); }
|
||||
|
||||
} // namespace time_internal
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
589
Pods/abseil/absl/time/civil_time.h
generated
Normal file
589
Pods/abseil/absl/time/civil_time.h
generated
Normal file
@@ -0,0 +1,589 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: civil_time.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines abstractions for computing with "civil time".
|
||||
// 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`. A "date"
|
||||
// is perhaps the most common example of a civil time (represented here as
|
||||
// an `absl::CivilDay`).
|
||||
//
|
||||
// Modern-day civil time follows the Gregorian Calendar and is a
|
||||
// time-zone-independent concept: a civil time of "2015-06-01 12:00:00", for
|
||||
// example, is not tied to a time zone. Put another way, a civil time does not
|
||||
// map to a unique point in time; a civil time must be mapped to an absolute
|
||||
// time *through* a time zone.
|
||||
//
|
||||
// Because a civil time is what most people think of as "time," it is common to
|
||||
// map absolute times to civil times to present to users.
|
||||
//
|
||||
// Time zones define the relationship between absolute and civil times. Given an
|
||||
// absolute or civil time and a time zone, you can compute the other time:
|
||||
//
|
||||
// Civil Time = F(Absolute Time, Time Zone)
|
||||
// Absolute Time = G(Civil Time, Time Zone)
|
||||
//
|
||||
// The Abseil time library allows you to construct such civil times from
|
||||
// absolute times; consult time.h for such functionality.
|
||||
//
|
||||
// This library provides six classes for constructing civil-time objects, and
|
||||
// provides several helper functions for rounding, iterating, and performing
|
||||
// arithmetic on civil-time objects, while avoiding complications like
|
||||
// daylight-saving time (DST):
|
||||
//
|
||||
// * `absl::CivilSecond`
|
||||
// * `absl::CivilMinute`
|
||||
// * `absl::CivilHour`
|
||||
// * `absl::CivilDay`
|
||||
// * `absl::CivilMonth`
|
||||
// * `absl::CivilYear`
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Construct a civil-time object for a specific day
|
||||
// const absl::CivilDay cd(1969, 07, 20);
|
||||
//
|
||||
// // Construct a civil-time object for a specific second
|
||||
// const absl::CivilSecond cd(2018, 8, 1, 12, 0, 1);
|
||||
//
|
||||
// Note: In C++14 and later, this library is usable in a constexpr context.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // Valid in C++14
|
||||
// constexpr absl::CivilDay cd(1969, 07, 20);
|
||||
|
||||
#ifndef ABSL_TIME_CIVIL_TIME_H_
|
||||
#define ABSL_TIME_CIVIL_TIME_H_
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
namespace time_internal {
|
||||
struct second_tag : cctz::detail::second_tag {};
|
||||
struct minute_tag : second_tag, cctz::detail::minute_tag {};
|
||||
struct hour_tag : minute_tag, cctz::detail::hour_tag {};
|
||||
struct day_tag : hour_tag, cctz::detail::day_tag {};
|
||||
struct month_tag : day_tag, cctz::detail::month_tag {};
|
||||
struct year_tag : month_tag, cctz::detail::year_tag {};
|
||||
} // namespace time_internal
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// CivilSecond, CivilMinute, CivilHour, CivilDay, CivilMonth, CivilYear
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// Each of these civil-time types is a simple value type with the same
|
||||
// interface for construction and the same six accessors for each of the civil
|
||||
// time 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.
|
||||
//
|
||||
// CONSTRUCTION
|
||||
//
|
||||
// Each of the civil-time types can be constructed in two ways: by directly
|
||||
// passing to the constructor up to six integers representing the YMDHMS fields,
|
||||
// or by copying the YMDHMS fields from a differently aligned civil-time type.
|
||||
// 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. Since there is no
|
||||
// minimum year, the default is 1970.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// absl::CivilDay default_value; // 1970-01-01 00:00:00
|
||||
//
|
||||
// absl::CivilDay a(2015, 2, 3); // 2015-02-03 00:00:00
|
||||
// absl::CivilDay b(2015, 2, 3, 4, 5, 6); // 2015-02-03 00:00:00
|
||||
// absl::CivilDay c(2015); // 2015-01-01 00:00:00
|
||||
//
|
||||
// absl::CivilSecond ss(2015, 2, 3, 4, 5, 6); // 2015-02-03 04:05:06
|
||||
// absl::CivilMinute mm(ss); // 2015-02-03 04:05:00
|
||||
// absl::CivilHour hh(mm); // 2015-02-03 04:00:00
|
||||
// absl::CivilDay d(hh); // 2015-02-03 00:00:00
|
||||
// absl::CivilMonth m(d); // 2015-02-01 00:00:00
|
||||
// absl::CivilYear y(m); // 2015-01-01 00:00:00
|
||||
//
|
||||
// m = absl::CivilMonth(y); // 2015-01-01 00:00:00
|
||||
// d = absl::CivilDay(m); // 2015-01-01 00:00:00
|
||||
// hh = absl::CivilHour(d); // 2015-01-01 00:00:00
|
||||
// mm = absl::CivilMinute(hh); // 2015-01-01 00:00:00
|
||||
// ss = absl::CivilSecond(mm); // 2015-01-01 00:00:00
|
||||
//
|
||||
// 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.)
|
||||
//
|
||||
// absl::CivilSecond : 2015-11-22 12:34:56
|
||||
// absl::CivilMinute : 2015-11-22 12:34:00
|
||||
// absl::CivilHour : 2015-11-22 12:00:00
|
||||
// absl::CivilDay : 2015-11-22 00:00:00
|
||||
// absl::CivilMonth : 2015-11-01 00:00:00
|
||||
// absl::CivilYear : 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 an absl::CivilDay increments the day
|
||||
// field (normalizing as necessary), and subtracting 7 from an absl::CivilMonth
|
||||
// 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 absl::CivilHour objects
|
||||
// will give an answer in units of civil hours.
|
||||
//
|
||||
// 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., absl::CivilDay -> absl::CivilSecond), the conversion may be
|
||||
// performed implicitly since no information is lost. However, if information
|
||||
// could be discarded (e.g., CivilSecond -> CivilDay), the conversion must
|
||||
// be explicit at the call site.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// void UseDay(absl::CivilDay day);
|
||||
//
|
||||
// absl::CivilSecond cs;
|
||||
// UseDay(cs); // Won't compile because data may be discarded
|
||||
// UseDay(absl::CivilDay(cs)); // OK: explicit conversion
|
||||
//
|
||||
// absl::CivilDay cd;
|
||||
// UseDay(cd); // OK: no conversion needed
|
||||
//
|
||||
// absl::CivilMonth cm;
|
||||
// UseDay(cm); // OK: implicit conversion to absl::CivilDay
|
||||
//
|
||||
// NORMALIZATION
|
||||
//
|
||||
// Normalization takes invalid values and adjusts them to produce valid values.
|
||||
// Within the civil-time library, integer arguments passed to the Civil*
|
||||
// constructors may be out-of-range, in which case they are normalized by
|
||||
// carrying overflow into a field of courser granularity to produce valid
|
||||
// civil-time objects. This normalization enables natural arithmetic on
|
||||
// constructor arguments without worrying about the field's range.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// // Out-of-range; normalized to 2016-11-01
|
||||
// absl::CivilDay d(2016, 10, 32);
|
||||
// // Out-of-range, negative: normalized to 2016-10-30T23
|
||||
// absl::CivilHour h1(2016, 10, 31, -1);
|
||||
// // Normalization is cumulative: normalized to 2016-10-30T23
|
||||
// absl::CivilHour h2(2016, 10, 32, -25);
|
||||
//
|
||||
// Note: If normalization is undesired, you can signal an error by comparing
|
||||
// the constructor arguments to the normalized values returned by the YMDHMS
|
||||
// properties.
|
||||
//
|
||||
// COMPARISON
|
||||
//
|
||||
// Comparison between civil-time objects considers all six YMDHMS fields,
|
||||
// regardless of the type's alignment. Comparison between differently aligned
|
||||
// civil-time types is allowed.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// absl::CivilDay feb_3(2015, 2, 3); // 2015-02-03 00:00:00
|
||||
// absl::CivilDay mar_4(2015, 3, 4); // 2015-03-04 00:00:00
|
||||
// // feb_3 < mar_4
|
||||
// // absl::CivilYear(feb_3) == absl::CivilYear(mar_4)
|
||||
//
|
||||
// absl::CivilSecond feb_3_noon(2015, 2, 3, 12, 0, 0); // 2015-02-03 12:00:00
|
||||
// // feb_3 < feb_3_noon
|
||||
// // feb_3 == absl::CivilDay(feb_3_noon)
|
||||
//
|
||||
// // Iterates all the days of February 2015.
|
||||
// for (absl::CivilDay d(2015, 2, 1); d < absl::CivilMonth(2015, 3); ++d) {
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// 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 operators require arguments with
|
||||
// the same alignment and return the answer in units of the alignment.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::CivilDay a(2015, 2, 3);
|
||||
// ++a; // 2015-02-04 00:00:00
|
||||
// --a; // 2015-02-03 00:00:00
|
||||
// absl::CivilDay b = a + 1; // 2015-02-04 00:00:00
|
||||
// absl::CivilDay c = 1 + b; // 2015-02-05 00:00:00
|
||||
// int n = c - a; // n = 2 (civil days)
|
||||
// int m = c - absl::CivilMonth(c); // Won't compile: different types.
|
||||
//
|
||||
// ACCESSORS
|
||||
//
|
||||
// Each civil-time type has accessors for all six of the civil-time fields:
|
||||
// year, month, day, hour, minute, and second.
|
||||
//
|
||||
// civil_year_t year()
|
||||
// int month()
|
||||
// int day()
|
||||
// int hour()
|
||||
// int minute()
|
||||
// int second()
|
||||
//
|
||||
// Recall that fields inferior to the type's alignment will be set to their
|
||||
// minimum valid value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::CivilDay d(2015, 6, 28);
|
||||
// // d.year() == 2015
|
||||
// // d.month() == 6
|
||||
// // d.day() == 28
|
||||
// // d.hour() == 0
|
||||
// // d.minute() == 0
|
||||
// // d.second() == 0
|
||||
//
|
||||
// CASE STUDY: 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 is the result of adding a month to January 31?"
|
||||
// This is an interesting question because it is unclear what is meant by a
|
||||
// "month", and several different answers are possible, depending on context:
|
||||
//
|
||||
// 1. March 3 (or 2 if a leap year), if "add a month" means to add a month to
|
||||
// the current month, and adjust the date to overflow the extra days into
|
||||
// March. In this case the result of "February 31" would be normalized as
|
||||
// within the civil-time library.
|
||||
// 2. February 28 (or 29 if a leap year), if "add a month" means to add a
|
||||
// month, and adjust the date while holding the resulting month constant.
|
||||
// In this case, the result of "February 31" would be truncated to the last
|
||||
// day in February.
|
||||
// 3. An error. The caller may get some error, an exception, an invalid date
|
||||
// object, or perhaps return `false`. 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.
|
||||
//
|
||||
// The Abseil time library avoids this 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 Abseil 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":
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// const absl::CivilDay d(2015, 1, 31);
|
||||
//
|
||||
// // Answer 1:
|
||||
// // Add 1 to the month field in the constructor, and rely on normalization.
|
||||
// const auto normalized = absl::CivilDay(d.year(), d.month() + 1, d.day());
|
||||
// // 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 = absl::CivilMonth(d) + 1;
|
||||
// const auto last_day_of_next_month = absl::CivilDay(next_month + 1) - 1;
|
||||
// const auto capped = std::min(normalized, last_day_of_next_month);
|
||||
// // capped == 2015-02-28
|
||||
//
|
||||
// // Answer 3:
|
||||
// // Signal an error if the normalized answer is not in next month.
|
||||
// if (absl::CivilMonth(normalized) != next_month) {
|
||||
// // error, month overflow
|
||||
// }
|
||||
//
|
||||
using CivilSecond =
|
||||
time_internal::cctz::detail::civil_time<time_internal::second_tag>;
|
||||
using CivilMinute =
|
||||
time_internal::cctz::detail::civil_time<time_internal::minute_tag>;
|
||||
using CivilHour =
|
||||
time_internal::cctz::detail::civil_time<time_internal::hour_tag>;
|
||||
using CivilDay =
|
||||
time_internal::cctz::detail::civil_time<time_internal::day_tag>;
|
||||
using CivilMonth =
|
||||
time_internal::cctz::detail::civil_time<time_internal::month_tag>;
|
||||
using CivilYear =
|
||||
time_internal::cctz::detail::civil_time<time_internal::year_tag>;
|
||||
|
||||
// civil_year_t
|
||||
//
|
||||
// Type alias of a civil-time year value. This type is guaranteed to (at least)
|
||||
// support any year value supported by `time_t`.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::CivilSecond cs = ...;
|
||||
// absl::civil_year_t y = cs.year();
|
||||
// cs = absl::CivilSecond(y, 1, 1, 0, 0, 0); // CivilSecond(CivilYear(cs))
|
||||
//
|
||||
using civil_year_t = time_internal::cctz::year_t;
|
||||
|
||||
// civil_diff_t
|
||||
//
|
||||
// Type alias of the difference between two civil-time values.
|
||||
// This type is used to indicate arguments that are not
|
||||
// normalized (such as parameters to the civil-time constructors), the results
|
||||
// of civil-time subtraction, or the operand to civil-time addition.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::civil_diff_t n_sec = cs1 - cs2; // cs1 == cs2 + n_sec;
|
||||
//
|
||||
using civil_diff_t = time_internal::cctz::diff_t;
|
||||
|
||||
// Weekday::monday, Weekday::tuesday, Weekday::wednesday, Weekday::thursday,
|
||||
// Weekday::friday, Weekday::saturday, Weekday::sunday
|
||||
//
|
||||
// The Weekday enum class represents the civil-time concept of a "weekday" with
|
||||
// members for all days of the week.
|
||||
//
|
||||
// absl::Weekday wd = absl::Weekday::thursday;
|
||||
//
|
||||
using Weekday = time_internal::cctz::weekday;
|
||||
|
||||
// GetWeekday()
|
||||
//
|
||||
// Returns the absl::Weekday for the given (realigned) civil-time value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::CivilDay a(2015, 8, 13);
|
||||
// absl::Weekday wd = absl::GetWeekday(a); // wd == absl::Weekday::thursday
|
||||
//
|
||||
inline Weekday GetWeekday(CivilSecond cs) {
|
||||
return time_internal::cctz::get_weekday(cs);
|
||||
}
|
||||
|
||||
// NextWeekday()
|
||||
// PrevWeekday()
|
||||
//
|
||||
// Returns the absl::CivilDay that strictly follows or precedes a given
|
||||
// absl::CivilDay, and that falls on the given absl::Weekday.
|
||||
//
|
||||
// Example, given the following month:
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// absl::CivilDay a(2015, 8, 13);
|
||||
// // absl::GetWeekday(a) == absl::Weekday::thursday
|
||||
// absl::CivilDay b = absl::NextWeekday(a, absl::Weekday::thursday);
|
||||
// // b = 2015-08-20
|
||||
// absl::CivilDay c = absl::PrevWeekday(a, absl::Weekday::thursday);
|
||||
// // c = 2015-08-06
|
||||
//
|
||||
// absl::CivilDay d = ...
|
||||
// // Gets the following Thursday if d is not already Thursday
|
||||
// absl::CivilDay thurs1 = absl::NextWeekday(d - 1, absl::Weekday::thursday);
|
||||
// // Gets the previous Thursday if d is not already Thursday
|
||||
// absl::CivilDay thurs2 = absl::PrevWeekday(d + 1, absl::Weekday::thursday);
|
||||
//
|
||||
inline CivilDay NextWeekday(CivilDay cd, Weekday wd) {
|
||||
return CivilDay(time_internal::cctz::next_weekday(cd, wd));
|
||||
}
|
||||
inline CivilDay PrevWeekday(CivilDay cd, Weekday wd) {
|
||||
return CivilDay(time_internal::cctz::prev_weekday(cd, wd));
|
||||
}
|
||||
|
||||
// GetYearDay()
|
||||
//
|
||||
// Returns the day-of-year for the given (realigned) civil-time value.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::CivilDay a(2015, 1, 1);
|
||||
// int yd_jan_1 = absl::GetYearDay(a); // yd_jan_1 = 1
|
||||
// absl::CivilDay b(2015, 12, 31);
|
||||
// int yd_dec_31 = absl::GetYearDay(b); // yd_dec_31 = 365
|
||||
//
|
||||
inline int GetYearDay(CivilSecond cs) {
|
||||
return time_internal::cctz::get_yearday(cs);
|
||||
}
|
||||
|
||||
// FormatCivilTime()
|
||||
//
|
||||
// Formats the given civil-time value into a string value of the following
|
||||
// format:
|
||||
//
|
||||
// Type | Format
|
||||
// ---------------------------------
|
||||
// CivilSecond | YYYY-MM-DDTHH:MM:SS
|
||||
// CivilMinute | YYYY-MM-DDTHH:MM
|
||||
// CivilHour | YYYY-MM-DDTHH
|
||||
// CivilDay | YYYY-MM-DD
|
||||
// CivilMonth | YYYY-MM
|
||||
// CivilYear | YYYY
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::CivilDay d = absl::CivilDay(1969, 7, 20);
|
||||
// std::string day_string = absl::FormatCivilTime(d); // "1969-07-20"
|
||||
//
|
||||
std::string FormatCivilTime(CivilSecond c);
|
||||
std::string FormatCivilTime(CivilMinute c);
|
||||
std::string FormatCivilTime(CivilHour c);
|
||||
std::string FormatCivilTime(CivilDay c);
|
||||
std::string FormatCivilTime(CivilMonth c);
|
||||
std::string FormatCivilTime(CivilYear c);
|
||||
|
||||
// Support for StrFormat(), StrCat(), etc
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, CivilSecond c) {
|
||||
sink.Append(FormatCivilTime(c));
|
||||
}
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, CivilMinute c) {
|
||||
sink.Append(FormatCivilTime(c));
|
||||
}
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, CivilHour c) {
|
||||
sink.Append(FormatCivilTime(c));
|
||||
}
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, CivilDay c) {
|
||||
sink.Append(FormatCivilTime(c));
|
||||
}
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, CivilMonth c) {
|
||||
sink.Append(FormatCivilTime(c));
|
||||
}
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, CivilYear c) {
|
||||
sink.Append(FormatCivilTime(c));
|
||||
}
|
||||
|
||||
// absl::ParseCivilTime()
|
||||
//
|
||||
// Parses a civil-time value from the specified `absl::string_view` into the
|
||||
// passed output parameter. Returns `true` upon successful parsing.
|
||||
//
|
||||
// The expected form of the input string is as follows:
|
||||
//
|
||||
// Type | Format
|
||||
// ---------------------------------
|
||||
// CivilSecond | YYYY-MM-DDTHH:MM:SS
|
||||
// CivilMinute | YYYY-MM-DDTHH:MM
|
||||
// CivilHour | YYYY-MM-DDTHH
|
||||
// CivilDay | YYYY-MM-DD
|
||||
// CivilMonth | YYYY-MM
|
||||
// CivilYear | YYYY
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::CivilDay d;
|
||||
// bool ok = absl::ParseCivilTime("2018-01-02", &d); // OK
|
||||
//
|
||||
// Note that parsing will fail if the string's format does not match the
|
||||
// expected type exactly. `ParseLenientCivilTime()` below is more lenient.
|
||||
//
|
||||
bool ParseCivilTime(absl::string_view s, CivilSecond* c);
|
||||
bool ParseCivilTime(absl::string_view s, CivilMinute* c);
|
||||
bool ParseCivilTime(absl::string_view s, CivilHour* c);
|
||||
bool ParseCivilTime(absl::string_view s, CivilDay* c);
|
||||
bool ParseCivilTime(absl::string_view s, CivilMonth* c);
|
||||
bool ParseCivilTime(absl::string_view s, CivilYear* c);
|
||||
|
||||
// ParseLenientCivilTime()
|
||||
//
|
||||
// Parses any of the formats accepted by `absl::ParseCivilTime()`, but is more
|
||||
// lenient if the format of the string does not exactly match the associated
|
||||
// type.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::CivilDay d;
|
||||
// bool ok = absl::ParseLenientCivilTime("1969-07-20", &d); // OK
|
||||
// ok = absl::ParseLenientCivilTime("1969-07-20T10", &d); // OK: T10 floored
|
||||
// ok = absl::ParseLenientCivilTime("1969-07", &d); // OK: day defaults to 1
|
||||
//
|
||||
bool ParseLenientCivilTime(absl::string_view s, CivilSecond* c);
|
||||
bool ParseLenientCivilTime(absl::string_view s, CivilMinute* c);
|
||||
bool ParseLenientCivilTime(absl::string_view s, CivilHour* c);
|
||||
bool ParseLenientCivilTime(absl::string_view s, CivilDay* c);
|
||||
bool ParseLenientCivilTime(absl::string_view s, CivilMonth* c);
|
||||
bool ParseLenientCivilTime(absl::string_view s, CivilYear* c);
|
||||
|
||||
namespace time_internal { // For functions found via ADL on civil-time tags.
|
||||
|
||||
// Streaming Operators
|
||||
//
|
||||
// Each civil-time type may be sent to an output stream using operator<<().
|
||||
// The result matches the string produced by `FormatCivilTime()`.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::CivilDay d = absl::CivilDay(1969, 7, 20);
|
||||
// std::cout << "Date is: " << d << "\n";
|
||||
//
|
||||
std::ostream& operator<<(std::ostream& os, CivilYear y);
|
||||
std::ostream& operator<<(std::ostream& os, CivilMonth m);
|
||||
std::ostream& operator<<(std::ostream& os, CivilDay d);
|
||||
std::ostream& operator<<(std::ostream& os, CivilHour h);
|
||||
std::ostream& operator<<(std::ostream& os, CivilMinute m);
|
||||
std::ostream& operator<<(std::ostream& os, CivilSecond s);
|
||||
|
||||
// AbslParseFlag()
|
||||
//
|
||||
// Parses the command-line flag string representation `s` into a civil-time
|
||||
// value. Flags must be specified in a format that is valid for
|
||||
// `absl::ParseLenientCivilTime()`.
|
||||
bool AbslParseFlag(absl::string_view s, CivilSecond* c, std::string* error);
|
||||
bool AbslParseFlag(absl::string_view s, CivilMinute* c, std::string* error);
|
||||
bool AbslParseFlag(absl::string_view s, CivilHour* c, std::string* error);
|
||||
bool AbslParseFlag(absl::string_view s, CivilDay* c, std::string* error);
|
||||
bool AbslParseFlag(absl::string_view s, CivilMonth* c, std::string* error);
|
||||
bool AbslParseFlag(absl::string_view s, CivilYear* c, std::string* error);
|
||||
|
||||
// AbslUnparseFlag()
|
||||
//
|
||||
// Unparses a civil-time value into a command-line string representation using
|
||||
// the format specified by `absl::ParseCivilTime()`.
|
||||
std::string AbslUnparseFlag(CivilSecond c);
|
||||
std::string AbslUnparseFlag(CivilMinute c);
|
||||
std::string AbslUnparseFlag(CivilHour c);
|
||||
std::string AbslUnparseFlag(CivilDay c);
|
||||
std::string AbslUnparseFlag(CivilMonth c);
|
||||
std::string AbslUnparseFlag(CivilYear c);
|
||||
|
||||
} // namespace time_internal
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_CIVIL_TIME_H_
|
||||
590
Pods/abseil/absl/time/clock.cc
generated
Normal file
590
Pods/abseil/absl/time/clock.cc
generated
Normal file
@@ -0,0 +1,590 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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 "absl/time/clock.h"
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/optimization.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <limits>
|
||||
|
||||
#include "absl/base/internal/spinlock.h"
|
||||
#include "absl/base/internal/unscaledcycleclock.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/base/port.h"
|
||||
#include "absl/base/thread_annotations.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
Time Now() {
|
||||
// TODO(bww): Get a timespec instead so we don't have to divide.
|
||||
int64_t n = absl::GetCurrentTimeNanos();
|
||||
if (n >= 0) {
|
||||
return time_internal::FromUnixDuration(
|
||||
time_internal::MakeDuration(n / 1000000000, n % 1000000000 * 4));
|
||||
}
|
||||
return time_internal::FromUnixDuration(absl::Nanoseconds(n));
|
||||
}
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
// Decide if we should use the fast GetCurrentTimeNanos() algorithm based on the
|
||||
// cyclecounter, otherwise just get the time directly from the OS on every call.
|
||||
// By default, the fast algorithm based on the cyclecount is disabled because in
|
||||
// certain situations, for example, if the OS enters a "sleep" mode, it may
|
||||
// produce incorrect values immediately upon waking.
|
||||
// This can be chosen at compile-time via
|
||||
// -DABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS=[0|1]
|
||||
#ifndef ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
|
||||
#define ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS 0
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(_WIN32)
|
||||
#include "absl/time/internal/get_current_time_chrono.inc"
|
||||
#else
|
||||
#include "absl/time/internal/get_current_time_posix.inc"
|
||||
#endif
|
||||
|
||||
// Allows override by test.
|
||||
#ifndef GET_CURRENT_TIME_NANOS_FROM_SYSTEM
|
||||
#define GET_CURRENT_TIME_NANOS_FROM_SYSTEM() \
|
||||
::absl::time_internal::GetCurrentTimeNanosFromSystem()
|
||||
#endif
|
||||
|
||||
#if !ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
int64_t GetCurrentTimeNanos() { return GET_CURRENT_TIME_NANOS_FROM_SYSTEM(); }
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
#else // Use the cyclecounter-based implementation below.
|
||||
|
||||
// Allows override by test.
|
||||
#ifndef GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW
|
||||
#define GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW() \
|
||||
::absl::time_internal::UnscaledCycleClockWrapperForGetCurrentTime::Now()
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
// This is a friend wrapper around UnscaledCycleClock::Now()
|
||||
// (needed to access UnscaledCycleClock).
|
||||
class UnscaledCycleClockWrapperForGetCurrentTime {
|
||||
public:
|
||||
static int64_t Now() { return base_internal::UnscaledCycleClock::Now(); }
|
||||
};
|
||||
} // namespace time_internal
|
||||
|
||||
// uint64_t is used in this module to provide an extra bit in multiplications
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// An implementation of reader-write locks that use no atomic ops in the read
|
||||
// case. This is a generalization of Lamport's method for reading a multiword
|
||||
// clock. Increment a word on each write acquisition, using the low-order bit
|
||||
// as a spinlock; the word is the high word of the "clock". Readers read the
|
||||
// high word, then all other data, then the high word again, and repeat the
|
||||
// read if the reads of the high words yields different answers, or an odd
|
||||
// value (either case suggests possible interference from a writer).
|
||||
// Here we use a spinlock to ensure only one writer at a time, rather than
|
||||
// spinning on the bottom bit of the word to benefit from SpinLock
|
||||
// spin-delay tuning.
|
||||
|
||||
// Acquire seqlock (*seq) and return the value to be written to unlock.
|
||||
static inline uint64_t SeqAcquire(std::atomic<uint64_t> *seq) {
|
||||
uint64_t x = seq->fetch_add(1, std::memory_order_relaxed);
|
||||
|
||||
// We put a release fence between update to *seq and writes to shared data.
|
||||
// Thus all stores to shared data are effectively release operations and
|
||||
// update to *seq above cannot be re-ordered past any of them. Note that
|
||||
// this barrier is not for the fetch_add above. A release barrier for the
|
||||
// fetch_add would be before it, not after.
|
||||
std::atomic_thread_fence(std::memory_order_release);
|
||||
|
||||
return x + 2; // original word plus 2
|
||||
}
|
||||
|
||||
// Release seqlock (*seq) by writing x to it---a value previously returned by
|
||||
// SeqAcquire.
|
||||
static inline void SeqRelease(std::atomic<uint64_t> *seq, uint64_t x) {
|
||||
// The unlock store to *seq must have release ordering so that all
|
||||
// updates to shared data must finish before this store.
|
||||
seq->store(x, std::memory_order_release); // release lock for readers
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
// "nsscaled" is unit of time equal to a (2**kScale)th of a nanosecond.
|
||||
enum { kScale = 30 };
|
||||
|
||||
// The minimum interval between samples of the time base.
|
||||
// We pick enough time to amortize the cost of the sample,
|
||||
// to get a reasonably accurate cycle counter rate reading,
|
||||
// and not so much that calculations will overflow 64-bits.
|
||||
static const uint64_t kMinNSBetweenSamples = 2000 << 20;
|
||||
|
||||
// We require that kMinNSBetweenSamples shifted by kScale
|
||||
// have at least a bit left over for 64-bit calculations.
|
||||
static_assert(((kMinNSBetweenSamples << (kScale + 1)) >> (kScale + 1)) ==
|
||||
kMinNSBetweenSamples,
|
||||
"cannot represent kMaxBetweenSamplesNSScaled");
|
||||
|
||||
// data from a sample of the kernel's time value
|
||||
struct TimeSampleAtomic {
|
||||
std::atomic<uint64_t> raw_ns{0}; // raw kernel time
|
||||
std::atomic<uint64_t> base_ns{0}; // our estimate of time
|
||||
std::atomic<uint64_t> base_cycles{0}; // cycle counter reading
|
||||
std::atomic<uint64_t> nsscaled_per_cycle{0}; // cycle period
|
||||
// cycles before we'll sample again (a scaled reciprocal of the period,
|
||||
// to avoid a division on the fast path).
|
||||
std::atomic<uint64_t> min_cycles_per_sample{0};
|
||||
};
|
||||
// Same again, but with non-atomic types
|
||||
struct TimeSample {
|
||||
uint64_t raw_ns = 0; // raw kernel time
|
||||
uint64_t base_ns = 0; // our estimate of time
|
||||
uint64_t base_cycles = 0; // cycle counter reading
|
||||
uint64_t nsscaled_per_cycle = 0; // cycle period
|
||||
uint64_t min_cycles_per_sample = 0; // approx cycles before next sample
|
||||
};
|
||||
|
||||
struct ABSL_CACHELINE_ALIGNED TimeState {
|
||||
std::atomic<uint64_t> seq{0};
|
||||
TimeSampleAtomic last_sample; // the last sample; under seq
|
||||
|
||||
// The following counters are used only by the test code.
|
||||
int64_t stats_initializations{0};
|
||||
int64_t stats_reinitializations{0};
|
||||
int64_t stats_calibrations{0};
|
||||
int64_t stats_slow_paths{0};
|
||||
int64_t stats_fast_slow_paths{0};
|
||||
|
||||
uint64_t last_now_cycles ABSL_GUARDED_BY(lock){0};
|
||||
|
||||
// Used by GetCurrentTimeNanosFromKernel().
|
||||
// We try to read clock values at about the same time as the kernel clock.
|
||||
// This value gets adjusted up or down as estimate of how long that should
|
||||
// take, so we can reject attempts that take unusually long.
|
||||
std::atomic<uint64_t> approx_syscall_time_in_cycles{10 * 1000};
|
||||
// Number of times in a row we've seen a kernel time call take substantially
|
||||
// less than approx_syscall_time_in_cycles.
|
||||
std::atomic<uint32_t> kernel_time_seen_smaller{0};
|
||||
|
||||
// A reader-writer lock protecting the static locations below.
|
||||
// See SeqAcquire() and SeqRelease() above.
|
||||
absl::base_internal::SpinLock lock{absl::kConstInit,
|
||||
base_internal::SCHEDULE_KERNEL_ONLY};
|
||||
};
|
||||
ABSL_CONST_INIT static TimeState time_state;
|
||||
|
||||
// Return the time in ns as told by the kernel interface. Place in *cycleclock
|
||||
// the value of the cycleclock at about the time of the syscall.
|
||||
// This call represents the time base that this module synchronizes to.
|
||||
// Ensures that *cycleclock does not step back by up to (1 << 16) from
|
||||
// last_cycleclock, to discard small backward counter steps. (Larger steps are
|
||||
// assumed to be complete resyncs, which shouldn't happen. If they do, a full
|
||||
// reinitialization of the outer algorithm should occur.)
|
||||
static int64_t GetCurrentTimeNanosFromKernel(uint64_t last_cycleclock,
|
||||
uint64_t *cycleclock)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(time_state.lock) {
|
||||
uint64_t local_approx_syscall_time_in_cycles = // local copy
|
||||
time_state.approx_syscall_time_in_cycles.load(std::memory_order_relaxed);
|
||||
|
||||
int64_t current_time_nanos_from_system;
|
||||
uint64_t before_cycles;
|
||||
uint64_t after_cycles;
|
||||
uint64_t elapsed_cycles;
|
||||
int loops = 0;
|
||||
do {
|
||||
before_cycles =
|
||||
static_cast<uint64_t>(GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW());
|
||||
current_time_nanos_from_system = GET_CURRENT_TIME_NANOS_FROM_SYSTEM();
|
||||
after_cycles =
|
||||
static_cast<uint64_t>(GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW());
|
||||
// elapsed_cycles is unsigned, so is large on overflow
|
||||
elapsed_cycles = after_cycles - before_cycles;
|
||||
if (elapsed_cycles >= local_approx_syscall_time_in_cycles &&
|
||||
++loops == 20) { // clock changed frequencies? Back off.
|
||||
loops = 0;
|
||||
if (local_approx_syscall_time_in_cycles < 1000 * 1000) {
|
||||
local_approx_syscall_time_in_cycles =
|
||||
(local_approx_syscall_time_in_cycles + 1) << 1;
|
||||
}
|
||||
time_state.approx_syscall_time_in_cycles.store(
|
||||
local_approx_syscall_time_in_cycles, std::memory_order_relaxed);
|
||||
}
|
||||
} while (elapsed_cycles >= local_approx_syscall_time_in_cycles ||
|
||||
last_cycleclock - after_cycles < (static_cast<uint64_t>(1) << 16));
|
||||
|
||||
// Adjust approx_syscall_time_in_cycles to be within a factor of 2
|
||||
// of the typical time to execute one iteration of the loop above.
|
||||
if ((local_approx_syscall_time_in_cycles >> 1) < elapsed_cycles) {
|
||||
// measured time is no smaller than half current approximation
|
||||
time_state.kernel_time_seen_smaller.store(0, std::memory_order_relaxed);
|
||||
} else if (time_state.kernel_time_seen_smaller.fetch_add(
|
||||
1, std::memory_order_relaxed) >= 3) {
|
||||
// smaller delays several times in a row; reduce approximation by 12.5%
|
||||
const uint64_t new_approximation =
|
||||
local_approx_syscall_time_in_cycles -
|
||||
(local_approx_syscall_time_in_cycles >> 3);
|
||||
time_state.approx_syscall_time_in_cycles.store(new_approximation,
|
||||
std::memory_order_relaxed);
|
||||
time_state.kernel_time_seen_smaller.store(0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
*cycleclock = after_cycles;
|
||||
return current_time_nanos_from_system;
|
||||
}
|
||||
|
||||
static int64_t GetCurrentTimeNanosSlowPath() ABSL_ATTRIBUTE_COLD;
|
||||
|
||||
// Read the contents of *atomic into *sample.
|
||||
// Each field is read atomically, but to maintain atomicity between fields,
|
||||
// the access must be done under a lock.
|
||||
static void ReadTimeSampleAtomic(const struct TimeSampleAtomic *atomic,
|
||||
struct TimeSample *sample) {
|
||||
sample->base_ns = atomic->base_ns.load(std::memory_order_relaxed);
|
||||
sample->base_cycles = atomic->base_cycles.load(std::memory_order_relaxed);
|
||||
sample->nsscaled_per_cycle =
|
||||
atomic->nsscaled_per_cycle.load(std::memory_order_relaxed);
|
||||
sample->min_cycles_per_sample =
|
||||
atomic->min_cycles_per_sample.load(std::memory_order_relaxed);
|
||||
sample->raw_ns = atomic->raw_ns.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
// Public routine.
|
||||
// Algorithm: We wish to compute real time from a cycle counter. In normal
|
||||
// operation, we construct a piecewise linear approximation to the kernel time
|
||||
// source, using the cycle counter value. The start of each line segment is at
|
||||
// the same point as the end of the last, but may have a different slope (that
|
||||
// is, a different idea of the cycle counter frequency). Every couple of
|
||||
// seconds, the kernel time source is sampled and compared with the current
|
||||
// approximation. A new slope is chosen that, if followed for another couple
|
||||
// of seconds, will correct the error at the current position. The information
|
||||
// for a sample is in the "last_sample" struct. The linear approximation is
|
||||
// estimated_time = last_sample.base_ns +
|
||||
// last_sample.ns_per_cycle * (counter_reading - last_sample.base_cycles)
|
||||
// (ns_per_cycle is actually stored in different units and scaled, to avoid
|
||||
// overflow). The base_ns of the next linear approximation is the
|
||||
// estimated_time using the last approximation; the base_cycles is the cycle
|
||||
// counter value at that time; the ns_per_cycle is the number of ns per cycle
|
||||
// measured since the last sample, but adjusted so that most of the difference
|
||||
// between the estimated_time and the kernel time will be corrected by the
|
||||
// estimated time to the next sample. In normal operation, this algorithm
|
||||
// relies on:
|
||||
// - the cycle counter and kernel time rates not changing a lot in a few
|
||||
// seconds.
|
||||
// - the client calling into the code often compared to a couple of seconds, so
|
||||
// the time to the next correction can be estimated.
|
||||
// Any time ns_per_cycle is not known, a major error is detected, or the
|
||||
// assumption about frequent calls is violated, the implementation returns the
|
||||
// kernel time. It records sufficient data that a linear approximation can
|
||||
// resume a little later.
|
||||
|
||||
int64_t GetCurrentTimeNanos() {
|
||||
// read the data from the "last_sample" struct (but don't need raw_ns yet)
|
||||
// The reads of "seq" and test of the values emulate a reader lock.
|
||||
uint64_t base_ns;
|
||||
uint64_t base_cycles;
|
||||
uint64_t nsscaled_per_cycle;
|
||||
uint64_t min_cycles_per_sample;
|
||||
uint64_t seq_read0;
|
||||
uint64_t seq_read1;
|
||||
|
||||
// If we have enough information to interpolate, the value returned will be
|
||||
// derived from this cycleclock-derived time estimate. On some platforms
|
||||
// (POWER) the function to retrieve this value has enough complexity to
|
||||
// contribute to register pressure - reading it early before initializing
|
||||
// the other pieces of the calculation minimizes spill/restore instructions,
|
||||
// minimizing icache cost.
|
||||
uint64_t now_cycles =
|
||||
static_cast<uint64_t>(GET_CURRENT_TIME_NANOS_CYCLECLOCK_NOW());
|
||||
|
||||
// Acquire pairs with the barrier in SeqRelease - if this load sees that
|
||||
// store, the shared-data reads necessarily see that SeqRelease's updates
|
||||
// to the same shared data.
|
||||
seq_read0 = time_state.seq.load(std::memory_order_acquire);
|
||||
|
||||
base_ns = time_state.last_sample.base_ns.load(std::memory_order_relaxed);
|
||||
base_cycles =
|
||||
time_state.last_sample.base_cycles.load(std::memory_order_relaxed);
|
||||
nsscaled_per_cycle =
|
||||
time_state.last_sample.nsscaled_per_cycle.load(std::memory_order_relaxed);
|
||||
min_cycles_per_sample = time_state.last_sample.min_cycles_per_sample.load(
|
||||
std::memory_order_relaxed);
|
||||
|
||||
// This acquire fence pairs with the release fence in SeqAcquire. Since it
|
||||
// is sequenced between reads of shared data and seq_read1, the reads of
|
||||
// shared data are effectively acquiring.
|
||||
std::atomic_thread_fence(std::memory_order_acquire);
|
||||
|
||||
// The shared-data reads are effectively acquire ordered, and the
|
||||
// shared-data writes are effectively release ordered. Therefore if our
|
||||
// shared-data reads see any of a particular update's shared-data writes,
|
||||
// seq_read1 is guaranteed to see that update's SeqAcquire.
|
||||
seq_read1 = time_state.seq.load(std::memory_order_relaxed);
|
||||
|
||||
// Fast path. Return if min_cycles_per_sample has not yet elapsed since the
|
||||
// last sample, and we read a consistent sample. The fast path activates
|
||||
// only when min_cycles_per_sample is non-zero, which happens when we get an
|
||||
// estimate for the cycle time. The predicate will fail if now_cycles <
|
||||
// base_cycles, or if some other thread is in the slow path.
|
||||
//
|
||||
// Since we now read now_cycles before base_ns, it is possible for now_cycles
|
||||
// to be less than base_cycles (if we were interrupted between those loads and
|
||||
// last_sample was updated). This is harmless, because delta_cycles will wrap
|
||||
// and report a time much much bigger than min_cycles_per_sample. In that case
|
||||
// we will take the slow path.
|
||||
uint64_t delta_cycles;
|
||||
if (seq_read0 == seq_read1 && (seq_read0 & 1) == 0 &&
|
||||
(delta_cycles = now_cycles - base_cycles) < min_cycles_per_sample) {
|
||||
return static_cast<int64_t>(
|
||||
base_ns + ((delta_cycles * nsscaled_per_cycle) >> kScale));
|
||||
}
|
||||
return GetCurrentTimeNanosSlowPath();
|
||||
}
|
||||
|
||||
// Return (a << kScale)/b.
|
||||
// Zero is returned if b==0. Scaling is performed internally to
|
||||
// preserve precision without overflow.
|
||||
static uint64_t SafeDivideAndScale(uint64_t a, uint64_t b) {
|
||||
// Find maximum safe_shift so that
|
||||
// 0 <= safe_shift <= kScale and (a << safe_shift) does not overflow.
|
||||
int safe_shift = kScale;
|
||||
while (((a << safe_shift) >> safe_shift) != a) {
|
||||
safe_shift--;
|
||||
}
|
||||
uint64_t scaled_b = b >> (kScale - safe_shift);
|
||||
uint64_t quotient = 0;
|
||||
if (scaled_b != 0) {
|
||||
quotient = (a << safe_shift) / scaled_b;
|
||||
}
|
||||
return quotient;
|
||||
}
|
||||
|
||||
static uint64_t UpdateLastSample(
|
||||
uint64_t now_cycles, uint64_t now_ns, uint64_t delta_cycles,
|
||||
const struct TimeSample *sample) ABSL_ATTRIBUTE_COLD;
|
||||
|
||||
// The slow path of GetCurrentTimeNanos(). This is taken while gathering
|
||||
// initial samples, when enough time has elapsed since the last sample, and if
|
||||
// any other thread is writing to last_sample.
|
||||
//
|
||||
// Manually mark this 'noinline' to minimize stack frame size of the fast
|
||||
// path. Without this, sometimes a compiler may inline this big block of code
|
||||
// into the fast path. That causes lots of register spills and reloads that
|
||||
// are unnecessary unless the slow path is taken.
|
||||
//
|
||||
// TODO(absl-team): Remove this attribute when our compiler is smart enough
|
||||
// to do the right thing.
|
||||
ABSL_ATTRIBUTE_NOINLINE
|
||||
static int64_t GetCurrentTimeNanosSlowPath()
|
||||
ABSL_LOCKS_EXCLUDED(time_state.lock) {
|
||||
// Serialize access to slow-path. Fast-path readers are not blocked yet, and
|
||||
// code below must not modify last_sample until the seqlock is acquired.
|
||||
time_state.lock.Lock();
|
||||
|
||||
// Sample the kernel time base. This is the definition of
|
||||
// "now" if we take the slow path.
|
||||
uint64_t now_cycles;
|
||||
uint64_t now_ns = static_cast<uint64_t>(
|
||||
GetCurrentTimeNanosFromKernel(time_state.last_now_cycles, &now_cycles));
|
||||
time_state.last_now_cycles = now_cycles;
|
||||
|
||||
uint64_t estimated_base_ns;
|
||||
|
||||
// ----------
|
||||
// Read the "last_sample" values again; this time holding the write lock.
|
||||
struct TimeSample sample;
|
||||
ReadTimeSampleAtomic(&time_state.last_sample, &sample);
|
||||
|
||||
// ----------
|
||||
// Try running the fast path again; another thread may have updated the
|
||||
// sample between our run of the fast path and the sample we just read.
|
||||
uint64_t delta_cycles = now_cycles - sample.base_cycles;
|
||||
if (delta_cycles < sample.min_cycles_per_sample) {
|
||||
// Another thread updated the sample. This path does not take the seqlock
|
||||
// so that blocked readers can make progress without blocking new readers.
|
||||
estimated_base_ns = sample.base_ns +
|
||||
((delta_cycles * sample.nsscaled_per_cycle) >> kScale);
|
||||
time_state.stats_fast_slow_paths++;
|
||||
} else {
|
||||
estimated_base_ns =
|
||||
UpdateLastSample(now_cycles, now_ns, delta_cycles, &sample);
|
||||
}
|
||||
|
||||
time_state.lock.Unlock();
|
||||
|
||||
return static_cast<int64_t>(estimated_base_ns);
|
||||
}
|
||||
|
||||
// Main part of the algorithm. Locks out readers, updates the approximation
|
||||
// using the new sample from the kernel, and stores the result in last_sample
|
||||
// for readers. Returns the new estimated time.
|
||||
static uint64_t UpdateLastSample(uint64_t now_cycles, uint64_t now_ns,
|
||||
uint64_t delta_cycles,
|
||||
const struct TimeSample *sample)
|
||||
ABSL_EXCLUSIVE_LOCKS_REQUIRED(time_state.lock) {
|
||||
uint64_t estimated_base_ns = now_ns;
|
||||
uint64_t lock_value =
|
||||
SeqAcquire(&time_state.seq); // acquire seqlock to block readers
|
||||
|
||||
// The 5s in the next if-statement limits the time for which we will trust
|
||||
// the cycle counter and our last sample to give a reasonable result.
|
||||
// Errors in the rate of the source clock can be multiplied by the ratio
|
||||
// between this limit and kMinNSBetweenSamples.
|
||||
if (sample->raw_ns == 0 || // no recent sample, or clock went backwards
|
||||
sample->raw_ns + static_cast<uint64_t>(5) * 1000 * 1000 * 1000 < now_ns ||
|
||||
now_ns < sample->raw_ns || now_cycles < sample->base_cycles) {
|
||||
// record this sample, and forget any previously known slope.
|
||||
time_state.last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
|
||||
time_state.last_sample.base_ns.store(estimated_base_ns,
|
||||
std::memory_order_relaxed);
|
||||
time_state.last_sample.base_cycles.store(now_cycles,
|
||||
std::memory_order_relaxed);
|
||||
time_state.last_sample.nsscaled_per_cycle.store(0,
|
||||
std::memory_order_relaxed);
|
||||
time_state.last_sample.min_cycles_per_sample.store(
|
||||
0, std::memory_order_relaxed);
|
||||
time_state.stats_initializations++;
|
||||
} else if (sample->raw_ns + 500 * 1000 * 1000 < now_ns &&
|
||||
sample->base_cycles + 50 < now_cycles) {
|
||||
// Enough time has passed to compute the cycle time.
|
||||
if (sample->nsscaled_per_cycle != 0) { // Have a cycle time estimate.
|
||||
// Compute time from counter reading, but avoiding overflow
|
||||
// delta_cycles may be larger than on the fast path.
|
||||
uint64_t estimated_scaled_ns;
|
||||
int s = -1;
|
||||
do {
|
||||
s++;
|
||||
estimated_scaled_ns = (delta_cycles >> s) * sample->nsscaled_per_cycle;
|
||||
} while (estimated_scaled_ns / sample->nsscaled_per_cycle !=
|
||||
(delta_cycles >> s));
|
||||
estimated_base_ns = sample->base_ns +
|
||||
(estimated_scaled_ns >> (kScale - s));
|
||||
}
|
||||
|
||||
// Compute the assumed cycle time kMinNSBetweenSamples ns into the future
|
||||
// assuming the cycle counter rate stays the same as the last interval.
|
||||
uint64_t ns = now_ns - sample->raw_ns;
|
||||
uint64_t measured_nsscaled_per_cycle = SafeDivideAndScale(ns, delta_cycles);
|
||||
|
||||
uint64_t assumed_next_sample_delta_cycles =
|
||||
SafeDivideAndScale(kMinNSBetweenSamples, measured_nsscaled_per_cycle);
|
||||
|
||||
// Estimate low by this much.
|
||||
int64_t diff_ns = static_cast<int64_t>(now_ns - estimated_base_ns);
|
||||
|
||||
// We want to set nsscaled_per_cycle so that our estimate of the ns time
|
||||
// at the assumed cycle time is the assumed ns time.
|
||||
// That is, we want to set nsscaled_per_cycle so:
|
||||
// kMinNSBetweenSamples + diff_ns ==
|
||||
// (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale
|
||||
// But we wish to damp oscillations, so instead correct only most
|
||||
// of our current error, by solving:
|
||||
// kMinNSBetweenSamples + diff_ns - (diff_ns / 16) ==
|
||||
// (assumed_next_sample_delta_cycles * nsscaled_per_cycle) >> kScale
|
||||
ns = static_cast<uint64_t>(static_cast<int64_t>(kMinNSBetweenSamples) +
|
||||
diff_ns - (diff_ns / 16));
|
||||
uint64_t new_nsscaled_per_cycle =
|
||||
SafeDivideAndScale(ns, assumed_next_sample_delta_cycles);
|
||||
if (new_nsscaled_per_cycle != 0 &&
|
||||
diff_ns < 100 * 1000 * 1000 && -diff_ns < 100 * 1000 * 1000) {
|
||||
// record the cycle time measurement
|
||||
time_state.last_sample.nsscaled_per_cycle.store(
|
||||
new_nsscaled_per_cycle, std::memory_order_relaxed);
|
||||
uint64_t new_min_cycles_per_sample =
|
||||
SafeDivideAndScale(kMinNSBetweenSamples, new_nsscaled_per_cycle);
|
||||
time_state.last_sample.min_cycles_per_sample.store(
|
||||
new_min_cycles_per_sample, std::memory_order_relaxed);
|
||||
time_state.stats_calibrations++;
|
||||
} else { // something went wrong; forget the slope
|
||||
time_state.last_sample.nsscaled_per_cycle.store(
|
||||
0, std::memory_order_relaxed);
|
||||
time_state.last_sample.min_cycles_per_sample.store(
|
||||
0, std::memory_order_relaxed);
|
||||
estimated_base_ns = now_ns;
|
||||
time_state.stats_reinitializations++;
|
||||
}
|
||||
time_state.last_sample.raw_ns.store(now_ns, std::memory_order_relaxed);
|
||||
time_state.last_sample.base_ns.store(estimated_base_ns,
|
||||
std::memory_order_relaxed);
|
||||
time_state.last_sample.base_cycles.store(now_cycles,
|
||||
std::memory_order_relaxed);
|
||||
} else {
|
||||
// have a sample, but no slope; waiting for enough time for a calibration
|
||||
time_state.stats_slow_paths++;
|
||||
}
|
||||
|
||||
SeqRelease(&time_state.seq, lock_value); // release the readers
|
||||
|
||||
return estimated_base_ns;
|
||||
}
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
#endif // ABSL_USE_CYCLECLOCK_FOR_GET_CURRENT_TIME_NANOS
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace {
|
||||
|
||||
// Returns the maximum duration that SleepOnce() can sleep for.
|
||||
constexpr absl::Duration MaxSleep() {
|
||||
#ifdef _WIN32
|
||||
// Windows Sleep() takes unsigned long argument in milliseconds.
|
||||
return absl::Milliseconds(
|
||||
std::numeric_limits<unsigned long>::max()); // NOLINT(runtime/int)
|
||||
#else
|
||||
return absl::Seconds(std::numeric_limits<time_t>::max());
|
||||
#endif
|
||||
}
|
||||
|
||||
// Sleeps for the given duration.
|
||||
// REQUIRES: to_sleep <= MaxSleep().
|
||||
void SleepOnce(absl::Duration to_sleep) {
|
||||
#ifdef _WIN32
|
||||
Sleep(static_cast<DWORD>(to_sleep / absl::Milliseconds(1)));
|
||||
#else
|
||||
struct timespec sleep_time = absl::ToTimespec(to_sleep);
|
||||
while (nanosleep(&sleep_time, &sleep_time) != 0 && errno == EINTR) {
|
||||
// Ignore signals and wait for the full interval to elapse.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
extern "C" {
|
||||
|
||||
ABSL_ATTRIBUTE_WEAK void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(
|
||||
absl::Duration duration) {
|
||||
while (duration > absl::ZeroDuration()) {
|
||||
absl::Duration to_sleep = std::min(duration, absl::MaxSleep());
|
||||
absl::SleepOnce(to_sleep);
|
||||
duration -= to_sleep;
|
||||
}
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
78
Pods/abseil/absl/time/clock.h
generated
Normal file
78
Pods/abseil/absl/time/clock.h
generated
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: clock.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file contains utility functions for working with the system-wide
|
||||
// realtime clock. For descriptions of the main time abstractions used within
|
||||
// this header file, consult the time.h header file.
|
||||
#ifndef ABSL_TIME_CLOCK_H_
|
||||
#define ABSL_TIME_CLOCK_H_
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
// Now()
|
||||
//
|
||||
// Returns the current time, expressed as an `absl::Time` absolute time value.
|
||||
absl::Time Now();
|
||||
|
||||
// GetCurrentTimeNanos()
|
||||
//
|
||||
// Returns the current time, expressed as a count of nanoseconds since the Unix
|
||||
// Epoch (https://en.wikipedia.org/wiki/Unix_time). Prefer `absl::Now()` instead
|
||||
// for all but the most performance-sensitive cases (i.e. when you are calling
|
||||
// this function hundreds of thousands of times per second).
|
||||
int64_t GetCurrentTimeNanos();
|
||||
|
||||
// SleepFor()
|
||||
//
|
||||
// Sleeps for the specified duration, expressed as an `absl::Duration`.
|
||||
//
|
||||
// Notes:
|
||||
// * Signal interruptions will not reduce the sleep duration.
|
||||
// * Returns immediately when passed a nonpositive duration.
|
||||
void SleepFor(absl::Duration duration);
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation Details
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// In some build configurations we pass --detect-odr-violations to the
|
||||
// gold linker. This causes it to flag weak symbol overrides as ODR
|
||||
// violations. Because ODR only applies to C++ and not C,
|
||||
// --detect-odr-violations ignores symbols not mangled with C++ names.
|
||||
// By changing our extension points to be extern "C", we dodge this
|
||||
// check.
|
||||
extern "C" {
|
||||
ABSL_DLL void ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(
|
||||
absl::Duration duration);
|
||||
} // extern "C"
|
||||
|
||||
inline void absl::SleepFor(absl::Duration duration) {
|
||||
ABSL_INTERNAL_C_SYMBOL(AbslInternalSleepFor)(duration);
|
||||
}
|
||||
|
||||
#endif // ABSL_TIME_CLOCK_H_
|
||||
953
Pods/abseil/absl/time/duration.cc
generated
Normal file
953
Pods/abseil/absl/time/duration.cc
generated
Normal file
@@ -0,0 +1,953 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The implementation of the absl::Duration class, which is declared in
|
||||
// //absl/time.h. This class behaves like a numeric type; it has no public
|
||||
// methods and is used only through the operators defined here.
|
||||
//
|
||||
// Implementation notes:
|
||||
//
|
||||
// An absl::Duration is represented as
|
||||
//
|
||||
// rep_hi_ : (int64_t) Whole seconds
|
||||
// rep_lo_ : (uint32_t) Fractions of a second
|
||||
//
|
||||
// The seconds value (rep_hi_) may be positive or negative as appropriate.
|
||||
// The fractional seconds (rep_lo_) is always a positive offset from rep_hi_.
|
||||
// The API for Duration guarantees at least nanosecond resolution, which
|
||||
// means rep_lo_ could have a max value of 1B - 1 if it stored nanoseconds.
|
||||
// However, to utilize more of the available 32 bits of space in rep_lo_,
|
||||
// we instead store quarters of a nanosecond in rep_lo_ resulting in a max
|
||||
// value of 4B - 1. This allows us to correctly handle calculations like
|
||||
// 0.5 nanos + 0.5 nanos = 1 nano. The following example shows the actual
|
||||
// Duration rep using quarters of a nanosecond.
|
||||
//
|
||||
// 2.5 sec = {rep_hi_=2, rep_lo_=2000000000} // lo = 4 * 500000000
|
||||
// -2.5 sec = {rep_hi_=-3, rep_lo_=2000000000}
|
||||
//
|
||||
// Infinite durations are represented as Durations with the rep_lo_ field set
|
||||
// to all 1s.
|
||||
//
|
||||
// +InfiniteDuration:
|
||||
// rep_hi_ : kint64max
|
||||
// rep_lo_ : ~0U
|
||||
//
|
||||
// -InfiniteDuration:
|
||||
// rep_hi_ : kint64min
|
||||
// rep_lo_ : ~0U
|
||||
//
|
||||
// Arithmetic overflows/underflows to +/- infinity and saturates.
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <winsock2.h> // for timeval
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <chrono> // NOLINT(build/c++11)
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/attributes.h"
|
||||
#include "absl/base/casts.h"
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/numeric/int128.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/strings/strip.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
namespace {
|
||||
|
||||
using time_internal::kTicksPerNanosecond;
|
||||
using time_internal::kTicksPerSecond;
|
||||
|
||||
constexpr int64_t kint64max = std::numeric_limits<int64_t>::max();
|
||||
constexpr int64_t kint64min = std::numeric_limits<int64_t>::min();
|
||||
|
||||
// Can't use std::isinfinite() because it doesn't exist on windows.
|
||||
inline bool IsFinite(double d) {
|
||||
if (std::isnan(d)) return false;
|
||||
return d != std::numeric_limits<double>::infinity() &&
|
||||
d != -std::numeric_limits<double>::infinity();
|
||||
}
|
||||
|
||||
inline bool IsValidDivisor(double d) {
|
||||
if (std::isnan(d)) return false;
|
||||
return d != 0.0;
|
||||
}
|
||||
|
||||
// *sec may be positive or negative. *ticks must be in the range
|
||||
// -kTicksPerSecond < *ticks < kTicksPerSecond. If *ticks is negative it
|
||||
// will be normalized to a positive value by adjusting *sec accordingly.
|
||||
inline void NormalizeTicks(int64_t* sec, int64_t* ticks) {
|
||||
if (*ticks < 0) {
|
||||
--*sec;
|
||||
*ticks += kTicksPerSecond;
|
||||
}
|
||||
}
|
||||
|
||||
// Makes a uint128 from the absolute value of the given scalar.
|
||||
inline uint128 MakeU128(int64_t a) {
|
||||
uint128 u128 = 0;
|
||||
if (a < 0) {
|
||||
++u128;
|
||||
++a; // Makes it safe to negate 'a'
|
||||
a = -a;
|
||||
}
|
||||
u128 += static_cast<uint64_t>(a);
|
||||
return u128;
|
||||
}
|
||||
|
||||
// Makes a uint128 count of ticks out of the absolute value of the Duration.
|
||||
inline uint128 MakeU128Ticks(Duration d) {
|
||||
int64_t rep_hi = time_internal::GetRepHi(d);
|
||||
uint32_t rep_lo = time_internal::GetRepLo(d);
|
||||
if (rep_hi < 0) {
|
||||
++rep_hi;
|
||||
rep_hi = -rep_hi;
|
||||
rep_lo = kTicksPerSecond - rep_lo;
|
||||
}
|
||||
uint128 u128 = static_cast<uint64_t>(rep_hi);
|
||||
u128 *= static_cast<uint64_t>(kTicksPerSecond);
|
||||
u128 += rep_lo;
|
||||
return u128;
|
||||
}
|
||||
|
||||
// Breaks a uint128 of ticks into a Duration.
|
||||
inline Duration MakeDurationFromU128(uint128 u128, bool is_neg) {
|
||||
int64_t rep_hi;
|
||||
uint32_t rep_lo;
|
||||
const uint64_t h64 = Uint128High64(u128);
|
||||
const uint64_t l64 = Uint128Low64(u128);
|
||||
if (h64 == 0) { // fastpath
|
||||
const uint64_t hi = l64 / kTicksPerSecond;
|
||||
rep_hi = static_cast<int64_t>(hi);
|
||||
rep_lo = static_cast<uint32_t>(l64 - hi * kTicksPerSecond);
|
||||
} else {
|
||||
// kMaxRepHi64 is the high 64 bits of (2^63 * kTicksPerSecond).
|
||||
// Any positive tick count whose high 64 bits are >= kMaxRepHi64
|
||||
// is not representable as a Duration. A negative tick count can
|
||||
// have its high 64 bits == kMaxRepHi64 but only when the low 64
|
||||
// bits are all zero, otherwise it is not representable either.
|
||||
const uint64_t kMaxRepHi64 = 0x77359400UL;
|
||||
if (h64 >= kMaxRepHi64) {
|
||||
if (is_neg && h64 == kMaxRepHi64 && l64 == 0) {
|
||||
// Avoid trying to represent -kint64min below.
|
||||
return time_internal::MakeDuration(kint64min);
|
||||
}
|
||||
return is_neg ? -InfiniteDuration() : InfiniteDuration();
|
||||
}
|
||||
const uint128 kTicksPerSecond128 = static_cast<uint64_t>(kTicksPerSecond);
|
||||
const uint128 hi = u128 / kTicksPerSecond128;
|
||||
rep_hi = static_cast<int64_t>(Uint128Low64(hi));
|
||||
rep_lo =
|
||||
static_cast<uint32_t>(Uint128Low64(u128 - hi * kTicksPerSecond128));
|
||||
}
|
||||
if (is_neg) {
|
||||
rep_hi = -rep_hi;
|
||||
if (rep_lo != 0) {
|
||||
--rep_hi;
|
||||
rep_lo = kTicksPerSecond - rep_lo;
|
||||
}
|
||||
}
|
||||
return time_internal::MakeDuration(rep_hi, rep_lo);
|
||||
}
|
||||
|
||||
// Convert between int64_t and uint64_t, preserving representation. This
|
||||
// allows us to do arithmetic in the unsigned domain, where overflow has
|
||||
// well-defined behavior. See operator+=() and operator-=().
|
||||
//
|
||||
// C99 7.20.1.1.1, as referenced by C++11 18.4.1.2, says, "The typedef
|
||||
// name intN_t designates a signed integer type with width N, no padding
|
||||
// bits, and a two's complement representation." So, we can convert to
|
||||
// and from the corresponding uint64_t value using a bit cast.
|
||||
inline uint64_t EncodeTwosComp(int64_t v) {
|
||||
return absl::bit_cast<uint64_t>(v);
|
||||
}
|
||||
inline int64_t DecodeTwosComp(uint64_t v) { return absl::bit_cast<int64_t>(v); }
|
||||
|
||||
// Note: The overflow detection in this function is done using greater/less *or
|
||||
// equal* because kint64max/min is too large to be represented exactly in a
|
||||
// double (which only has 53 bits of precision). In order to avoid assigning to
|
||||
// rep->hi a double value that is too large for an int64_t (and therefore is
|
||||
// undefined), we must consider computations that equal kint64max/min as a
|
||||
// double as overflow cases.
|
||||
inline bool SafeAddRepHi(double a_hi, double b_hi, Duration* d) {
|
||||
double c = a_hi + b_hi;
|
||||
if (c >= static_cast<double>(kint64max)) {
|
||||
*d = InfiniteDuration();
|
||||
return false;
|
||||
}
|
||||
if (c <= static_cast<double>(kint64min)) {
|
||||
*d = -InfiniteDuration();
|
||||
return false;
|
||||
}
|
||||
*d = time_internal::MakeDuration(c, time_internal::GetRepLo(*d));
|
||||
return true;
|
||||
}
|
||||
|
||||
// A functor that's similar to std::multiplies<T>, except this returns the max
|
||||
// T value instead of overflowing. This is only defined for uint128.
|
||||
template <typename Ignored>
|
||||
struct SafeMultiply {
|
||||
uint128 operator()(uint128 a, uint128 b) const {
|
||||
// b hi is always zero because it originated as an int64_t.
|
||||
assert(Uint128High64(b) == 0);
|
||||
// Fastpath to avoid the expensive overflow check with division.
|
||||
if (Uint128High64(a) == 0) {
|
||||
return (((Uint128Low64(a) | Uint128Low64(b)) >> 32) == 0)
|
||||
? static_cast<uint128>(Uint128Low64(a) * Uint128Low64(b))
|
||||
: a * b;
|
||||
}
|
||||
return b == 0 ? b : (a > kuint128max / b) ? kuint128max : a * b;
|
||||
}
|
||||
};
|
||||
|
||||
// Scales (i.e., multiplies or divides, depending on the Operation template)
|
||||
// the Duration d by the int64_t r.
|
||||
template <template <typename> class Operation>
|
||||
inline Duration ScaleFixed(Duration d, int64_t r) {
|
||||
const uint128 a = MakeU128Ticks(d);
|
||||
const uint128 b = MakeU128(r);
|
||||
const uint128 q = Operation<uint128>()(a, b);
|
||||
const bool is_neg = (time_internal::GetRepHi(d) < 0) != (r < 0);
|
||||
return MakeDurationFromU128(q, is_neg);
|
||||
}
|
||||
|
||||
// Scales (i.e., multiplies or divides, depending on the Operation template)
|
||||
// the Duration d by the double r.
|
||||
template <template <typename> class Operation>
|
||||
inline Duration ScaleDouble(Duration d, double r) {
|
||||
Operation<double> op;
|
||||
double hi_doub = op(time_internal::GetRepHi(d), r);
|
||||
double lo_doub = op(time_internal::GetRepLo(d), r);
|
||||
|
||||
double hi_int = 0;
|
||||
double hi_frac = std::modf(hi_doub, &hi_int);
|
||||
|
||||
// Moves hi's fractional bits to lo.
|
||||
lo_doub /= kTicksPerSecond;
|
||||
lo_doub += hi_frac;
|
||||
|
||||
double lo_int = 0;
|
||||
double lo_frac = std::modf(lo_doub, &lo_int);
|
||||
|
||||
// Rolls lo into hi if necessary.
|
||||
int64_t lo64 = std::round(lo_frac * kTicksPerSecond);
|
||||
|
||||
Duration ans;
|
||||
if (!SafeAddRepHi(hi_int, lo_int, &ans)) return ans;
|
||||
int64_t hi64 = time_internal::GetRepHi(ans);
|
||||
if (!SafeAddRepHi(hi64, lo64 / kTicksPerSecond, &ans)) return ans;
|
||||
hi64 = time_internal::GetRepHi(ans);
|
||||
lo64 %= kTicksPerSecond;
|
||||
NormalizeTicks(&hi64, &lo64);
|
||||
return time_internal::MakeDuration(hi64, lo64);
|
||||
}
|
||||
|
||||
// Tries to divide num by den as fast as possible by looking for common, easy
|
||||
// cases. If the division was done, the quotient is in *q and the remainder is
|
||||
// in *rem and true will be returned.
|
||||
inline bool IDivFastPath(const Duration num, const Duration den, int64_t* q,
|
||||
Duration* rem) {
|
||||
// Bail if num or den is an infinity.
|
||||
if (time_internal::IsInfiniteDuration(num) ||
|
||||
time_internal::IsInfiniteDuration(den))
|
||||
return false;
|
||||
|
||||
int64_t num_hi = time_internal::GetRepHi(num);
|
||||
uint32_t num_lo = time_internal::GetRepLo(num);
|
||||
int64_t den_hi = time_internal::GetRepHi(den);
|
||||
uint32_t den_lo = time_internal::GetRepLo(den);
|
||||
|
||||
if (den_hi == 0 && den_lo == kTicksPerNanosecond) {
|
||||
// Dividing by 1ns
|
||||
if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000000) {
|
||||
*q = num_hi * 1000000000 + num_lo / kTicksPerNanosecond;
|
||||
*rem = time_internal::MakeDuration(0, num_lo % den_lo);
|
||||
return true;
|
||||
}
|
||||
} else if (den_hi == 0 && den_lo == 100 * kTicksPerNanosecond) {
|
||||
// Dividing by 100ns (common when converting to Universal time)
|
||||
if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 10000000) {
|
||||
*q = num_hi * 10000000 + num_lo / (100 * kTicksPerNanosecond);
|
||||
*rem = time_internal::MakeDuration(0, num_lo % den_lo);
|
||||
return true;
|
||||
}
|
||||
} else if (den_hi == 0 && den_lo == 1000 * kTicksPerNanosecond) {
|
||||
// Dividing by 1us
|
||||
if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000000) {
|
||||
*q = num_hi * 1000000 + num_lo / (1000 * kTicksPerNanosecond);
|
||||
*rem = time_internal::MakeDuration(0, num_lo % den_lo);
|
||||
return true;
|
||||
}
|
||||
} else if (den_hi == 0 && den_lo == 1000000 * kTicksPerNanosecond) {
|
||||
// Dividing by 1ms
|
||||
if (num_hi >= 0 && num_hi < (kint64max - kTicksPerSecond) / 1000) {
|
||||
*q = num_hi * 1000 + num_lo / (1000000 * kTicksPerNanosecond);
|
||||
*rem = time_internal::MakeDuration(0, num_lo % den_lo);
|
||||
return true;
|
||||
}
|
||||
} else if (den_hi > 0 && den_lo == 0) {
|
||||
// Dividing by positive multiple of 1s
|
||||
if (num_hi >= 0) {
|
||||
if (den_hi == 1) {
|
||||
*q = num_hi;
|
||||
*rem = time_internal::MakeDuration(0, num_lo);
|
||||
return true;
|
||||
}
|
||||
*q = num_hi / den_hi;
|
||||
*rem = time_internal::MakeDuration(num_hi % den_hi, num_lo);
|
||||
return true;
|
||||
}
|
||||
if (num_lo != 0) {
|
||||
num_hi += 1;
|
||||
}
|
||||
int64_t quotient = num_hi / den_hi;
|
||||
int64_t rem_sec = num_hi % den_hi;
|
||||
if (rem_sec > 0) {
|
||||
rem_sec -= den_hi;
|
||||
quotient += 1;
|
||||
}
|
||||
if (num_lo != 0) {
|
||||
rem_sec -= 1;
|
||||
}
|
||||
*q = quotient;
|
||||
*rem = time_internal::MakeDuration(rem_sec, num_lo);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace time_internal {
|
||||
|
||||
// The 'satq' argument indicates whether the quotient should saturate at the
|
||||
// bounds of int64_t. If it does saturate, the difference will spill over to
|
||||
// the remainder. If it does not saturate, the remainder remain accurate,
|
||||
// but the returned quotient will over/underflow int64_t and should not be used.
|
||||
int64_t IDivDuration(bool satq, const Duration num, const Duration den,
|
||||
Duration* rem) {
|
||||
int64_t q = 0;
|
||||
if (IDivFastPath(num, den, &q, rem)) {
|
||||
return q;
|
||||
}
|
||||
|
||||
const bool num_neg = num < ZeroDuration();
|
||||
const bool den_neg = den < ZeroDuration();
|
||||
const bool quotient_neg = num_neg != den_neg;
|
||||
|
||||
if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) {
|
||||
*rem = num_neg ? -InfiniteDuration() : InfiniteDuration();
|
||||
return quotient_neg ? kint64min : kint64max;
|
||||
}
|
||||
if (time_internal::IsInfiniteDuration(den)) {
|
||||
*rem = num;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const uint128 a = MakeU128Ticks(num);
|
||||
const uint128 b = MakeU128Ticks(den);
|
||||
uint128 quotient128 = a / b;
|
||||
|
||||
if (satq) {
|
||||
// Limits the quotient to the range of int64_t.
|
||||
if (quotient128 > uint128(static_cast<uint64_t>(kint64max))) {
|
||||
quotient128 = quotient_neg ? uint128(static_cast<uint64_t>(kint64min))
|
||||
: uint128(static_cast<uint64_t>(kint64max));
|
||||
}
|
||||
}
|
||||
|
||||
const uint128 remainder128 = a - quotient128 * b;
|
||||
*rem = MakeDurationFromU128(remainder128, num_neg);
|
||||
|
||||
if (!quotient_neg || quotient128 == 0) {
|
||||
return Uint128Low64(quotient128) & kint64max;
|
||||
}
|
||||
// The quotient needs to be negated, but we need to carefully handle
|
||||
// quotient128s with the top bit on.
|
||||
return -static_cast<int64_t>(Uint128Low64(quotient128 - 1) & kint64max) - 1;
|
||||
}
|
||||
|
||||
} // namespace time_internal
|
||||
|
||||
//
|
||||
// Additive operators.
|
||||
//
|
||||
|
||||
Duration& Duration::operator+=(Duration rhs) {
|
||||
if (time_internal::IsInfiniteDuration(*this)) return *this;
|
||||
if (time_internal::IsInfiniteDuration(rhs)) return *this = rhs;
|
||||
const int64_t orig_rep_hi = rep_hi_.Get();
|
||||
rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_.Get()) +
|
||||
EncodeTwosComp(rhs.rep_hi_.Get()));
|
||||
if (rep_lo_ >= kTicksPerSecond - rhs.rep_lo_) {
|
||||
rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_.Get()) + 1);
|
||||
rep_lo_ -= kTicksPerSecond;
|
||||
}
|
||||
rep_lo_ += rhs.rep_lo_;
|
||||
if (rhs.rep_hi_.Get() < 0 ? rep_hi_.Get() > orig_rep_hi
|
||||
: rep_hi_.Get() < orig_rep_hi) {
|
||||
return *this =
|
||||
rhs.rep_hi_.Get() < 0 ? -InfiniteDuration() : InfiniteDuration();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Duration& Duration::operator-=(Duration rhs) {
|
||||
if (time_internal::IsInfiniteDuration(*this)) return *this;
|
||||
if (time_internal::IsInfiniteDuration(rhs)) {
|
||||
return *this = rhs.rep_hi_.Get() >= 0 ? -InfiniteDuration()
|
||||
: InfiniteDuration();
|
||||
}
|
||||
const int64_t orig_rep_hi = rep_hi_.Get();
|
||||
rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_.Get()) -
|
||||
EncodeTwosComp(rhs.rep_hi_.Get()));
|
||||
if (rep_lo_ < rhs.rep_lo_) {
|
||||
rep_hi_ = DecodeTwosComp(EncodeTwosComp(rep_hi_.Get()) - 1);
|
||||
rep_lo_ += kTicksPerSecond;
|
||||
}
|
||||
rep_lo_ -= rhs.rep_lo_;
|
||||
if (rhs.rep_hi_.Get() < 0 ? rep_hi_.Get() < orig_rep_hi
|
||||
: rep_hi_.Get() > orig_rep_hi) {
|
||||
return *this = rhs.rep_hi_.Get() >= 0 ? -InfiniteDuration()
|
||||
: InfiniteDuration();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//
|
||||
// Multiplicative operators.
|
||||
//
|
||||
|
||||
Duration& Duration::operator*=(int64_t r) {
|
||||
if (time_internal::IsInfiniteDuration(*this)) {
|
||||
const bool is_neg = (r < 0) != (rep_hi_.Get() < 0);
|
||||
return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
|
||||
}
|
||||
return *this = ScaleFixed<SafeMultiply>(*this, r);
|
||||
}
|
||||
|
||||
Duration& Duration::operator*=(double r) {
|
||||
if (time_internal::IsInfiniteDuration(*this) || !IsFinite(r)) {
|
||||
const bool is_neg = std::signbit(r) != (rep_hi_.Get() < 0);
|
||||
return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
|
||||
}
|
||||
return *this = ScaleDouble<std::multiplies>(*this, r);
|
||||
}
|
||||
|
||||
Duration& Duration::operator/=(int64_t r) {
|
||||
if (time_internal::IsInfiniteDuration(*this) || r == 0) {
|
||||
const bool is_neg = (r < 0) != (rep_hi_.Get() < 0);
|
||||
return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
|
||||
}
|
||||
return *this = ScaleFixed<std::divides>(*this, r);
|
||||
}
|
||||
|
||||
Duration& Duration::operator/=(double r) {
|
||||
if (time_internal::IsInfiniteDuration(*this) || !IsValidDivisor(r)) {
|
||||
const bool is_neg = std::signbit(r) != (rep_hi_.Get() < 0);
|
||||
return *this = is_neg ? -InfiniteDuration() : InfiniteDuration();
|
||||
}
|
||||
return *this = ScaleDouble<std::divides>(*this, r);
|
||||
}
|
||||
|
||||
Duration& Duration::operator%=(Duration rhs) {
|
||||
time_internal::IDivDuration(false, *this, rhs, this);
|
||||
return *this;
|
||||
}
|
||||
|
||||
double FDivDuration(Duration num, Duration den) {
|
||||
// Arithmetic with infinity is sticky.
|
||||
if (time_internal::IsInfiniteDuration(num) || den == ZeroDuration()) {
|
||||
return (num < ZeroDuration()) == (den < ZeroDuration())
|
||||
? std::numeric_limits<double>::infinity()
|
||||
: -std::numeric_limits<double>::infinity();
|
||||
}
|
||||
if (time_internal::IsInfiniteDuration(den)) return 0.0;
|
||||
|
||||
double a =
|
||||
static_cast<double>(time_internal::GetRepHi(num)) * kTicksPerSecond +
|
||||
time_internal::GetRepLo(num);
|
||||
double b =
|
||||
static_cast<double>(time_internal::GetRepHi(den)) * kTicksPerSecond +
|
||||
time_internal::GetRepLo(den);
|
||||
return a / b;
|
||||
}
|
||||
|
||||
//
|
||||
// Trunc/Floor/Ceil.
|
||||
//
|
||||
|
||||
Duration Trunc(Duration d, Duration unit) {
|
||||
return d - (d % unit);
|
||||
}
|
||||
|
||||
Duration Floor(const Duration d, const Duration unit) {
|
||||
const absl::Duration td = Trunc(d, unit);
|
||||
return td <= d ? td : td - AbsDuration(unit);
|
||||
}
|
||||
|
||||
Duration Ceil(const Duration d, const Duration unit) {
|
||||
const absl::Duration td = Trunc(d, unit);
|
||||
return td >= d ? td : td + AbsDuration(unit);
|
||||
}
|
||||
|
||||
//
|
||||
// Factory functions.
|
||||
//
|
||||
|
||||
Duration DurationFromTimespec(timespec ts) {
|
||||
if (static_cast<uint64_t>(ts.tv_nsec) < 1000 * 1000 * 1000) {
|
||||
int64_t ticks = ts.tv_nsec * kTicksPerNanosecond;
|
||||
return time_internal::MakeDuration(ts.tv_sec, ticks);
|
||||
}
|
||||
return Seconds(ts.tv_sec) + Nanoseconds(ts.tv_nsec);
|
||||
}
|
||||
|
||||
Duration DurationFromTimeval(timeval tv) {
|
||||
if (static_cast<uint64_t>(tv.tv_usec) < 1000 * 1000) {
|
||||
int64_t ticks = tv.tv_usec * 1000 * kTicksPerNanosecond;
|
||||
return time_internal::MakeDuration(tv.tv_sec, ticks);
|
||||
}
|
||||
return Seconds(tv.tv_sec) + Microseconds(tv.tv_usec);
|
||||
}
|
||||
|
||||
//
|
||||
// Conversion to other duration types.
|
||||
//
|
||||
|
||||
int64_t ToInt64Nanoseconds(Duration d) {
|
||||
if (time_internal::GetRepHi(d) >= 0 &&
|
||||
time_internal::GetRepHi(d) >> 33 == 0) {
|
||||
return (time_internal::GetRepHi(d) * 1000 * 1000 * 1000) +
|
||||
(time_internal::GetRepLo(d) / kTicksPerNanosecond);
|
||||
}
|
||||
return d / Nanoseconds(1);
|
||||
}
|
||||
int64_t ToInt64Microseconds(Duration d) {
|
||||
if (time_internal::GetRepHi(d) >= 0 &&
|
||||
time_internal::GetRepHi(d) >> 43 == 0) {
|
||||
return (time_internal::GetRepHi(d) * 1000 * 1000) +
|
||||
(time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000));
|
||||
}
|
||||
return d / Microseconds(1);
|
||||
}
|
||||
int64_t ToInt64Milliseconds(Duration d) {
|
||||
if (time_internal::GetRepHi(d) >= 0 &&
|
||||
time_internal::GetRepHi(d) >> 53 == 0) {
|
||||
return (time_internal::GetRepHi(d) * 1000) +
|
||||
(time_internal::GetRepLo(d) / (kTicksPerNanosecond * 1000 * 1000));
|
||||
}
|
||||
return d / Milliseconds(1);
|
||||
}
|
||||
int64_t ToInt64Seconds(Duration d) {
|
||||
int64_t hi = time_internal::GetRepHi(d);
|
||||
if (time_internal::IsInfiniteDuration(d)) return hi;
|
||||
if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
|
||||
return hi;
|
||||
}
|
||||
int64_t ToInt64Minutes(Duration d) {
|
||||
int64_t hi = time_internal::GetRepHi(d);
|
||||
if (time_internal::IsInfiniteDuration(d)) return hi;
|
||||
if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
|
||||
return hi / 60;
|
||||
}
|
||||
int64_t ToInt64Hours(Duration d) {
|
||||
int64_t hi = time_internal::GetRepHi(d);
|
||||
if (time_internal::IsInfiniteDuration(d)) return hi;
|
||||
if (hi < 0 && time_internal::GetRepLo(d) != 0) ++hi;
|
||||
return hi / (60 * 60);
|
||||
}
|
||||
|
||||
double ToDoubleNanoseconds(Duration d) {
|
||||
return FDivDuration(d, Nanoseconds(1));
|
||||
}
|
||||
double ToDoubleMicroseconds(Duration d) {
|
||||
return FDivDuration(d, Microseconds(1));
|
||||
}
|
||||
double ToDoubleMilliseconds(Duration d) {
|
||||
return FDivDuration(d, Milliseconds(1));
|
||||
}
|
||||
double ToDoubleSeconds(Duration d) {
|
||||
return FDivDuration(d, Seconds(1));
|
||||
}
|
||||
double ToDoubleMinutes(Duration d) {
|
||||
return FDivDuration(d, Minutes(1));
|
||||
}
|
||||
double ToDoubleHours(Duration d) {
|
||||
return FDivDuration(d, Hours(1));
|
||||
}
|
||||
|
||||
timespec ToTimespec(Duration d) {
|
||||
timespec ts;
|
||||
if (!time_internal::IsInfiniteDuration(d)) {
|
||||
int64_t rep_hi = time_internal::GetRepHi(d);
|
||||
uint32_t rep_lo = time_internal::GetRepLo(d);
|
||||
if (rep_hi < 0) {
|
||||
// Tweak the fields so that unsigned division of rep_lo
|
||||
// maps to truncation (towards zero) for the timespec.
|
||||
rep_lo += kTicksPerNanosecond - 1;
|
||||
if (rep_lo >= kTicksPerSecond) {
|
||||
rep_hi += 1;
|
||||
rep_lo -= kTicksPerSecond;
|
||||
}
|
||||
}
|
||||
ts.tv_sec = static_cast<decltype(ts.tv_sec)>(rep_hi);
|
||||
if (ts.tv_sec == rep_hi) { // no time_t narrowing
|
||||
ts.tv_nsec = rep_lo / kTicksPerNanosecond;
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
if (d >= ZeroDuration()) {
|
||||
ts.tv_sec = std::numeric_limits<time_t>::max();
|
||||
ts.tv_nsec = 1000 * 1000 * 1000 - 1;
|
||||
} else {
|
||||
ts.tv_sec = std::numeric_limits<time_t>::min();
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
timeval ToTimeval(Duration d) {
|
||||
timeval tv;
|
||||
timespec ts = ToTimespec(d);
|
||||
if (ts.tv_sec < 0) {
|
||||
// Tweak the fields so that positive division of tv_nsec
|
||||
// maps to truncation (towards zero) for the timeval.
|
||||
ts.tv_nsec += 1000 - 1;
|
||||
if (ts.tv_nsec >= 1000 * 1000 * 1000) {
|
||||
ts.tv_sec += 1;
|
||||
ts.tv_nsec -= 1000 * 1000 * 1000;
|
||||
}
|
||||
}
|
||||
tv.tv_sec = static_cast<decltype(tv.tv_sec)>(ts.tv_sec);
|
||||
if (tv.tv_sec != ts.tv_sec) { // narrowing
|
||||
if (ts.tv_sec < 0) {
|
||||
tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
|
||||
tv.tv_usec = 0;
|
||||
} else {
|
||||
tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
|
||||
tv.tv_usec = 1000 * 1000 - 1;
|
||||
}
|
||||
return tv;
|
||||
}
|
||||
tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t
|
||||
return tv;
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds ToChronoNanoseconds(Duration d) {
|
||||
return time_internal::ToChronoDuration<std::chrono::nanoseconds>(d);
|
||||
}
|
||||
std::chrono::microseconds ToChronoMicroseconds(Duration d) {
|
||||
return time_internal::ToChronoDuration<std::chrono::microseconds>(d);
|
||||
}
|
||||
std::chrono::milliseconds ToChronoMilliseconds(Duration d) {
|
||||
return time_internal::ToChronoDuration<std::chrono::milliseconds>(d);
|
||||
}
|
||||
std::chrono::seconds ToChronoSeconds(Duration d) {
|
||||
return time_internal::ToChronoDuration<std::chrono::seconds>(d);
|
||||
}
|
||||
std::chrono::minutes ToChronoMinutes(Duration d) {
|
||||
return time_internal::ToChronoDuration<std::chrono::minutes>(d);
|
||||
}
|
||||
std::chrono::hours ToChronoHours(Duration d) {
|
||||
return time_internal::ToChronoDuration<std::chrono::hours>(d);
|
||||
}
|
||||
|
||||
//
|
||||
// To/From string formatting.
|
||||
//
|
||||
|
||||
namespace {
|
||||
|
||||
// Formats a positive 64-bit integer in the given field width. Note that
|
||||
// it is up to the caller of Format64() to ensure that there is sufficient
|
||||
// space before ep to hold the conversion.
|
||||
char* Format64(char* ep, int width, int64_t v) {
|
||||
do {
|
||||
--width;
|
||||
*--ep = static_cast<char>('0' + (v % 10)); // contiguous digits
|
||||
} while (v /= 10);
|
||||
while (--width >= 0) *--ep = '0'; // zero pad
|
||||
return ep;
|
||||
}
|
||||
|
||||
// Helpers for FormatDuration() that format 'n' and append it to 'out'
|
||||
// followed by the given 'unit'. If 'n' formats to "0", nothing is
|
||||
// appended (not even the unit).
|
||||
|
||||
// A type that encapsulates how to display a value of a particular unit. For
|
||||
// values that are displayed with fractional parts, the precision indicates
|
||||
// where to round the value. The precision varies with the display unit because
|
||||
// a Duration can hold only quarters of a nanosecond, so displaying information
|
||||
// beyond that is just noise.
|
||||
//
|
||||
// For example, a microsecond value of 42.00025xxxxx should not display beyond 5
|
||||
// fractional digits, because it is in the noise of what a Duration can
|
||||
// represent.
|
||||
struct DisplayUnit {
|
||||
absl::string_view abbr;
|
||||
int prec;
|
||||
double pow10;
|
||||
};
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplayNano = {"ns", 2, 1e2};
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplayMicro = {"us", 5, 1e5};
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplayMilli = {"ms", 8, 1e8};
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplaySec = {"s", 11, 1e11};
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplayMin = {"m", -1, 0.0}; // prec ignored
|
||||
ABSL_CONST_INIT const DisplayUnit kDisplayHour = {"h", -1,
|
||||
0.0}; // prec ignored
|
||||
|
||||
void AppendNumberUnit(std::string* out, int64_t n, DisplayUnit unit) {
|
||||
char buf[sizeof("2562047788015216")]; // hours in max duration
|
||||
char* const ep = buf + sizeof(buf);
|
||||
char* bp = Format64(ep, 0, n);
|
||||
if (*bp != '0' || bp + 1 != ep) {
|
||||
out->append(bp, static_cast<size_t>(ep - bp));
|
||||
out->append(unit.abbr.data(), unit.abbr.size());
|
||||
}
|
||||
}
|
||||
|
||||
// Note: unit.prec is limited to double's digits10 value (typically 15) so it
|
||||
// always fits in buf[].
|
||||
void AppendNumberUnit(std::string* out, double n, DisplayUnit unit) {
|
||||
constexpr int kBufferSize = std::numeric_limits<double>::digits10;
|
||||
const int prec = std::min(kBufferSize, unit.prec);
|
||||
char buf[kBufferSize]; // also large enough to hold integer part
|
||||
char* ep = buf + sizeof(buf);
|
||||
double d = 0;
|
||||
int64_t frac_part = std::round(std::modf(n, &d) * unit.pow10);
|
||||
int64_t int_part = d;
|
||||
if (int_part != 0 || frac_part != 0) {
|
||||
char* bp = Format64(ep, 0, int_part); // always < 1000
|
||||
out->append(bp, static_cast<size_t>(ep - bp));
|
||||
if (frac_part != 0) {
|
||||
out->push_back('.');
|
||||
bp = Format64(ep, prec, frac_part);
|
||||
while (ep[-1] == '0') --ep;
|
||||
out->append(bp, static_cast<size_t>(ep - bp));
|
||||
}
|
||||
out->append(unit.abbr.data(), unit.abbr.size());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// From Go's doc at https://golang.org/pkg/time/#Duration.String
|
||||
// [FormatDuration] returns a string representing the duration in the
|
||||
// form "72h3m0.5s". Leading zero units are omitted. As a special
|
||||
// case, durations less than one second format use a smaller unit
|
||||
// (milli-, micro-, or nanoseconds) to ensure that the leading digit
|
||||
// is non-zero.
|
||||
// Unlike Go, we format the zero duration as 0, with no unit.
|
||||
std::string FormatDuration(Duration d) {
|
||||
constexpr Duration kMinDuration = Seconds(kint64min);
|
||||
std::string s;
|
||||
if (d == kMinDuration) {
|
||||
// Avoid needing to negate kint64min by directly returning what the
|
||||
// following code should produce in that case.
|
||||
s = "-2562047788015215h30m8s";
|
||||
return s;
|
||||
}
|
||||
if (d < ZeroDuration()) {
|
||||
s.append("-");
|
||||
d = -d;
|
||||
}
|
||||
if (d == InfiniteDuration()) {
|
||||
s.append("inf");
|
||||
} else if (d < Seconds(1)) {
|
||||
// Special case for durations with a magnitude < 1 second. The duration
|
||||
// is printed as a fraction of a single unit, e.g., "1.2ms".
|
||||
if (d < Microseconds(1)) {
|
||||
AppendNumberUnit(&s, FDivDuration(d, Nanoseconds(1)), kDisplayNano);
|
||||
} else if (d < Milliseconds(1)) {
|
||||
AppendNumberUnit(&s, FDivDuration(d, Microseconds(1)), kDisplayMicro);
|
||||
} else {
|
||||
AppendNumberUnit(&s, FDivDuration(d, Milliseconds(1)), kDisplayMilli);
|
||||
}
|
||||
} else {
|
||||
AppendNumberUnit(&s, IDivDuration(d, Hours(1), &d), kDisplayHour);
|
||||
AppendNumberUnit(&s, IDivDuration(d, Minutes(1), &d), kDisplayMin);
|
||||
AppendNumberUnit(&s, FDivDuration(d, Seconds(1)), kDisplaySec);
|
||||
}
|
||||
if (s.empty() || s == "-") {
|
||||
s = "0";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// A helper for ParseDuration() that parses a leading number from the given
|
||||
// string and stores the result in *int_part/*frac_part/*frac_scale. The
|
||||
// given string pointer is modified to point to the first unconsumed char.
|
||||
bool ConsumeDurationNumber(const char** dpp, const char* ep, int64_t* int_part,
|
||||
int64_t* frac_part, int64_t* frac_scale) {
|
||||
*int_part = 0;
|
||||
*frac_part = 0;
|
||||
*frac_scale = 1; // invariant: *frac_part < *frac_scale
|
||||
const char* start = *dpp;
|
||||
for (; *dpp != ep; *dpp += 1) {
|
||||
const int d = **dpp - '0'; // contiguous digits
|
||||
if (d < 0 || 10 <= d) break;
|
||||
|
||||
if (*int_part > kint64max / 10) return false;
|
||||
*int_part *= 10;
|
||||
if (*int_part > kint64max - d) return false;
|
||||
*int_part += d;
|
||||
}
|
||||
const bool int_part_empty = (*dpp == start);
|
||||
if (*dpp == ep || **dpp != '.') return !int_part_empty;
|
||||
|
||||
for (*dpp += 1; *dpp != ep; *dpp += 1) {
|
||||
const int d = **dpp - '0'; // contiguous digits
|
||||
if (d < 0 || 10 <= d) break;
|
||||
if (*frac_scale <= kint64max / 10) {
|
||||
*frac_part *= 10;
|
||||
*frac_part += d;
|
||||
*frac_scale *= 10;
|
||||
}
|
||||
}
|
||||
return !int_part_empty || *frac_scale != 1;
|
||||
}
|
||||
|
||||
// A helper for ParseDuration() that parses a leading unit designator (e.g.,
|
||||
// ns, us, ms, s, m, h) from the given string and stores the resulting unit
|
||||
// in "*unit". The given string pointer is modified to point to the first
|
||||
// unconsumed char.
|
||||
bool ConsumeDurationUnit(const char** start, const char* end, Duration* unit) {
|
||||
size_t size = static_cast<size_t>(end - *start);
|
||||
switch (size) {
|
||||
case 0:
|
||||
return false;
|
||||
default:
|
||||
switch (**start) {
|
||||
case 'n':
|
||||
if (*(*start + 1) == 's') {
|
||||
*start += 2;
|
||||
*unit = Nanoseconds(1);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
if (*(*start + 1) == 's') {
|
||||
*start += 2;
|
||||
*unit = Microseconds(1);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
if (*(*start + 1) == 's') {
|
||||
*start += 2;
|
||||
*unit = Milliseconds(1);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ABSL_FALLTHROUGH_INTENDED;
|
||||
case 1:
|
||||
switch (**start) {
|
||||
case 's':
|
||||
*unit = Seconds(1);
|
||||
*start += 1;
|
||||
return true;
|
||||
case 'm':
|
||||
*unit = Minutes(1);
|
||||
*start += 1;
|
||||
return true;
|
||||
case 'h':
|
||||
*unit = Hours(1);
|
||||
*start += 1;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// From Go's doc at https://golang.org/pkg/time/#ParseDuration
|
||||
// [ParseDuration] parses a duration string. A duration string is
|
||||
// a possibly signed sequence of decimal numbers, each with optional
|
||||
// fraction and a unit suffix, such as "300ms", "-1.5h" or "2h45m".
|
||||
// Valid time units are "ns", "us" "ms", "s", "m", "h".
|
||||
bool ParseDuration(absl::string_view dur_sv, Duration* d) {
|
||||
int sign = 1;
|
||||
if (absl::ConsumePrefix(&dur_sv, "-")) {
|
||||
sign = -1;
|
||||
} else {
|
||||
absl::ConsumePrefix(&dur_sv, "+");
|
||||
}
|
||||
if (dur_sv.empty()) return false;
|
||||
|
||||
// Special case for a string of "0".
|
||||
if (dur_sv == "0") {
|
||||
*d = ZeroDuration();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dur_sv == "inf") {
|
||||
*d = sign * InfiniteDuration();
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* start = dur_sv.data();
|
||||
const char* end = start + dur_sv.size();
|
||||
|
||||
Duration dur;
|
||||
while (start != end) {
|
||||
int64_t int_part;
|
||||
int64_t frac_part;
|
||||
int64_t frac_scale;
|
||||
Duration unit;
|
||||
if (!ConsumeDurationNumber(&start, end, &int_part, &frac_part,
|
||||
&frac_scale) ||
|
||||
!ConsumeDurationUnit(&start, end, &unit)) {
|
||||
return false;
|
||||
}
|
||||
if (int_part != 0) dur += sign * int_part * unit;
|
||||
if (frac_part != 0) dur += sign * frac_part * unit / frac_scale;
|
||||
}
|
||||
*d = dur;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbslParseFlag(absl::string_view text, Duration* dst, std::string*) {
|
||||
return ParseDuration(text, dst);
|
||||
}
|
||||
|
||||
std::string AbslUnparseFlag(Duration d) { return FormatDuration(d); }
|
||||
bool ParseFlag(const std::string& text, Duration* dst, std::string* ) {
|
||||
return ParseDuration(text, dst);
|
||||
}
|
||||
|
||||
std::string UnparseFlag(Duration d) { return FormatDuration(d); }
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
161
Pods/abseil/absl/time/format.cc
generated
Normal file
161
Pods/abseil/absl/time/format.cc
generated
Normal file
@@ -0,0 +1,161 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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 <string.h>
|
||||
|
||||
#include <cctype>
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/strings/match.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
#include "absl/time/time.h"
|
||||
|
||||
namespace cctz = absl::time_internal::cctz;
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
ABSL_DLL extern const char RFC3339_full[] = "%Y-%m-%d%ET%H:%M:%E*S%Ez";
|
||||
ABSL_DLL extern const char RFC3339_sec[] = "%Y-%m-%d%ET%H:%M:%S%Ez";
|
||||
|
||||
ABSL_DLL extern const char RFC1123_full[] = "%a, %d %b %E4Y %H:%M:%S %z";
|
||||
ABSL_DLL extern const char RFC1123_no_wday[] = "%d %b %E4Y %H:%M:%S %z";
|
||||
|
||||
namespace {
|
||||
|
||||
const char kInfiniteFutureStr[] = "infinite-future";
|
||||
const char kInfinitePastStr[] = "infinite-past";
|
||||
|
||||
struct cctz_parts {
|
||||
cctz::time_point<cctz::seconds> sec;
|
||||
cctz::detail::femtoseconds fem;
|
||||
};
|
||||
|
||||
inline cctz::time_point<cctz::seconds> unix_epoch() {
|
||||
return std::chrono::time_point_cast<cctz::seconds>(
|
||||
std::chrono::system_clock::from_time_t(0));
|
||||
}
|
||||
|
||||
// Splits a Time into seconds and femtoseconds, which can be used with CCTZ.
|
||||
// Requires that 't' is finite. See duration.cc for details about rep_hi and
|
||||
// rep_lo.
|
||||
cctz_parts Split(absl::Time t) {
|
||||
const auto d = time_internal::ToUnixDuration(t);
|
||||
const int64_t rep_hi = time_internal::GetRepHi(d);
|
||||
const int64_t rep_lo = time_internal::GetRepLo(d);
|
||||
const auto sec = unix_epoch() + cctz::seconds(rep_hi);
|
||||
const auto fem = cctz::detail::femtoseconds(rep_lo * (1000 * 1000 / 4));
|
||||
return {sec, fem};
|
||||
}
|
||||
|
||||
// Joins the given seconds and femtoseconds into a Time. See duration.cc for
|
||||
// details about rep_hi and rep_lo.
|
||||
absl::Time Join(const cctz_parts& parts) {
|
||||
const int64_t rep_hi = (parts.sec - unix_epoch()).count();
|
||||
const uint32_t rep_lo =
|
||||
static_cast<uint32_t>(parts.fem.count() / (1000 * 1000 / 4));
|
||||
const auto d = time_internal::MakeDuration(rep_hi, rep_lo);
|
||||
return time_internal::FromUnixDuration(d);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::string FormatTime(absl::string_view format, absl::Time t,
|
||||
absl::TimeZone tz) {
|
||||
if (t == absl::InfiniteFuture()) return std::string(kInfiniteFutureStr);
|
||||
if (t == absl::InfinitePast()) return std::string(kInfinitePastStr);
|
||||
const auto parts = Split(t);
|
||||
return cctz::detail::format(std::string(format), parts.sec, parts.fem,
|
||||
cctz::time_zone(tz));
|
||||
}
|
||||
|
||||
std::string FormatTime(absl::Time t, absl::TimeZone tz) {
|
||||
return FormatTime(RFC3339_full, t, tz);
|
||||
}
|
||||
|
||||
std::string FormatTime(absl::Time t) {
|
||||
return absl::FormatTime(RFC3339_full, t, absl::LocalTimeZone());
|
||||
}
|
||||
|
||||
bool ParseTime(absl::string_view format, absl::string_view input,
|
||||
absl::Time* time, std::string* err) {
|
||||
return absl::ParseTime(format, input, absl::UTCTimeZone(), time, err);
|
||||
}
|
||||
|
||||
// If the input string does not contain an explicit UTC offset, interpret
|
||||
// the fields with respect to the given TimeZone.
|
||||
bool ParseTime(absl::string_view format, absl::string_view input,
|
||||
absl::TimeZone tz, absl::Time* time, std::string* err) {
|
||||
auto strip_leading_space = [](absl::string_view* sv) {
|
||||
while (!sv->empty()) {
|
||||
if (!std::isspace(sv->front())) return;
|
||||
sv->remove_prefix(1);
|
||||
}
|
||||
};
|
||||
|
||||
// Portable toolchains means we don't get nice constexpr here.
|
||||
struct Literal {
|
||||
const char* name;
|
||||
size_t size;
|
||||
absl::Time value;
|
||||
};
|
||||
static Literal literals[] = {
|
||||
{kInfiniteFutureStr, strlen(kInfiniteFutureStr), InfiniteFuture()},
|
||||
{kInfinitePastStr, strlen(kInfinitePastStr), InfinitePast()},
|
||||
};
|
||||
strip_leading_space(&input);
|
||||
for (const auto& lit : literals) {
|
||||
if (absl::StartsWith(input, absl::string_view(lit.name, lit.size))) {
|
||||
absl::string_view tail = input;
|
||||
tail.remove_prefix(lit.size);
|
||||
strip_leading_space(&tail);
|
||||
if (tail.empty()) {
|
||||
*time = lit.value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string error;
|
||||
cctz_parts parts;
|
||||
const bool b =
|
||||
cctz::detail::parse(std::string(format), std::string(input),
|
||||
cctz::time_zone(tz), &parts.sec, &parts.fem, &error);
|
||||
if (b) {
|
||||
*time = Join(parts);
|
||||
} else if (err != nullptr) {
|
||||
*err = error;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
// Functions required to support absl::Time flags.
|
||||
bool AbslParseFlag(absl::string_view text, absl::Time* t, std::string* error) {
|
||||
return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
|
||||
}
|
||||
|
||||
std::string AbslUnparseFlag(absl::Time t) {
|
||||
return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
|
||||
}
|
||||
bool ParseFlag(const std::string& text, absl::Time* t, std::string* error) {
|
||||
return absl::ParseTime(RFC3339_full, text, absl::UTCTimeZone(), t, error);
|
||||
}
|
||||
|
||||
std::string UnparseFlag(absl::Time t) {
|
||||
return absl::FormatTime(RFC3339_full, t, absl::UTCTimeZone());
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
332
Pods/abseil/absl/time/internal/cctz/include/cctz/civil_time.h
generated
Normal file
332
Pods/abseil/absl/time/internal/cctz/include/cctz/civil_time.h
generated
Normal file
@@ -0,0 +1,332 @@
|
||||
// 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 ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time_detail.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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;
|
||||
|
||||
// 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 thurs1 = next_weekday(d - 1, weekday::thursday);
|
||||
// // Gets the previous Thursday if d is not already Thursday
|
||||
// civil_day thurs2 = prev_weekday(d + 1, weekday::thursday);
|
||||
//
|
||||
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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_H_
|
||||
632
Pods/abseil/absl/time/internal/cctz/include/cctz/civil_time_detail.h
generated
Normal file
632
Pods/abseil/absl/time/internal/cctz/include/cctz/civil_time_detail.h
generated
Normal file
@@ -0,0 +1,632 @@
|
||||
// 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 ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <type_traits>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
// 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 absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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 {
|
||||
const int yi = static_cast<int>((y + (m > 2)) % 400);
|
||||
return yi < 0 ? yi + 400 : yi;
|
||||
}
|
||||
CONSTEXPR_F int days_per_century(int yi) noexcept {
|
||||
return 36524 + (yi == 0 || yi > 300);
|
||||
}
|
||||
CONSTEXPR_F int days_per_4years(int yi) noexcept {
|
||||
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) {
|
||||
ey -= 400;
|
||||
cd += 146097;
|
||||
}
|
||||
ey += (d / 146097) * 400;
|
||||
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.
|
||||
ey -= 1;
|
||||
d += days_per_year(ey, m);
|
||||
} else {
|
||||
ey -= 400;
|
||||
d += 146097;
|
||||
}
|
||||
}
|
||||
if (d > 365) {
|
||||
int yi = year_index(ey, m); // Index into Gregorian 400 year cycle.
|
||||
for (;;) {
|
||||
int n = days_per_century(yi);
|
||||
if (d <= n) break;
|
||||
d -= n;
|
||||
ey += 100;
|
||||
yi += 100;
|
||||
if (yi >= 400) yi -= 400;
|
||||
}
|
||||
for (;;) {
|
||||
int n = days_per_4years(yi);
|
||||
if (d <= n) break;
|
||||
d -= n;
|
||||
ey += 4;
|
||||
yi += 4;
|
||||
if (yi >= 400) yi -= 400;
|
||||
}
|
||||
for (;;) {
|
||||
int n = days_per_year(ey, m);
|
||||
if (d <= n) break;
|
||||
d -= n;
|
||||
++ey;
|
||||
}
|
||||
}
|
||||
if (d > 28) {
|
||||
for (;;) {
|
||||
int n = days_per_month(ey, m);
|
||||
if (d <= n) break;
|
||||
d -= n;
|
||||
if (++m > 12) {
|
||||
++ey;
|
||||
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};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace impl {
|
||||
|
||||
template <typename H>
|
||||
H AbslHashValueImpl(second_tag, H h, fields f) {
|
||||
return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm, f.ss);
|
||||
}
|
||||
template <typename H>
|
||||
H AbslHashValueImpl(minute_tag, H h, fields f) {
|
||||
return H::combine(std::move(h), f.y, f.m, f.d, f.hh, f.mm);
|
||||
}
|
||||
template <typename H>
|
||||
H AbslHashValueImpl(hour_tag, H h, fields f) {
|
||||
return H::combine(std::move(h), f.y, f.m, f.d, f.hh);
|
||||
}
|
||||
template <typename H>
|
||||
H AbslHashValueImpl(day_tag, H h, fields f) {
|
||||
return H::combine(std::move(h), f.y, f.m, f.d);
|
||||
}
|
||||
template <typename H>
|
||||
H AbslHashValueImpl(month_tag, H h, fields f) {
|
||||
return H::combine(std::move(h), f.y, f.m);
|
||||
}
|
||||
template <typename H>
|
||||
H AbslHashValueImpl(year_tag, H h, fields f) {
|
||||
return H::combine(std::move(h), f.y);
|
||||
}
|
||||
|
||||
} // namespace impl
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
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 auto(max)() -> civil_time {
|
||||
const auto max_year = (std::numeric_limits<std::int_least64_t>::max)();
|
||||
return civil_time(max_year, 12, 31, 23, 59, 59);
|
||||
}
|
||||
static CONSTEXPR_F auto(min)() -> civil_time {
|
||||
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 *this = *this + n;
|
||||
}
|
||||
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.
|
||||
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_);
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, civil_time a) {
|
||||
return impl::AbslHashValueImpl(T{}, std::move(h), a.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,
|
||||
};
|
||||
|
||||
CONSTEXPR_F weekday get_weekday(const civil_second& cs) noexcept {
|
||||
CONSTEXPR_D weekday k_weekday_by_mon_off[13] = {
|
||||
weekday::monday, weekday::tuesday, weekday::wednesday,
|
||||
weekday::thursday, weekday::friday, weekday::saturday,
|
||||
weekday::sunday, weekday::monday, weekday::tuesday,
|
||||
weekday::wednesday, weekday::thursday, weekday::friday,
|
||||
weekday::saturday,
|
||||
};
|
||||
CONSTEXPR_D int k_weekday_offsets[1 + 12] = {
|
||||
-1, 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4,
|
||||
};
|
||||
year_t wd = 2400 + (cs.year() % 400) - (cs.month() < 3);
|
||||
wd += wd / 4 - wd / 100 + wd / 400;
|
||||
wd += k_weekday_offsets[cs.month()] + cs.day();
|
||||
return k_weekday_by_mon_off[wd % 7 + 6];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
|
||||
CONSTEXPR_F civil_day next_weekday(civil_day cd, weekday wd) noexcept {
|
||||
CONSTEXPR_D weekday k_weekdays_forw[14] = {
|
||||
weekday::monday, weekday::tuesday, weekday::wednesday,
|
||||
weekday::thursday, weekday::friday, weekday::saturday,
|
||||
weekday::sunday, weekday::monday, weekday::tuesday,
|
||||
weekday::wednesday, weekday::thursday, weekday::friday,
|
||||
weekday::saturday, weekday::sunday,
|
||||
};
|
||||
weekday base = get_weekday(cd);
|
||||
for (int i = 0;; ++i) {
|
||||
if (base == k_weekdays_forw[i]) {
|
||||
for (int j = i + 1;; ++j) {
|
||||
if (wd == k_weekdays_forw[j]) {
|
||||
return cd + (j - i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CONSTEXPR_F civil_day prev_weekday(civil_day cd, weekday wd) noexcept {
|
||||
CONSTEXPR_D weekday k_weekdays_back[14] = {
|
||||
weekday::sunday, weekday::saturday, weekday::friday,
|
||||
weekday::thursday, weekday::wednesday, weekday::tuesday,
|
||||
weekday::monday, weekday::sunday, weekday::saturday,
|
||||
weekday::friday, weekday::thursday, weekday::wednesday,
|
||||
weekday::tuesday, weekday::monday,
|
||||
};
|
||||
weekday base = get_weekday(cd);
|
||||
for (int i = 0;; ++i) {
|
||||
if (base == k_weekdays_back[i]) {
|
||||
for (int j = i + 1;; ++j) {
|
||||
if (wd == k_weekdays_back[j]) {
|
||||
return cd - (j - i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CONSTEXPR_F int get_yearday(const civil_second& cs) noexcept {
|
||||
CONSTEXPR_D 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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#undef CONSTEXPR_M
|
||||
#undef CONSTEXPR_F
|
||||
#undef CONSTEXPR_D
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_CIVIL_TIME_DETAIL_H_
|
||||
460
Pods/abseil/absl/time/internal/cctz/include/cctz/time_zone.h
generated
Normal file
460
Pods/abseil/absl/time/internal/cctz/include/cctz/time_zone.h
generated
Normal file
@@ -0,0 +1,460 @@
|
||||
// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <ratio> // NOLINT: We use std::ratio in this header
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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>
|
||||
std::pair<time_point<seconds>, D> split_seconds(const time_point<D>& tp);
|
||||
std::pair<time_point<seconds>, seconds> split_seconds(
|
||||
const time_point<seconds>& tp);
|
||||
} // 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:
|
||||
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")
|
||||
};
|
||||
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,
|
||||
// respectively (all three times are equal if kind == UNIQUE). If any
|
||||
// of these three absolute times is outside the representable range of a
|
||||
// time_point<seconds> the field is set to its maximum/minimum value.
|
||||
//
|
||||
// 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;
|
||||
|
||||
// Finds the time of the next/previous offset change in this time zone.
|
||||
//
|
||||
// By definition, next_transition(tp, &trans) returns false when tp has
|
||||
// its maximum value, and prev_transition(tp, &trans) returns false
|
||||
// when tp has its minimum value. If the zone has no transitions, the
|
||||
// result will also be false no matter what the argument.
|
||||
//
|
||||
// Otherwise, when tp has its minimum value, next_transition(tp, &trans)
|
||||
// returns true and sets trans to the first recorded transition. Chains
|
||||
// of calls to next_transition()/prev_transition() will eventually return
|
||||
// false, but it is unspecified exactly when next_transition(tp, &trans)
|
||||
// jumps to false, or what time is set by prev_transition(tp, &trans) for
|
||||
// a very distant tp.
|
||||
//
|
||||
// Note: Enumeration of time-zone transitions is for informational purposes
|
||||
// only. Modern time-related code should not care about when offset changes
|
||||
// occur.
|
||||
//
|
||||
// Example:
|
||||
// cctz::time_zone nyc;
|
||||
// if (!cctz::load_time_zone("America/New_York", &nyc)) { ... }
|
||||
// const auto now = std::chrono::system_clock::now();
|
||||
// auto tp = cctz::time_point<cctz::seconds>::min();
|
||||
// cctz::time_zone::civil_transition trans;
|
||||
// while (tp <= now && nyc.next_transition(tp, &trans)) {
|
||||
// // transition: trans.from -> trans.to
|
||||
// tp = nyc.lookup(trans.to).trans;
|
||||
// }
|
||||
struct civil_transition {
|
||||
civil_second from; // the civil time we jump from
|
||||
civil_second to; // the civil time we jump to
|
||||
};
|
||||
bool next_transition(const time_point<seconds>& tp,
|
||||
civil_transition* trans) const;
|
||||
template <typename D>
|
||||
bool next_transition(const time_point<D>& tp, civil_transition* trans) const {
|
||||
return next_transition(detail::split_seconds(tp).first, trans);
|
||||
}
|
||||
bool prev_transition(const time_point<seconds>& tp,
|
||||
civil_transition* trans) const;
|
||||
template <typename D>
|
||||
bool prev_transition(const time_point<D>& tp, civil_transition* trans) const {
|
||||
return prev_transition(detail::split_seconds(tp).first, trans);
|
||||
}
|
||||
|
||||
// version() and description() provide additional information about the
|
||||
// time zone. The content of each of the returned strings is unspecified,
|
||||
// however, when the IANA Time Zone Database is the underlying data source
|
||||
// the version() string will be in the familar form (e.g, "2018e") or
|
||||
// empty when unavailable.
|
||||
//
|
||||
// Note: These functions are for informational or testing purposes only.
|
||||
std::string version() const; // empty when unknown
|
||||
std::string description() const;
|
||||
|
||||
// Relational operators.
|
||||
friend bool operator==(time_zone lhs, time_zone rhs) {
|
||||
return &lhs.effective_impl() == &rhs.effective_impl();
|
||||
}
|
||||
friend bool operator!=(time_zone lhs, time_zone rhs) { return !(lhs == rhs); }
|
||||
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, time_zone tz) {
|
||||
return H::combine(std::move(h), &tz.effective_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.
|
||||
time_zone fixed_time_zone(const seconds& offset);
|
||||
|
||||
// Returns a time zone representing the local time zone. Falls back to UTC.
|
||||
// Note: local_time_zone.name() may only be something like "localtime".
|
||||
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>;
|
||||
std::string format(const std::string&, const time_point<seconds>&,
|
||||
const femtoseconds&, const time_zone&);
|
||||
bool parse(const std::string&, const std::string&, const time_zone&,
|
||||
time_point<seconds>*, femtoseconds*, std::string* err = nullptr);
|
||||
template <typename Rep, std::intmax_t Denom>
|
||||
bool join_seconds(
|
||||
const time_point<seconds>& sec, const femtoseconds& fs,
|
||||
time_point<std::chrono::duration<Rep, std::ratio<1, Denom>>>* tpp);
|
||||
template <typename Rep, std::intmax_t Num>
|
||||
bool join_seconds(
|
||||
const time_point<seconds>& sec, const femtoseconds& fs,
|
||||
time_point<std::chrono::duration<Rep, std::ratio<Num, 1>>>* tpp);
|
||||
template <typename Rep>
|
||||
bool join_seconds(
|
||||
const time_point<seconds>& sec, const femtoseconds& fs,
|
||||
time_point<std::chrono::duration<Rep, std::ratio<1, 1>>>* tpp);
|
||||
bool join_seconds(const time_point<seconds>& sec, const femtoseconds&,
|
||||
time_point<seconds>* tpp);
|
||||
} // 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)
|
||||
// - %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.
|
||||
//
|
||||
// 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
|
||||
// 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
|
||||
// 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) {
|
||||
time_point<seconds> sec;
|
||||
detail::femtoseconds fs;
|
||||
return detail::parse(fmt, input, tz, &sec, &fs) &&
|
||||
detail::join_seconds(sec, fs, tpp);
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
// Split a time_point<D> into a time_point<seconds> and a D subseconds.
|
||||
// Undefined behavior if time_point<seconds> is not of sufficient range.
|
||||
// Note that this means it is UB to call cctz::time_zone::lookup(tp) or
|
||||
// cctz::format(fmt, tp, tz) with a time_point that is outside the range
|
||||
// of a 64-bit std::time_t.
|
||||
template <typename D>
|
||||
std::pair<time_point<seconds>, D> split_seconds(const time_point<D>& tp) {
|
||||
auto sec = std::chrono::time_point_cast<seconds>(tp);
|
||||
auto sub = tp - sec;
|
||||
if (sub.count() < 0) {
|
||||
sec -= seconds(1);
|
||||
sub += seconds(1);
|
||||
}
|
||||
return {sec, std::chrono::duration_cast<D>(sub)};
|
||||
}
|
||||
|
||||
inline std::pair<time_point<seconds>, seconds> split_seconds(
|
||||
const time_point<seconds>& tp) {
|
||||
return {tp, seconds::zero()};
|
||||
}
|
||||
|
||||
// Join a time_point<seconds> and femto subseconds into a time_point<D>.
|
||||
// Floors to the resolution of time_point<D>. Returns false if time_point<D>
|
||||
// is not of sufficient range.
|
||||
template <typename Rep, std::intmax_t Denom>
|
||||
bool join_seconds(
|
||||
const time_point<seconds>& sec, const femtoseconds& fs,
|
||||
time_point<std::chrono::duration<Rep, std::ratio<1, Denom>>>* tpp) {
|
||||
using D = std::chrono::duration<Rep, std::ratio<1, Denom>>;
|
||||
// TODO(#199): Return false if result unrepresentable as a time_point<D>.
|
||||
*tpp = std::chrono::time_point_cast<D>(sec);
|
||||
*tpp += std::chrono::duration_cast<D>(fs);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Rep, std::intmax_t Num>
|
||||
bool join_seconds(
|
||||
const time_point<seconds>& sec, const femtoseconds&,
|
||||
time_point<std::chrono::duration<Rep, std::ratio<Num, 1>>>* tpp) {
|
||||
using D = std::chrono::duration<Rep, std::ratio<Num, 1>>;
|
||||
auto count = sec.time_since_epoch().count();
|
||||
if (count >= 0 || count % Num == 0) {
|
||||
count /= Num;
|
||||
} else {
|
||||
count /= Num;
|
||||
count -= 1;
|
||||
}
|
||||
if (count > (std::numeric_limits<Rep>::max)()) return false;
|
||||
if (count < (std::numeric_limits<Rep>::min)()) return false;
|
||||
*tpp = time_point<D>() + D{static_cast<Rep>(count)};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename Rep>
|
||||
bool join_seconds(
|
||||
const time_point<seconds>& sec, const femtoseconds&,
|
||||
time_point<std::chrono::duration<Rep, std::ratio<1, 1>>>* tpp) {
|
||||
using D = std::chrono::duration<Rep, std::ratio<1, 1>>;
|
||||
auto count = sec.time_since_epoch().count();
|
||||
if (count > (std::numeric_limits<Rep>::max)()) return false;
|
||||
if (count < (std::numeric_limits<Rep>::min)()) return false;
|
||||
*tpp = time_point<D>() + D{static_cast<Rep>(count)};
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool join_seconds(const time_point<seconds>& sec, const femtoseconds&,
|
||||
time_point<seconds>* tpp) {
|
||||
*tpp = sec;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
|
||||
102
Pods/abseil/absl/time/internal/cctz/include/cctz/zone_info_source.h
generated
Normal file
102
Pods/abseil/absl/time/internal/cctz/include/cctz/zone_info_source.h
generated
Normal file
@@ -0,0 +1,102 @@
|
||||
// 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 ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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()
|
||||
|
||||
// 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 time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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<absl::time_internal::cctz::ZoneInfoSource> (*)(
|
||||
const std::string&,
|
||||
const std::function<std::unique_ptr<
|
||||
absl::time_internal::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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_ZONE_INFO_SOURCE_H_
|
||||
94
Pods/abseil/absl/time/internal/cctz/src/civil_time_detail.cc
generated
Normal file
94
Pods/abseil/absl/time/internal/cctz/src/civil_time_detail.cc
generated
Normal file
@@ -0,0 +1,94 @@
|
||||
// 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 "absl/time/internal/cctz/include/cctz/civil_time_detail.h"
|
||||
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
140
Pods/abseil/absl/time/internal/cctz/src/time_zone_fixed.cc
generated
Normal file
140
Pods/abseil/absl/time/internal/cctz/src/time_zone_fixed.cc
generated
Normal file
@@ -0,0 +1,140 @@
|
||||
// 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>
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
namespace {
|
||||
|
||||
// The prefix used for the internal names of fixed-offset zones.
|
||||
const char kFixedZonePrefix[] = "Fixed/UTC";
|
||||
|
||||
const char kDigits[] = "0123456789";
|
||||
|
||||
char* Format02d(char* p, int v) {
|
||||
*p++ = kDigits[(v / 10) % 10];
|
||||
*p++ = kDigits[v % 10];
|
||||
return p;
|
||||
}
|
||||
|
||||
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 == "UTC" || name == "UTC0") {
|
||||
*offset = seconds::zero();
|
||||
return true;
|
||||
}
|
||||
|
||||
const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
|
||||
const char* const ep = kFixedZonePrefix + prefix_len;
|
||||
if (name.size() != prefix_len + 9) // <prefix>+99:99:99
|
||||
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
|
||||
*offset = seconds(secs * (np[0] == '-' ? -1 : 1)); // "-" means west
|
||||
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";
|
||||
}
|
||||
int offset_seconds = static_cast<int>(offset.count());
|
||||
const char sign = (offset_seconds < 0 ? '-' : '+');
|
||||
int offset_minutes = offset_seconds / 60;
|
||||
offset_seconds %= 60;
|
||||
if (sign == '-') {
|
||||
if (offset_seconds > 0) {
|
||||
offset_seconds -= 60;
|
||||
offset_minutes += 1;
|
||||
}
|
||||
offset_seconds = -offset_seconds;
|
||||
offset_minutes = -offset_minutes;
|
||||
}
|
||||
int offset_hours = offset_minutes / 60;
|
||||
offset_minutes %= 60;
|
||||
const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
|
||||
char buf[prefix_len + sizeof("-24:00:00")];
|
||||
char* ep = std::copy_n(kFixedZonePrefix, prefix_len, buf);
|
||||
*ep++ = sign;
|
||||
ep = Format02d(ep, offset_hours);
|
||||
*ep++ = ':';
|
||||
ep = Format02d(ep, offset_minutes);
|
||||
*ep++ = ':';
|
||||
ep = Format02d(ep, offset_seconds);
|
||||
*ep++ = '\0';
|
||||
assert(ep == buf + sizeof(buf));
|
||||
return buf;
|
||||
}
|
||||
|
||||
std::string FixedOffsetToAbbr(const seconds& offset) {
|
||||
std::string abbr = FixedOffsetToName(offset);
|
||||
const std::size_t prefix_len = sizeof(kFixedZonePrefix) - 1;
|
||||
if (abbr.size() == prefix_len + 9) { // <prefix>+99:99:99
|
||||
abbr.erase(0, prefix_len); // +99:99:99
|
||||
abbr.erase(6, 1); // +99:9999
|
||||
abbr.erase(3, 1); // +999999
|
||||
if (abbr[5] == '0' && abbr[6] == '0') { // +999900
|
||||
abbr.erase(5, 2); // +9999
|
||||
if (abbr[3] == '0' && abbr[4] == '0') { // +9900
|
||||
abbr.erase(3, 2); // +99
|
||||
}
|
||||
}
|
||||
}
|
||||
return abbr;
|
||||
}
|
||||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
52
Pods/abseil/absl/time/internal/cctz/src/time_zone_fixed.h
generated
Normal file
52
Pods/abseil/absl/time/internal/cctz/src/time_zone_fixed.h
generated
Normal file
@@ -0,0 +1,52 @@
|
||||
// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_FIXED_H_
|
||||
1029
Pods/abseil/absl/time/internal/cctz/src/time_zone_format.cc
generated
Normal file
1029
Pods/abseil/absl/time/internal/cctz/src/time_zone_format.cc
generated
Normal file
@@ -0,0 +1,1029 @@
|
||||
// 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)
|
||||
#if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__VXWORKS__)
|
||||
#define HAS_STRPTIME 1 // Assume everyone else has strptime().
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAS_STRPTIME) && HAS_STRPTIME
|
||||
#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) && !defined(__OpenBSD__)
|
||||
#define _XOPEN_SOURCE 500 // Exposes definitions for SUSv2 (UNIX 98).
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/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 "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "time_zone_if.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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
|
||||
|
||||
// Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0).
|
||||
int ToTmWday(weekday wd) {
|
||||
switch (wd) {
|
||||
case weekday::sunday:
|
||||
return 0;
|
||||
case weekday::monday:
|
||||
return 1;
|
||||
case weekday::tuesday:
|
||||
return 2;
|
||||
case weekday::wednesday:
|
||||
return 3;
|
||||
case weekday::thursday:
|
||||
return 4;
|
||||
case weekday::friday:
|
||||
return 5;
|
||||
case weekday::saturday:
|
||||
return 6;
|
||||
}
|
||||
return 0; /*NOTREACHED*/
|
||||
}
|
||||
|
||||
// Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday.
|
||||
weekday FromTmWday(int tm_wday) {
|
||||
switch (tm_wday) {
|
||||
case 0:
|
||||
return weekday::sunday;
|
||||
case 1:
|
||||
return weekday::monday;
|
||||
case 2:
|
||||
return weekday::tuesday;
|
||||
case 3:
|
||||
return weekday::wednesday;
|
||||
case 4:
|
||||
return weekday::thursday;
|
||||
case 5:
|
||||
return weekday::friday;
|
||||
case 6:
|
||||
return weekday::saturday;
|
||||
}
|
||||
return weekday::sunday; /*NOTREACHED*/
|
||||
}
|
||||
|
||||
std::tm ToTM(const time_zone::absolute_lookup& al) {
|
||||
std::tm tm{};
|
||||
tm.tm_sec = al.cs.second();
|
||||
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;
|
||||
}
|
||||
|
||||
// Returns the week of the year [0:53] given a civil day and the day on
|
||||
// which weeks are defined to start.
|
||||
int ToWeek(const civil_day& cd, weekday week_start) {
|
||||
const civil_day d(cd.year() % 400, cd.month(), cd.day());
|
||||
return static_cast<int>((d - prev_weekday(civil_year(d), week_start)) / 7);
|
||||
}
|
||||
|
||||
const char kDigits[] = "0123456789";
|
||||
|
||||
// Formats a 64-bit integer in the given field width. Note that it is up
|
||||
// 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 = '+';
|
||||
if (offset < 0) {
|
||||
offset = -offset; // bounded by 24h so no overflow
|
||||
sign = '-';
|
||||
}
|
||||
const int seconds = offset % 60;
|
||||
const int minutes = (offset /= 60) % 60;
|
||||
const int hours = offset /= 60;
|
||||
const char sep = mode[0];
|
||||
const bool ext = (sep != '\0' && mode[1] == '*');
|
||||
const bool ccc = (ext && mode[2] == ':');
|
||||
if (ext && (!ccc || seconds != 0)) {
|
||||
ep = Format02d(ep, seconds);
|
||||
*--ep = sep;
|
||||
} else {
|
||||
// If we're not rendering seconds, sub-minute negative offsets
|
||||
// should get a positive sign (e.g., offset=-10s => "+00:00").
|
||||
if (hours == 0 && minutes == 0) sign = '+';
|
||||
}
|
||||
if (!ccc || minutes != 0 || seconds != 0) {
|
||||
ep = Format02d(ep, minutes);
|
||||
if (sep != '\0') *--ep = sep;
|
||||
}
|
||||
ep = Format02d(ep, hours);
|
||||
*--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:
|
||||
//
|
||||
// - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
|
||||
// - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
|
||||
// - %E#S - Seconds with # digits of fractional precision
|
||||
// - %E*S - Seconds with full fractional precision (a literal '*')
|
||||
// - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
|
||||
// - %ET - The RFC3339 "date-time" separator "T"
|
||||
//
|
||||
// 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.
|
||||
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;
|
||||
case 'U':
|
||||
bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::sunday));
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
break;
|
||||
case 'u':
|
||||
bp = Format64(ep, 0, tm.tm_wday ? tm.tm_wday : 7);
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
break;
|
||||
case 'W':
|
||||
bp = Format02d(ep, ToWeek(civil_day(al.cs), weekday::monday));
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
break;
|
||||
case 'w':
|
||||
bp = Format64(ep, 0, tm.tm_wday);
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
break;
|
||||
case 'H':
|
||||
bp = Format02d(ep, al.cs.hour());
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
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;
|
||||
case '%':
|
||||
result.push_back('%');
|
||||
break;
|
||||
}
|
||||
pending = ++cur;
|
||||
continue;
|
||||
}
|
||||
|
||||
// More complex specifiers that we handle ourselves.
|
||||
if (*cur == ':' && cur + 1 != end) {
|
||||
if (*(cur + 1) == 'z') {
|
||||
// Formats %:z.
|
||||
if (cur - 1 != pending) {
|
||||
FormatTM(&result, std::string(pending, cur - 1), tm);
|
||||
}
|
||||
bp = FormatOffset(ep, al.offset, ":");
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
pending = cur += 2;
|
||||
continue;
|
||||
}
|
||||
if (*(cur + 1) == ':' && cur + 2 != end) {
|
||||
if (*(cur + 2) == 'z') {
|
||||
// Formats %::z.
|
||||
if (cur - 1 != pending) {
|
||||
FormatTM(&result, std::string(pending, cur - 1), tm);
|
||||
}
|
||||
bp = FormatOffset(ep, al.offset, ":*");
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
pending = cur += 3;
|
||||
continue;
|
||||
}
|
||||
if (*(cur + 2) == ':' && cur + 3 != end) {
|
||||
if (*(cur + 3) == 'z') {
|
||||
// Formats %:::z.
|
||||
if (cur - 1 != pending) {
|
||||
FormatTM(&result, std::string(pending, cur - 1), tm);
|
||||
}
|
||||
bp = FormatOffset(ep, al.offset, ":*:");
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
pending = cur += 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop if there is no E modifier.
|
||||
if (*cur != 'E' || ++cur == end) continue;
|
||||
|
||||
// Format our extensions.
|
||||
if (*cur == 'T') {
|
||||
// Formats %ET.
|
||||
if (cur - 2 != pending) {
|
||||
FormatTM(&result, std::string(pending, cur - 2), tm);
|
||||
}
|
||||
result.append("T");
|
||||
pending = ++cur;
|
||||
} else if (*cur == 'z') {
|
||||
// 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;
|
||||
} else if (*cur == '*' && cur + 1 != end && *(cur + 1) == 'z') {
|
||||
// Formats %E*z.
|
||||
if (cur - 2 != pending) {
|
||||
FormatTM(&result, std::string(pending, cur - 2), tm);
|
||||
}
|
||||
bp = FormatOffset(ep, al.offset, ":*");
|
||||
result.append(bp, static_cast<std::size_t>(ep - bp));
|
||||
pending = cur += 2;
|
||||
} else if (*cur == '*' && cur + 1 != end &&
|
||||
(*(cur + 1) == 'S' || *(cur + 1) == 'f')) {
|
||||
// Formats %E*S or %E*F.
|
||||
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) {
|
||||
const char first = *dp++;
|
||||
if (first == '+' || first == '-') {
|
||||
char sep = mode[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);
|
||||
if (bp != nullptr && bp - ap == 2) {
|
||||
dp = bp;
|
||||
if (sep != '\0' && *bp == sep) ++bp;
|
||||
const char* cp = ParseInt(bp, 2, 0, 59, &seconds);
|
||||
if (cp != nullptr && cp - bp == 2) dp = cp;
|
||||
}
|
||||
*offset = ((hours * 60 + minutes) * 60) + seconds;
|
||||
if (first == '-') *offset = -*offset;
|
||||
} else {
|
||||
dp = nullptr;
|
||||
}
|
||||
} else if (first == 'Z' || first == 'z') { // Zulu
|
||||
*offset = 0;
|
||||
} else {
|
||||
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.
|
||||
bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) {
|
||||
const civil_year y(*year % 400);
|
||||
civil_day cd = prev_weekday(y, week_start); // week 0
|
||||
cd = next_weekday(cd - 1, FromTmWday(tm->tm_wday)) + (week_num * 7);
|
||||
if (const year_t shift = cd.year() - y.year()) {
|
||||
if (shift > 0) {
|
||||
if (*year > std::numeric_limits<year_t>::max() - shift) return false;
|
||||
} else {
|
||||
if (*year < std::numeric_limits<year_t>::min() - shift) return false;
|
||||
}
|
||||
*year += shift;
|
||||
}
|
||||
tm->tm_mon = cd.month() - 1;
|
||||
tm->tm_mday = cd.day();
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Uses strptime(3) to parse the given input. Supports the same extended
|
||||
// format specifiers as format(), although %E#S and %E*S are treated
|
||||
// identically (and similarly for %E#f and %E*f). %Ez and %E*z also accept
|
||||
// the same inputs. %ET accepts either 'T' or 't'.
|
||||
//
|
||||
// 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;
|
||||
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;
|
||||
week_num = -1;
|
||||
continue;
|
||||
case 'd':
|
||||
case 'e':
|
||||
data = ParseInt(data, 2, 1, 31, &tm.tm_mday);
|
||||
week_num = -1;
|
||||
continue;
|
||||
case 'U':
|
||||
data = ParseInt(data, 0, 0, 53, &week_num);
|
||||
week_start = weekday::sunday;
|
||||
continue;
|
||||
case 'W':
|
||||
data = ParseInt(data, 0, 0, 53, &week_num);
|
||||
week_start = weekday::monday;
|
||||
continue;
|
||||
case 'u':
|
||||
data = ParseInt(data, 0, 1, 7, &tm.tm_wday);
|
||||
if (data != nullptr) tm.tm_wday %= 7;
|
||||
continue;
|
||||
case 'w':
|
||||
data = ParseInt(data, 0, 0, 6, &tm.tm_wday);
|
||||
continue;
|
||||
case '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;
|
||||
case ':':
|
||||
if (fmt[0] == 'z' ||
|
||||
(fmt[0] == ':' &&
|
||||
(fmt[1] == 'z' || (fmt[1] == ':' && fmt[2] == 'z')))) {
|
||||
data = ParseOffset(data, ":", &offset);
|
||||
if (data != nullptr) saw_offset = true;
|
||||
fmt += (fmt[0] == 'z') ? 1 : (fmt[1] == 'z') ? 2 : 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case '%':
|
||||
data = (*data == '%' ? data + 1 : nullptr);
|
||||
continue;
|
||||
case 'E':
|
||||
if (fmt[0] == 'T') {
|
||||
if (*data == 'T' || *data == 't') {
|
||||
++data;
|
||||
++fmt;
|
||||
} else {
|
||||
data = nullptr;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (fmt[0] == 'z' || (fmt[0] == '*' && fmt[1] == 'z')) {
|
||||
data = ParseOffset(data, ":", &offset);
|
||||
if (data != nullptr) saw_offset = true;
|
||||
fmt += (fmt[0] == 'z') ? 1 : 2;
|
||||
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;
|
||||
}
|
||||
if (fmt[0] == '*' && fmt[1] == 'f') {
|
||||
if (data != nullptr && std::isdigit(*data)) {
|
||||
data = ParseSubSeconds(data, &subseconds);
|
||||
}
|
||||
fmt += 2;
|
||||
continue;
|
||||
}
|
||||
if (fmt[0] == '4' && fmt[1] == 'Y') {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Compute year, tm.tm_mon and tm.tm_mday if we parsed a week number.
|
||||
if (week_num != -1) {
|
||||
if (!FromWeek(week_num, week_start, &year, &tm)) {
|
||||
if (err != nullptr) *err = "Out-of-range field";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const int month = tm.tm_mon + 1;
|
||||
civil_second cs(year, month, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
|
||||
// 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 (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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
47
Pods/abseil/absl/time/internal/cctz/src/time_zone_if.cc
generated
Normal file
47
Pods/abseil/absl/time/internal/cctz/src/time_zone_if.cc
generated
Normal file
@@ -0,0 +1,47 @@
|
||||
// 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 "absl/base/config.h"
|
||||
#include "time_zone_info.h"
|
||||
#include "time_zone_libc.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
std::unique_ptr<TimeZoneIf> TimeZoneIf::UTC() { return TimeZoneInfo::UTC(); }
|
||||
|
||||
std::unique_ptr<TimeZoneIf> TimeZoneIf::Make(const std::string& name) {
|
||||
// Support "libc:localtime" and "libc:*" to access the legacy
|
||||
// localtime and UTC support respectively from the C library.
|
||||
// NOTE: The "libc:*" zones are internal, test-only interfaces, and
|
||||
// are subject to change/removal without notice. Do not use them.
|
||||
if (name.compare(0, 5, "libc:") == 0) {
|
||||
return TimeZoneLibC::Make(name.substr(5));
|
||||
}
|
||||
|
||||
// Otherwise use the "zoneinfo" implementation.
|
||||
return TimeZoneInfo::Make(name);
|
||||
}
|
||||
|
||||
// Defined out-of-line to avoid emitting a weak vtable in all TUs.
|
||||
TimeZoneIf::~TimeZoneIf() {}
|
||||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
80
Pods/abseil/absl/time/internal/cctz/src/time_zone_if.h
generated
Normal file
80
Pods/abseil/absl/time/internal/cctz/src/time_zone_if.h
generated
Normal file
@@ -0,0 +1,80 @@
|
||||
// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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:
|
||||
// Factory functions for TimeZoneIf implementations.
|
||||
static std::unique_ptr<TimeZoneIf> UTC(); // never fails
|
||||
static std::unique_ptr<TimeZoneIf> Make(const std::string& name);
|
||||
|
||||
virtual ~TimeZoneIf();
|
||||
|
||||
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 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() = default;
|
||||
TimeZoneIf(const TimeZoneIf&) = delete;
|
||||
TimeZoneIf& operator=(const TimeZoneIf&) = delete;
|
||||
};
|
||||
|
||||
// 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, and that the results are representable.
|
||||
// (That is, that they share an epoch, which is required since C++20.)
|
||||
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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IF_H_
|
||||
115
Pods/abseil/absl/time/internal/cctz/src/time_zone_impl.cc
generated
Normal file
115
Pods/abseil/absl/time/internal/cctz/src/time_zone_impl.cc
generated
Normal file
@@ -0,0 +1,115 @@
|
||||
// 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"
|
||||
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "time_zone_fixed.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the new time zone (outside the lock).
|
||||
std::unique_ptr<const Impl> new_impl(new Impl(name));
|
||||
|
||||
// Add the new time zone to the map.
|
||||
std::lock_guard<std::mutex> lock(TimeZoneMutex());
|
||||
if (time_zone_map == nullptr) time_zone_map = new TimeZoneImplByName;
|
||||
const Impl*& impl = (*time_zone_map)[name];
|
||||
if (impl == nullptr) { // this thread won any load race
|
||||
impl = new_impl->zone_ ? new_impl.release() : utc_impl;
|
||||
}
|
||||
*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) {
|
||||
// Existing time_zone::Impl* entries are in the wild, so we can't delete
|
||||
// them. Instead, we move them to a private container, where they are
|
||||
// logically unreachable but not "leaked". Future requests will result
|
||||
// in reloading the data.
|
||||
static auto* cleared = new std::deque<const time_zone::Impl*>;
|
||||
for (const auto& element : *time_zone_map) {
|
||||
cleared->push_back(element.second);
|
||||
}
|
||||
time_zone_map->clear();
|
||||
}
|
||||
}
|
||||
|
||||
time_zone::Impl::Impl() : name_("UTC"), zone_(TimeZoneIf::UTC()) {}
|
||||
|
||||
time_zone::Impl::Impl(const std::string& name)
|
||||
: name_(name), zone_(TimeZoneIf::Make(name_)) {}
|
||||
|
||||
const time_zone::Impl* time_zone::Impl::UTCImpl() {
|
||||
static const Impl* utc_impl = new Impl;
|
||||
return utc_impl;
|
||||
}
|
||||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
97
Pods/abseil/absl/time/internal/cctz/src/time_zone_impl.h
generated
Normal file
97
Pods/abseil/absl/time/internal/cctz/src/time_zone_impl.h
generated
Normal file
@@ -0,0 +1,97 @@
|
||||
// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
#include "time_zone_if.h"
|
||||
#include "time_zone_info.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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.
|
||||
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.
|
||||
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:
|
||||
Impl();
|
||||
explicit Impl(const std::string& name);
|
||||
Impl(const Impl&) = delete;
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
|
||||
static const Impl* UTCImpl();
|
||||
|
||||
const std::string name_;
|
||||
std::unique_ptr<TimeZoneIf> zone_;
|
||||
};
|
||||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_IMPL_H_
|
||||
1070
Pods/abseil/absl/time/internal/cctz/src/time_zone_info.cc
generated
Normal file
1070
Pods/abseil/absl/time/internal/cctz/src/time_zone_info.cc
generated
Normal file
@@ -0,0 +1,1070 @@
|
||||
// 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
|
||||
// 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 <fstream>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "time_zone_fixed.h"
|
||||
#include "time_zone_posix.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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,
|
||||
};
|
||||
|
||||
// Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat).
|
||||
inline int ToPosixWeekday(weekday wd) {
|
||||
switch (wd) {
|
||||
case weekday::sunday:
|
||||
return 0;
|
||||
case weekday::monday:
|
||||
return 1;
|
||||
case weekday::tuesday:
|
||||
return 2;
|
||||
case weekday::wednesday:
|
||||
return 3;
|
||||
case weekday::thursday:
|
||||
return 4;
|
||||
case weekday::friday:
|
||||
return 5;
|
||||
case weekday::saturday:
|
||||
return 6;
|
||||
}
|
||||
return 0; /*NOTREACHED*/
|
||||
}
|
||||
|
||||
// Single-byte, unsigned numeric values are encoded directly.
|
||||
inline std::uint_fast8_t Decode8(const char* cp) {
|
||||
return static_cast<std::uint_fast8_t>(*cp) & 0xff;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
// Builds the in-memory header using the raw bytes from the file.
|
||||
bool 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 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;
|
||||
}
|
||||
|
||||
// Does the rule for future transitions call for year-round daylight time?
|
||||
// See tz/zic.c:stringzone() for the details on how such rules are encoded.
|
||||
bool AllYearDST(const PosixTimeZone& posix) {
|
||||
if (posix.dst_start.date.fmt != PosixTransition::N) return false;
|
||||
if (posix.dst_start.date.n.day != 0) return false;
|
||||
if (posix.dst_start.time.offset != 0) return false;
|
||||
|
||||
if (posix.dst_end.date.fmt != PosixTransition::J) return false;
|
||||
if (posix.dst_end.date.j.day != kDaysPerYear[0]) return false;
|
||||
const auto offset = posix.std_offset - posix.dst_offset;
|
||||
if (posix.dst_end.time.offset + offset != kSecsPerDay) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// Find/make a transition type with these attributes.
|
||||
bool TimeZoneInfo::GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
|
||||
const std::string& abbr,
|
||||
std::uint_least8_t* index) {
|
||||
std::size_t type_index = 0;
|
||||
std::size_t abbr_index = abbreviations_.size();
|
||||
for (; type_index != transition_types_.size(); ++type_index) {
|
||||
const TransitionType& tt(transition_types_[type_index]);
|
||||
const char* tt_abbr = &abbreviations_[tt.abbr_index];
|
||||
if (tt_abbr == abbr) abbr_index = tt.abbr_index;
|
||||
if (tt.utc_offset == utc_offset && tt.is_dst == is_dst) {
|
||||
if (abbr_index == tt.abbr_index) break; // reuse
|
||||
}
|
||||
}
|
||||
if (type_index > 255 || abbr_index > 255) {
|
||||
// No index space (8 bits) available for a new type or abbreviation.
|
||||
return false;
|
||||
}
|
||||
if (type_index == transition_types_.size()) {
|
||||
TransitionType& tt(*transition_types_.emplace(transition_types_.end()));
|
||||
tt.utc_offset = static_cast<std::int_least32_t>(utc_offset);
|
||||
tt.is_dst = is_dst;
|
||||
if (abbr_index == abbreviations_.size()) {
|
||||
abbreviations_.append(abbr);
|
||||
abbreviations_.append(1, '\0');
|
||||
}
|
||||
tt.abbr_index = static_cast<std::uint_least8_t>(abbr_index);
|
||||
}
|
||||
*index = static_cast<std::uint_least8_t>(type_index);
|
||||
return true;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
if (future_spec_.empty()) return true; // last transition prevails
|
||||
|
||||
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;
|
||||
|
||||
if (AllYearDST(posix)) { // dst 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, dst_ti);
|
||||
}
|
||||
|
||||
// Extend the transitions for an additional 401 years using the future
|
||||
// specification. Years beyond those can be handled by mapping back to
|
||||
// a cycle-equivalent year within that range. Note that we need 401
|
||||
// (well, at least the first transition in the 401st year) so that the
|
||||
// end of the 400th year is mapped back to an extended year. And first
|
||||
// we may also need two additional transitions for the current year.
|
||||
transitions_.reserve(transitions_.size() + 2 + 401 * 2);
|
||||
extended_ = true;
|
||||
|
||||
const Transition& last(transitions_.back());
|
||||
const std::int_fast64_t last_time = last.unix_time;
|
||||
const TransitionType& last_tt(transition_types_[last.type_index]);
|
||||
last_year_ = LocalTime(last_time, last_tt).cs.year();
|
||||
bool leap_year = IsLeap(last_year_);
|
||||
const civil_second jan1(last_year_);
|
||||
std::int_fast64_t jan1_time = jan1 - civil_second();
|
||||
int jan1_weekday = ToPosixWeekday(get_weekday(jan1));
|
||||
|
||||
Transition dst = {0, dst_ti, civil_second(), civil_second()};
|
||||
Transition std = {0, std_ti, civil_second(), civil_second()};
|
||||
for (const year_t limit = last_year_ + 401;; ++last_year_) {
|
||||
auto dst_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_start);
|
||||
auto std_trans_off = TransOffset(leap_year, jan1_weekday, posix.dst_end);
|
||||
dst.unix_time = jan1_time + dst_trans_off - posix.std_offset;
|
||||
std.unix_time = jan1_time + std_trans_off - posix.dst_offset;
|
||||
const auto* ta = dst.unix_time < std.unix_time ? &dst : &std;
|
||||
const auto* tb = dst.unix_time < std.unix_time ? &std : &dst;
|
||||
if (last_time < tb->unix_time) {
|
||||
if (last_time < ta->unix_time) transitions_.push_back(*ta);
|
||||
transitions_.push_back(*tb);
|
||||
}
|
||||
if (last_year_ == limit) break;
|
||||
jan1_time += kSecsPerYear[leap_year];
|
||||
jan1_weekday = (jan1_weekday + kDaysPerYear[leap_year]) % 7;
|
||||
leap_year = !leap_year && IsLeap(last_year_ + 1);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using FilePtr = std::unique_ptr<FILE, int (*)(FILE*)>;
|
||||
|
||||
// fopen(3) adaptor.
|
||||
inline FilePtr FOpen(const char* path, const char* mode) {
|
||||
#if defined(_MSC_VER)
|
||||
FILE* fp;
|
||||
if (fopen_s(&fp, path, mode) != 0) fp = nullptr;
|
||||
return FilePtr(fp, fclose);
|
||||
#else
|
||||
// TODO: Enable the close-on-exec flag.
|
||||
return FilePtr(fopen(path, mode), fclose);
|
||||
#endif
|
||||
}
|
||||
|
||||
// A stdio(3)-backed implementation of ZoneInfoSource.
|
||||
class FileZoneInfoSource : public ZoneInfoSource {
|
||||
public:
|
||||
static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
|
||||
|
||||
std::size_t Read(void* ptr, std::size_t size) override {
|
||||
size = std::min(size, len_);
|
||||
std::size_t nread = fread(ptr, 1, size, fp_.get());
|
||||
len_ -= nread;
|
||||
return nread;
|
||||
}
|
||||
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(
|
||||
FilePtr fp, std::size_t len = std::numeric_limits<std::size_t>::max())
|
||||
: fp_(std::move(fp)), len_(len) {}
|
||||
|
||||
private:
|
||||
FilePtr fp_;
|
||||
std::size_t len_;
|
||||
};
|
||||
|
||||
std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open(
|
||||
const std::string& name) {
|
||||
// Use of the "file:" prefix is intended for testing purposes only.
|
||||
const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
|
||||
|
||||
// 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
|
||||
}
|
||||
path.append(name, pos, std::string::npos);
|
||||
|
||||
// Open the zoneinfo file.
|
||||
auto fp = FOpen(path.c_str(), "rb");
|
||||
if (fp == nullptr) return nullptr;
|
||||
return std::unique_ptr<ZoneInfoSource>(new FileZoneInfoSource(std::move(fp)));
|
||||
}
|
||||
|
||||
class AndroidZoneInfoSource : public FileZoneInfoSource {
|
||||
public:
|
||||
static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
|
||||
std::string Version() const override { return version_; }
|
||||
|
||||
private:
|
||||
explicit AndroidZoneInfoSource(FilePtr fp, std::size_t len,
|
||||
std::string version)
|
||||
: FileZoneInfoSource(std::move(fp), len), version_(std::move(version)) {}
|
||||
std::string version_;
|
||||
};
|
||||
|
||||
std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open(
|
||||
const std::string& name) {
|
||||
// Use of the "file:" prefix is intended for testing purposes only.
|
||||
const std::size_t pos = (name.compare(0, 5, "file:") == 0) ? 5 : 0;
|
||||
|
||||
// See Android's libc/tzcode/bionic.cpp for additional information.
|
||||
for (const char* tzdata : {"/apex/com.android.tzdata/etc/tz/tzdata",
|
||||
"/data/misc/zoneinfo/current/tzdata",
|
||||
"/system/usr/share/zoneinfo/tzdata"}) {
|
||||
auto fp = FOpen(tzdata, "rb");
|
||||
if (fp == nullptr) continue;
|
||||
|
||||
char hbuf[24]; // covers header.zonetab_offset too
|
||||
if (fread(hbuf, 1, sizeof(hbuf), fp.get()) != sizeof(hbuf)) continue;
|
||||
if (strncmp(hbuf, "tzdata", 6) != 0) continue;
|
||||
const char* vers = (hbuf[11] == '\0') ? hbuf + 6 : "";
|
||||
const std::int_fast32_t index_offset = Decode32(hbuf + 12);
|
||||
const std::int_fast32_t data_offset = Decode32(hbuf + 16);
|
||||
if (index_offset < 0 || data_offset < index_offset) continue;
|
||||
if (fseek(fp.get(), static_cast<long>(index_offset), SEEK_SET) != 0)
|
||||
continue;
|
||||
|
||||
char ebuf[52]; // covers entry.unused too
|
||||
const std::size_t index_size =
|
||||
static_cast<std::size_t>(data_offset - index_offset);
|
||||
const std::size_t zonecnt = index_size / sizeof(ebuf);
|
||||
if (zonecnt * sizeof(ebuf) != index_size) continue;
|
||||
for (std::size_t i = 0; i != zonecnt; ++i) {
|
||||
if (fread(ebuf, 1, sizeof(ebuf), fp.get()) != sizeof(ebuf)) break;
|
||||
const std::int_fast32_t start = data_offset + Decode32(ebuf + 40);
|
||||
const std::int_fast32_t length = Decode32(ebuf + 44);
|
||||
if (start < 0 || length < 0) break;
|
||||
ebuf[40] = '\0'; // ensure zone name is NUL terminated
|
||||
if (strcmp(name.c_str() + pos, ebuf) == 0) {
|
||||
if (fseek(fp.get(), static_cast<long>(start), SEEK_SET) != 0) break;
|
||||
return std::unique_ptr<ZoneInfoSource>(new AndroidZoneInfoSource(
|
||||
std::move(fp), static_cast<std::size_t>(length), vers));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// A zoneinfo source for use inside Fuchsia components. This attempts to
|
||||
// read zoneinfo files from one of several known paths in a component's
|
||||
// incoming namespace. [Config data][1] is preferred, but package-specific
|
||||
// resources are also supported.
|
||||
//
|
||||
// Fuchsia's implementation supports `FileZoneInfoSource::Version()`.
|
||||
//
|
||||
// [1]:
|
||||
// https://fuchsia.dev/fuchsia-src/development/components/data#using_config_data_in_your_component
|
||||
class FuchsiaZoneInfoSource : public FileZoneInfoSource {
|
||||
public:
|
||||
static std::unique_ptr<ZoneInfoSource> Open(const std::string& name);
|
||||
std::string Version() const override { return version_; }
|
||||
|
||||
private:
|
||||
explicit FuchsiaZoneInfoSource(FilePtr fp, std::string version)
|
||||
: FileZoneInfoSource(std::move(fp)), version_(std::move(version)) {}
|
||||
std::string version_;
|
||||
};
|
||||
|
||||
std::unique_ptr<ZoneInfoSource> FuchsiaZoneInfoSource::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;
|
||||
|
||||
// Prefixes where a Fuchsia component might find zoneinfo files,
|
||||
// in descending order of preference.
|
||||
const auto kTzdataPrefixes = {
|
||||
// The tzdata from `config-data`.
|
||||
"/config/data/tzdata/",
|
||||
// The tzdata bundled in the component's package.
|
||||
"/pkg/data/tzdata/",
|
||||
// General data storage.
|
||||
"/data/tzdata/",
|
||||
// The recommended path for routed-in tzdata files.
|
||||
// See for details:
|
||||
// https://fuchsia.dev/fuchsia-src/concepts/process/namespaces?hl=en#typical_directory_structure
|
||||
"/config/tzdata/",
|
||||
};
|
||||
const auto kEmptyPrefix = {""};
|
||||
const bool name_absolute = (pos != name.size() && name[pos] == '/');
|
||||
const auto prefixes = name_absolute ? kEmptyPrefix : kTzdataPrefixes;
|
||||
|
||||
// Fuchsia builds place zoneinfo files at "<prefix><format><name>".
|
||||
for (const std::string prefix : prefixes) {
|
||||
std::string path = prefix;
|
||||
if (!prefix.empty()) path += "zoneinfo/tzif2/"; // format
|
||||
path.append(name, pos, std::string::npos);
|
||||
|
||||
auto fp = FOpen(path.c_str(), "rb");
|
||||
if (fp == nullptr) continue;
|
||||
|
||||
std::string version;
|
||||
if (!prefix.empty()) {
|
||||
// Fuchsia builds place the version in "<prefix>revision.txt".
|
||||
std::ifstream version_stream(prefix + "revision.txt");
|
||||
if (version_stream.is_open()) {
|
||||
// revision.txt should contain no newlines, but to be
|
||||
// defensive we read just the first line.
|
||||
std::getline(version_stream, version);
|
||||
}
|
||||
}
|
||||
|
||||
return std::unique_ptr<ZoneInfoSource>(
|
||||
new FuchsiaZoneInfoSource(std::move(fp), std::move(version)));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // 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;
|
||||
|
||||
// We temporarily add some redundant, contemporary (2015 through 2025)
|
||||
// transitions for performance reasons. See TimeZoneInfo::LocalTime().
|
||||
// TODO: Fix the performance issue and remove the extra transitions.
|
||||
transitions_.clear();
|
||||
transitions_.reserve(12);
|
||||
for (const std::int_fast64_t unix_time : {
|
||||
-(1LL << 59), // a "first half" transition
|
||||
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);
|
||||
abbreviations_.append(1, '\0');
|
||||
future_spec_.clear(); // never needed for a fixed-offset zone
|
||||
extended_ = false;
|
||||
|
||||
tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
|
||||
tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
|
||||
|
||||
transitions_.shrink_to_fit();
|
||||
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;
|
||||
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.
|
||||
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.
|
||||
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.
|
||||
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 += (time_len + 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.
|
||||
auto get_char = [](ZoneInfoSource* azip) -> int {
|
||||
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 we did not find version information during the standard loading
|
||||
// process (as of tzh_version '3' that is unsupported), then ask the
|
||||
// ZoneInfoSource for any out-of-bound version string it may be privy to.
|
||||
if (version_.empty()) {
|
||||
version_ = zip->Version();
|
||||
}
|
||||
|
||||
// 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()));
|
||||
tr.unix_time = -(1LL << 59); // -18267312070-10-26T17:01:52+00:00
|
||||
tr.type_index = default_transition_type_;
|
||||
}
|
||||
|
||||
// Extend the transitions using the future specification.
|
||||
if (!ExtendTransitions()) return false;
|
||||
|
||||
// Ensure that there is always a transition in the second half of the
|
||||
// time line (the first half is handled above) so that the signed
|
||||
// difference between a civil_second and the civil_second of its
|
||||
// previous transition is always representable, without overflow.
|
||||
const Transition& last(transitions_.back());
|
||||
if (last.unix_time < 0) {
|
||||
const std::uint_fast8_t type_index = last.type_index;
|
||||
Transition& tr(*transitions_.emplace(transitions_.end()));
|
||||
tr.unix_time = 2147483647; // 2038-01-19T03:14:07+00:00
|
||||
tr.type_index = type_index;
|
||||
}
|
||||
|
||||
// Compute the local civil time for each transition and the preceding
|
||||
// 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_) {
|
||||
tt.civil_max = LocalTime(seconds::max().count(), tt).cs;
|
||||
tt.civil_min = LocalTime(seconds::min().count(), tt).cs;
|
||||
}
|
||||
|
||||
transitions_.shrink_to_fit();
|
||||
return true;
|
||||
}
|
||||
|
||||
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(
|
||||
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;
|
||||
if (auto z = FuchsiaZoneInfoSource::Open(n)) return z;
|
||||
return nullptr;
|
||||
});
|
||||
return zip != nullptr && Load(zip.get());
|
||||
}
|
||||
|
||||
std::unique_ptr<TimeZoneInfo> TimeZoneInfo::UTC() {
|
||||
auto tz = std::unique_ptr<TimeZoneInfo>(new TimeZoneInfo);
|
||||
tz->ResetToBuiltinUTC(seconds::zero());
|
||||
return tz;
|
||||
}
|
||||
|
||||
std::unique_ptr<TimeZoneInfo> TimeZoneInfo::Make(const std::string& name) {
|
||||
auto tz = std::unique_ptr<TimeZoneInfo>(new TimeZoneInfo);
|
||||
if (!tz->Load(name)) tz.reset(); // fallback to UTC
|
||||
return tz;
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (c4_shift > seconds::max().count() / kSecsPer400Years) {
|
||||
cl.pre = cl.trans = cl.post = time_point<seconds>::max();
|
||||
} else {
|
||||
const auto offset = seconds(c4_shift * kSecsPer400Years);
|
||||
const auto limit = time_point<seconds>::max() - offset;
|
||||
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(
|
||||
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;
|
||||
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_]);
|
||||
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_) {
|
||||
const year_t shift = (cs.year() - last_year_ - 1) / 400 + 1;
|
||||
return TimeLocal(YearShift(cs, shift * -400), shift);
|
||||
}
|
||||
const TransitionType& tt(transition_types_[tr->type_index]);
|
||||
if (cs > tt.civil_max) return MakeUnique(time_point<seconds>::max());
|
||||
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();
|
||||
}
|
||||
|
||||
bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp,
|
||||
time_zone::civil_transition* trans) const {
|
||||
if (transitions_.empty()) return false;
|
||||
const Transition* begin = &transitions_[0];
|
||||
const Transition* end = begin + transitions_.size();
|
||||
if (begin->unix_time <= -(1LL << 59)) {
|
||||
// Do not report the BIG_BANG found in some zoneinfo data as it is
|
||||
// really a sentinel, not a transition. See pre-2018f tz/zic.c.
|
||||
++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());
|
||||
for (; tr != end; ++tr) { // skip no-op transitions
|
||||
std::uint_fast8_t prev_type_index =
|
||||
(tr == begin) ? default_transition_type_ : tr[-1].type_index;
|
||||
if (!EquivTransitions(prev_type_index, tr[0].type_index)) break;
|
||||
}
|
||||
// When tr == end we return false, ignoring future_spec_.
|
||||
if (tr == end) return false;
|
||||
trans->from = tr->prev_civil_sec + 1;
|
||||
trans->to = tr->civil_sec;
|
||||
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)) {
|
||||
// Do not report the BIG_BANG found in some zoneinfo data as it is
|
||||
// really a sentinel, not a transition. See pre-2018f tz/zic.c.
|
||||
++begin;
|
||||
}
|
||||
std::int_fast64_t unix_time = ToUnixSeconds(tp);
|
||||
if (FromUnixSeconds(unix_time) != tp) {
|
||||
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
|
||||
}
|
||||
const Transition target = {unix_time, 0, civil_second(), civil_second()};
|
||||
const Transition* tr =
|
||||
std::lower_bound(begin, end, target, Transition::ByUnixTime());
|
||||
for (; tr != begin; --tr) { // skip no-op transitions
|
||||
std::uint_fast8_t prev_type_index =
|
||||
(tr - 1 == begin) ? default_transition_type_ : tr[-2].type_index;
|
||||
if (!EquivTransitions(prev_type_index, tr[-1].type_index)) break;
|
||||
}
|
||||
// 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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
128
Pods/abseil/absl/time/internal/cctz/src/time_zone_info.h
generated
Normal file
128
Pods/abseil/absl/time/internal/cctz/src/time_zone_info.h
generated
Normal file
@@ -0,0 +1,128 @@
|
||||
// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
|
||||
#include "time_zone_if.h"
|
||||
#include "tzfile.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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:
|
||||
// Factories.
|
||||
static std::unique_ptr<TimeZoneInfo> UTC(); // never fails
|
||||
static std::unique_ptr<TimeZoneInfo> Make(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;
|
||||
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:
|
||||
TimeZoneInfo() = default;
|
||||
TimeZoneInfo(const TimeZoneInfo&) = delete;
|
||||
TimeZoneInfo& operator=(const TimeZoneInfo&) = delete;
|
||||
|
||||
bool GetTransitionType(std::int_fast32_t utc_offset, bool is_dst,
|
||||
const std::string& abbr, std::uint_least8_t* index);
|
||||
bool EquivTransitions(std::uint_fast8_t tt1_index,
|
||||
std::uint_fast8_t tt2_index) const;
|
||||
bool ExtendTransitions();
|
||||
|
||||
bool ResetToBuiltinUTC(const seconds& offset);
|
||||
bool Load(const std::string& name);
|
||||
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,
|
||||
year_t c4_shift) const;
|
||||
|
||||
std::vector<Transition> transitions_; // ordered by unix_time and civil_sec
|
||||
std::vector<TransitionType> transition_types_; // distinct transition types
|
||||
std::uint_fast8_t default_transition_type_; // for before first transition
|
||||
std::string abbreviations_; // all the NUL-terminated abbreviations
|
||||
|
||||
std::string version_; // the tzdata version if available
|
||||
std::string 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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
|
||||
333
Pods/abseil/absl/time/internal/cctz/src/time_zone_libc.cc
generated
Normal file
333
Pods/abseil/absl/time/internal/cctz/src/time_zone_libc.cc
generated
Normal file
@@ -0,0 +1,333 @@
|
||||
// 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)
|
||||
#define _CRT_SECURE_NO_WARNINGS 1
|
||||
#endif
|
||||
|
||||
#include "time_zone_libc.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <limits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
#if defined(_AIX)
|
||||
extern "C" {
|
||||
extern long altzone;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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;
|
||||
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'.
|
||||
auto tm_gmtoff(const std::tm& tm) -> decltype(timezone) {
|
||||
const bool is_dst = tm.tm_isdst > 0;
|
||||
return is_dst ? altzone : timezone;
|
||||
}
|
||||
auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
|
||||
const bool is_dst = tm.tm_isdst > 0;
|
||||
return tzname[is_dst];
|
||||
}
|
||||
#elif defined(__native_client__) || defined(__myriad2__) || \
|
||||
defined(__EMSCRIPTEN__)
|
||||
// Uses the globals: '_timezone' and 'tzname'.
|
||||
auto tm_gmtoff(const std::tm& tm) -> decltype(_timezone + 0) {
|
||||
const bool is_dst = tm.tm_isdst > 0;
|
||||
return _timezone + (is_dst ? 60 * 60 : 0);
|
||||
}
|
||||
auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
|
||||
const bool is_dst = tm.tm_isdst > 0;
|
||||
return tzname[is_dst];
|
||||
}
|
||||
#elif defined(__VXWORKS__)
|
||||
// Uses the globals: 'timezone' and 'tzname'.
|
||||
auto tm_gmtoff(const std::tm& tm) -> decltype(timezone + 0) {
|
||||
const bool is_dst = tm.tm_isdst > 0;
|
||||
return timezone + (is_dst ? 60 * 60 : 0);
|
||||
}
|
||||
auto tm_zone(const std::tm& tm) -> decltype(tzname[0]) {
|
||||
const bool is_dst = tm.tm_isdst > 0;
|
||||
return tzname[is_dst];
|
||||
}
|
||||
#else
|
||||
// Adapt to different spellings of the struct std::tm extension fields.
|
||||
#if defined(tm_gmtoff)
|
||||
auto tm_gmtoff(const std::tm& tm) -> decltype(tm.tm_gmtoff) {
|
||||
return tm.tm_gmtoff;
|
||||
}
|
||||
#elif defined(__tm_gmtoff)
|
||||
auto tm_gmtoff(const std::tm& tm) -> decltype(tm.__tm_gmtoff) {
|
||||
return tm.__tm_gmtoff;
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
auto tm_gmtoff(const T& tm) -> decltype(tm.tm_gmtoff) {
|
||||
return tm.tm_gmtoff;
|
||||
}
|
||||
template <typename T>
|
||||
auto tm_gmtoff(const T& tm) -> decltype(tm.__tm_gmtoff) {
|
||||
return tm.__tm_gmtoff;
|
||||
}
|
||||
#endif // tm_gmtoff
|
||||
#if defined(tm_zone)
|
||||
auto tm_zone(const std::tm& tm) -> decltype(tm.tm_zone) { return tm.tm_zone; }
|
||||
#elif defined(__tm_zone)
|
||||
auto tm_zone(const std::tm& tm) -> decltype(tm.__tm_zone) {
|
||||
return tm.__tm_zone;
|
||||
}
|
||||
#else
|
||||
template <typename T>
|
||||
auto tm_zone(const T& tm) -> decltype(tm.tm_zone) {
|
||||
return tm.tm_zone;
|
||||
}
|
||||
template <typename T>
|
||||
auto tm_zone(const T& tm) -> decltype(tm.__tm_zone) {
|
||||
return tm.__tm_zone;
|
||||
}
|
||||
#endif // tm_zone
|
||||
#endif
|
||||
using tm_gmtoff_t = decltype(tm_gmtoff(std::tm{}));
|
||||
|
||||
inline std::tm* gm_time(const std::time_t* timep, std::tm* result) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return gmtime_s(result, timep) ? nullptr : result;
|
||||
#else
|
||||
return gmtime_r(timep, result);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline std::tm* local_time(const std::time_t* timep, std::tm* result) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
return localtime_s(result, timep) ? nullptr : result;
|
||||
#else
|
||||
return localtime_r(timep, result);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Converts a civil second and "dst" flag into a time_t and a struct tm.
|
||||
// Returns false if time_t cannot represent the requested civil second.
|
||||
// Caller must have already checked that cs.year() will fit into a tm_year.
|
||||
bool make_time(const civil_second& cs, int is_dst, std::time_t* t,
|
||||
std::tm* tm) {
|
||||
tm->tm_year = static_cast<int>(cs.year() - year_t{1900});
|
||||
tm->tm_mon = cs.month() - 1;
|
||||
tm->tm_mday = cs.day();
|
||||
tm->tm_hour = cs.hour();
|
||||
tm->tm_min = cs.minute();
|
||||
tm->tm_sec = cs.second();
|
||||
tm->tm_isdst = is_dst;
|
||||
*t = std::mktime(tm);
|
||||
if (*t == std::time_t{-1}) {
|
||||
std::tm tm2;
|
||||
const std::tm* tmp = local_time(t, &tm2);
|
||||
if (tmp == nullptr || tmp->tm_year != tm->tm_year ||
|
||||
tmp->tm_mon != tm->tm_mon || tmp->tm_mday != tm->tm_mday ||
|
||||
tmp->tm_hour != tm->tm_hour || tmp->tm_min != tm->tm_min ||
|
||||
tmp->tm_sec != tm->tm_sec) {
|
||||
// A true error (not just one second before the epoch).
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find the least time_t in [lo:hi] where local time matches offset, given:
|
||||
// (1) lo doesn't match, (2) hi does, and (3) there is only one transition.
|
||||
std::time_t find_trans(std::time_t lo, std::time_t hi, tm_gmtoff_t offset) {
|
||||
std::tm tm;
|
||||
while (lo + 1 != hi) {
|
||||
const std::time_t mid = lo + (hi - lo) / 2;
|
||||
std::tm* tmp = local_time(&mid, &tm);
|
||||
if (tmp != nullptr) {
|
||||
if (tm_gmtoff(*tmp) == offset) {
|
||||
hi = mid;
|
||||
} else {
|
||||
lo = mid;
|
||||
}
|
||||
} else {
|
||||
// If std::tm cannot hold some result we resort to a linear search,
|
||||
// ignoring all failed conversions. Slow, but never really happens.
|
||||
while (++lo != hi) {
|
||||
tmp = local_time(&lo, &tm);
|
||||
if (tmp != nullptr) {
|
||||
if (tm_gmtoff(*tmp) == offset) break;
|
||||
}
|
||||
}
|
||||
return lo;
|
||||
}
|
||||
}
|
||||
return hi;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::unique_ptr<TimeZoneLibC> TimeZoneLibC::Make(const std::string& name) {
|
||||
return std::unique_ptr<TimeZoneLibC>(new TimeZoneLibC(name));
|
||||
}
|
||||
|
||||
time_zone::absolute_lookup TimeZoneLibC::BreakTime(
|
||||
const time_point<seconds>& tp) const {
|
||||
time_zone::absolute_lookup al;
|
||||
al.offset = 0;
|
||||
al.is_dst = false;
|
||||
al.abbr = "-00";
|
||||
|
||||
const std::int_fast64_t s = ToUnixSeconds(tp);
|
||||
|
||||
// If std::time_t cannot hold the input we saturate the output.
|
||||
if (s < std::numeric_limits<std::time_t>::min()) {
|
||||
al.cs = civil_second::min();
|
||||
return al;
|
||||
}
|
||||
if (s > std::numeric_limits<std::time_t>::max()) {
|
||||
al.cs = civil_second::max();
|
||||
return al;
|
||||
}
|
||||
|
||||
const std::time_t t = static_cast<std::time_t>(s);
|
||||
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, tmp->tm_hour,
|
||||
tmp->tm_min, tmp->tm_sec);
|
||||
al.offset = static_cast<int>(tm_gmtoff(*tmp));
|
||||
al.abbr = local_ ? tm_zone(*tmp) : "UTC"; // as expected by cctz
|
||||
al.is_dst = tmp->tm_isdst > 0;
|
||||
return al;
|
||||
}
|
||||
|
||||
time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
|
||||
if (!local_) {
|
||||
// If time_point<seconds> cannot hold the result we saturate.
|
||||
static const civil_second min_tp_cs =
|
||||
civil_second() + ToUnixSeconds(time_point<seconds>::min());
|
||||
static const civil_second max_tp_cs =
|
||||
civil_second() + ToUnixSeconds(time_point<seconds>::max());
|
||||
const time_point<seconds> tp = (cs < min_tp_cs) ? time_point<seconds>::min()
|
||||
: (cs > max_tp_cs)
|
||||
? time_point<seconds>::max()
|
||||
: FromUnixSeconds(cs - civil_second());
|
||||
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
|
||||
}
|
||||
|
||||
// If tm_year cannot hold the requested year we saturate the result.
|
||||
if (cs.year() < 0) {
|
||||
if (cs.year() < std::numeric_limits<int>::min() + year_t{1900}) {
|
||||
const time_point<seconds> tp = time_point<seconds>::min();
|
||||
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
|
||||
}
|
||||
} 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.
|
||||
// We are also subject to the vagaries of mktime() implementations. For
|
||||
// example, some implementations treat "tm_isdst" as a demand (useless),
|
||||
// and some as a disambiguator (useful).
|
||||
std::time_t t0, t1;
|
||||
std::tm tm0, tm1;
|
||||
if (make_time(cs, 0, &t0, &tm0) && make_time(cs, 1, &t1, &tm1)) {
|
||||
if (tm0.tm_isdst == tm1.tm_isdst) {
|
||||
// The civil time was singular (pre == trans == post).
|
||||
const time_point<seconds> tp = FromUnixSeconds(tm0.tm_isdst ? t1 : t0);
|
||||
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
|
||||
}
|
||||
|
||||
tm_gmtoff_t offset = tm_gmtoff(tm0);
|
||||
if (t0 < t1) { // negative DST
|
||||
std::swap(t0, t1);
|
||||
offset = tm_gmtoff(tm1);
|
||||
}
|
||||
|
||||
const std::time_t tt = find_trans(t1, t0, offset);
|
||||
const time_point<seconds> trans = FromUnixSeconds(tt);
|
||||
|
||||
if (tm0.tm_isdst) {
|
||||
// The civil time did not exist (pre >= trans > post).
|
||||
const time_point<seconds> pre = FromUnixSeconds(t0);
|
||||
const time_point<seconds> post = FromUnixSeconds(t1);
|
||||
return {time_zone::civil_lookup::SKIPPED, pre, trans, post};
|
||||
}
|
||||
|
||||
// The civil time was ambiguous (pre < trans <= post).
|
||||
const time_point<seconds> pre = FromUnixSeconds(t1);
|
||||
const time_point<seconds> post = FromUnixSeconds(t0);
|
||||
return {time_zone::civil_lookup::REPEATED, pre, trans, post};
|
||||
}
|
||||
|
||||
// make_time() failed somehow so we saturate the result.
|
||||
const time_point<seconds> tp = (cs < civil_second())
|
||||
? time_point<seconds>::min()
|
||||
: time_point<seconds>::max();
|
||||
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
|
||||
}
|
||||
|
||||
bool TimeZoneLibC::NextTransition(const time_point<seconds>&,
|
||||
time_zone::civil_transition*) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TimeZoneLibC::PrevTransition(const time_point<seconds>&,
|
||||
time_zone::civil_transition*) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string TimeZoneLibC::Version() const {
|
||||
return std::string(); // unknown
|
||||
}
|
||||
|
||||
std::string TimeZoneLibC::Description() const {
|
||||
return local_ ? "localtime" : "UTC";
|
||||
}
|
||||
|
||||
TimeZoneLibC::TimeZoneLibC(const std::string& name)
|
||||
: local_(name == "localtime") {}
|
||||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
60
Pods/abseil/absl/time/internal/cctz/src/time_zone_libc.h
generated
Normal file
60
Pods/abseil/absl/time/internal/cctz/src/time_zone_libc.h
generated
Normal file
@@ -0,0 +1,60 @@
|
||||
// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "time_zone_if.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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.
|
||||
class TimeZoneLibC : public TimeZoneIf {
|
||||
public:
|
||||
// Factory.
|
||||
static std::unique_ptr<TimeZoneLibC> Make(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;
|
||||
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:
|
||||
explicit TimeZoneLibC(const std::string& name);
|
||||
TimeZoneLibC(const TimeZoneLibC&) = delete;
|
||||
TimeZoneLibC& operator=(const TimeZoneLibC&) = delete;
|
||||
|
||||
const bool local_; // localtime or UTC
|
||||
};
|
||||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_LIBC_H_
|
||||
363
Pods/abseil/absl/time/internal/cctz/src/time_zone_lookup.cc
generated
Normal file
363
Pods/abseil/absl/time/internal/cctz/src/time_zone_lookup.cc
generated
Normal file
@@ -0,0 +1,363 @@
|
||||
// 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 "absl/base/config.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
#include <sys/system_properties.h>
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ >= 21
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <CoreFoundation/CFTimeZone.h>
|
||||
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
#if defined(__Fuchsia__)
|
||||
#include <fuchsia/intl/cpp/fidl.h>
|
||||
#include <lib/async-loop/cpp/loop.h>
|
||||
#include <lib/fdio/directory.h>
|
||||
#include <zircon/types.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <sdkddkver.h>
|
||||
// Include only when the SDK is for Windows 10 (and later), and the binary is
|
||||
// targeted for Windows XP and later.
|
||||
// Note: The Windows SDK added windows.globalization.h file for Windows 10, but
|
||||
// MinGW did not add it until NTDDI_WIN10_NI (SDK version 10.0.22621.0).
|
||||
#if ((defined(_WIN32_WINNT_WIN10) && !defined(__MINGW32__)) || \
|
||||
(defined(NTDDI_WIN10_NI) && NTDDI_VERSION >= NTDDI_WIN10_NI)) && \
|
||||
(_WIN32_WINNT >= _WIN32_WINNT_WINXP)
|
||||
#define USE_WIN32_LOCAL_TIME_ZONE
|
||||
#include <roapi.h>
|
||||
#include <tchar.h>
|
||||
#include <wchar.h>
|
||||
#include <windows.globalization.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "time_zone_fixed.h"
|
||||
#include "time_zone_impl.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
namespace {
|
||||
#if defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21
|
||||
// Android 'L' removes __system_property_get() from the NDK, however
|
||||
// it is still a hidden symbol in libc so we use dlsym() to access it.
|
||||
// See Chromium's base/sys_info_android.cc for a similar example.
|
||||
|
||||
using property_get_func = int (*)(const char*, char*);
|
||||
|
||||
property_get_func LoadSystemPropertyGet() {
|
||||
int flag = RTLD_LAZY | RTLD_GLOBAL;
|
||||
#if defined(RTLD_NOLOAD)
|
||||
flag |= RTLD_NOLOAD; // libc.so should already be resident
|
||||
#endif
|
||||
if (void* handle = dlopen("libc.so", flag)) {
|
||||
void* sym = dlsym(handle, "__system_property_get");
|
||||
dlclose(handle);
|
||||
return reinterpret_cast<property_get_func>(sym);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int __system_property_get(const char* name, char* value) {
|
||||
static property_get_func system_property_get = LoadSystemPropertyGet();
|
||||
return system_property_get ? system_property_get(name, value) : -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_WIN32_LOCAL_TIME_ZONE)
|
||||
// Calls the WinRT Calendar.GetTimeZone method to obtain the IANA ID of the
|
||||
// local time zone. Returns an empty vector in case of an error.
|
||||
std::string win32_local_time_zone(const HMODULE combase) {
|
||||
std::string result;
|
||||
const auto ro_activate_instance =
|
||||
reinterpret_cast<decltype(&RoActivateInstance)>(
|
||||
GetProcAddress(combase, "RoActivateInstance"));
|
||||
if (!ro_activate_instance) {
|
||||
return result;
|
||||
}
|
||||
const auto windows_create_string_reference =
|
||||
reinterpret_cast<decltype(&WindowsCreateStringReference)>(
|
||||
GetProcAddress(combase, "WindowsCreateStringReference"));
|
||||
if (!windows_create_string_reference) {
|
||||
return result;
|
||||
}
|
||||
const auto windows_delete_string =
|
||||
reinterpret_cast<decltype(&WindowsDeleteString)>(
|
||||
GetProcAddress(combase, "WindowsDeleteString"));
|
||||
if (!windows_delete_string) {
|
||||
return result;
|
||||
}
|
||||
const auto windows_get_string_raw_buffer =
|
||||
reinterpret_cast<decltype(&WindowsGetStringRawBuffer)>(
|
||||
GetProcAddress(combase, "WindowsGetStringRawBuffer"));
|
||||
if (!windows_get_string_raw_buffer) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// The string returned by WindowsCreateStringReference doesn't need to be
|
||||
// deleted.
|
||||
HSTRING calendar_class_id;
|
||||
HSTRING_HEADER calendar_class_id_header;
|
||||
HRESULT hr = windows_create_string_reference(
|
||||
RuntimeClass_Windows_Globalization_Calendar,
|
||||
sizeof(RuntimeClass_Windows_Globalization_Calendar) / sizeof(wchar_t) - 1,
|
||||
&calendar_class_id_header, &calendar_class_id);
|
||||
if (FAILED(hr)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
IInspectable* calendar;
|
||||
hr = ro_activate_instance(calendar_class_id, &calendar);
|
||||
if (FAILED(hr)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ABI::Windows::Globalization::ITimeZoneOnCalendar* time_zone;
|
||||
hr = calendar->QueryInterface(IID_PPV_ARGS(&time_zone));
|
||||
if (FAILED(hr)) {
|
||||
calendar->Release();
|
||||
return result;
|
||||
}
|
||||
|
||||
HSTRING tz_hstr;
|
||||
hr = time_zone->GetTimeZone(&tz_hstr);
|
||||
if (SUCCEEDED(hr)) {
|
||||
UINT32 wlen;
|
||||
const PCWSTR tz_wstr = windows_get_string_raw_buffer(tz_hstr, &wlen);
|
||||
if (tz_wstr) {
|
||||
const int size =
|
||||
WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen),
|
||||
nullptr, 0, nullptr, nullptr);
|
||||
result.resize(static_cast<size_t>(size));
|
||||
WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen),
|
||||
&result[0], size, nullptr, nullptr);
|
||||
}
|
||||
windows_delete_string(tz_hstr);
|
||||
}
|
||||
time_zone->Release();
|
||||
calendar->Release();
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
std::string time_zone::name() const { return effective_impl().Name(); }
|
||||
|
||||
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 {
|
||||
return effective_impl().MakeTime(cs);
|
||||
}
|
||||
|
||||
bool time_zone::next_transition(const time_point<seconds>& tp,
|
||||
civil_transition* trans) const {
|
||||
return effective_impl().NextTransition(tp, trans);
|
||||
}
|
||||
|
||||
bool time_zone::prev_transition(const time_point<seconds>& tp,
|
||||
civil_transition* trans) const {
|
||||
return effective_impl().PrevTransition(tp, trans);
|
||||
}
|
||||
|
||||
std::string time_zone::version() const { return effective_impl().Version(); }
|
||||
|
||||
std::string time_zone::description() const {
|
||||
return effective_impl().Description();
|
||||
}
|
||||
|
||||
const time_zone::Impl& time_zone::effective_impl() const {
|
||||
if (impl_ == nullptr) {
|
||||
// Dereferencing an implicit-UTC time_zone is expected to be
|
||||
// rare, so we don't mind paying a small synchronization cost.
|
||||
return *time_zone::Impl::UTC().impl_;
|
||||
}
|
||||
return *impl_;
|
||||
}
|
||||
|
||||
bool load_time_zone(const std::string& name, time_zone* tz) {
|
||||
return time_zone::Impl::LoadTimeZone(name, tz);
|
||||
}
|
||||
|
||||
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";
|
||||
#if defined(__ANDROID__)
|
||||
char sysprop[PROP_VALUE_MAX];
|
||||
if (__system_property_get("persist.sys.timezone", sysprop) > 0) {
|
||||
zone = sysprop;
|
||||
}
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
std::vector<char> buffer;
|
||||
CFTimeZoneRef tz_default = CFTimeZoneCopyDefault();
|
||||
if (CFStringRef tz_name = CFTimeZoneGetName(tz_default)) {
|
||||
CFStringEncoding encoding = kCFStringEncodingUTF8;
|
||||
CFIndex length = CFStringGetLength(tz_name);
|
||||
CFIndex max_size = CFStringGetMaximumSizeForEncoding(length, encoding) + 1;
|
||||
buffer.resize(static_cast<size_t>(max_size));
|
||||
if (CFStringGetCString(tz_name, &buffer[0], max_size, encoding)) {
|
||||
zone = &buffer[0];
|
||||
}
|
||||
}
|
||||
CFRelease(tz_default);
|
||||
#endif
|
||||
#if defined(__Fuchsia__)
|
||||
std::string primary_tz;
|
||||
[&]() {
|
||||
// Note: We can't use the synchronous FIDL API here because it doesn't
|
||||
// allow timeouts; if the FIDL call failed, local_time_zone() would never
|
||||
// return.
|
||||
|
||||
const zx::duration kTimeout = zx::msec(500);
|
||||
|
||||
// Don't attach to the thread because otherwise the thread's dispatcher
|
||||
// would be set to null when the loop is destroyed, causing any other FIDL
|
||||
// code running on the same thread to crash.
|
||||
async::Loop loop(&kAsyncLoopConfigNeverAttachToThread);
|
||||
|
||||
fuchsia::intl::PropertyProviderHandle handle;
|
||||
zx_status_t status = fdio_service_connect_by_name(
|
||||
fuchsia::intl::PropertyProvider::Name_,
|
||||
handle.NewRequest().TakeChannel().release());
|
||||
if (status != ZX_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
fuchsia::intl::PropertyProviderPtr intl_provider;
|
||||
status = intl_provider.Bind(std::move(handle), loop.dispatcher());
|
||||
if (status != ZX_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
intl_provider->GetProfile(
|
||||
[&loop, &primary_tz](fuchsia::intl::Profile profile) {
|
||||
if (!profile.time_zones().empty()) {
|
||||
primary_tz = profile.time_zones()[0].id;
|
||||
}
|
||||
loop.Quit();
|
||||
});
|
||||
loop.Run(zx::deadline_after(kTimeout));
|
||||
}();
|
||||
|
||||
if (!primary_tz.empty()) {
|
||||
zone = primary_tz.c_str();
|
||||
}
|
||||
#endif
|
||||
#if defined(USE_WIN32_LOCAL_TIME_ZONE)
|
||||
// Use the WinRT Calendar class to get the local time zone. This feature is
|
||||
// available on Windows 10 and later. The library is dynamically linked to
|
||||
// maintain binary compatibility with Windows XP - Windows 7. On Windows 8,
|
||||
// The combase.dll API functions are available but the RoActivateInstance
|
||||
// call will fail for the Calendar class.
|
||||
std::string winrt_tz;
|
||||
const HMODULE combase =
|
||||
LoadLibraryEx(_T("combase.dll"), nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
|
||||
if (combase) {
|
||||
const auto ro_initialize = reinterpret_cast<decltype(&::RoInitialize)>(
|
||||
GetProcAddress(combase, "RoInitialize"));
|
||||
const auto ro_uninitialize = reinterpret_cast<decltype(&::RoUninitialize)>(
|
||||
GetProcAddress(combase, "RoUninitialize"));
|
||||
if (ro_initialize && ro_uninitialize) {
|
||||
const HRESULT hr = ro_initialize(RO_INIT_MULTITHREADED);
|
||||
// RPC_E_CHANGED_MODE means that a previous RoInitialize call specified
|
||||
// a different concurrency model. The WinRT runtime is initialized and
|
||||
// should work for our purpose here, but we should *not* call
|
||||
// RoUninitialize because it's a failure.
|
||||
if (SUCCEEDED(hr) || hr == RPC_E_CHANGED_MODE) {
|
||||
winrt_tz = win32_local_time_zone(combase);
|
||||
if (SUCCEEDED(hr)) {
|
||||
ro_uninitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
FreeLibrary(combase);
|
||||
}
|
||||
if (!winrt_tz.empty()) {
|
||||
zone = winrt_tz.c_str();
|
||||
}
|
||||
#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.
|
||||
// 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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
159
Pods/abseil/absl/time/internal/cctz/src/time_zone_posix.cc
generated
Normal file
159
Pods/abseil/absl/time/internal/cctz/src/time_zone_posix.cc
generated
Normal file
@@ -0,0 +1,159 @@
|
||||
// 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>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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;
|
||||
res->date.j.day = static_cast<std::int_fast16_t>(day);
|
||||
}
|
||||
} else {
|
||||
int day = 0;
|
||||
if ((p = ParseInt(p, 0, 365, &day)) != nullptr) {
|
||||
res->date.fmt = PosixTransition::N;
|
||||
res->date.n.day = static_cast<std::int_fast16_t>(day);
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
132
Pods/abseil/absl/time/internal/cctz/src/time_zone_posix.h
generated
Normal file
132
Pods/abseil/absl/time/internal/cctz/src/time_zone_posix.h
generated
Normal file
@@ -0,0 +1,132 @@
|
||||
// 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 ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
|
||||
#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
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 {
|
||||
std::int_fast16_t day; // day of non-leap year [1:365]
|
||||
};
|
||||
struct Day {
|
||||
std::int_fast16_t day; // day of year [0:365]
|
||||
};
|
||||
struct MonthWeekWeekday {
|
||||
std::int_fast8_t month; // month of year [1:12]
|
||||
std::int_fast8_t week; // week of month [1:5] (5==last)
|
||||
std::int_fast8_t weekday; // 0==Sun, ..., 6=Sat
|
||||
};
|
||||
|
||||
DateFormat fmt;
|
||||
|
||||
union {
|
||||
NonLeapDay j;
|
||||
Day n;
|
||||
MonthWeekWeekday m;
|
||||
};
|
||||
};
|
||||
|
||||
struct Time {
|
||||
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 abbreviation 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
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_POSIX_H_
|
||||
118
Pods/abseil/absl/time/internal/cctz/src/tzfile.h
generated
Normal file
118
Pods/abseil/absl/time/internal/cctz/src/tzfile.h
generated
Normal file
@@ -0,0 +1,118 @@
|
||||
/* Layout and location of TZif files. */
|
||||
|
||||
#ifndef TZFILE_H
|
||||
|
||||
#define TZFILE_H
|
||||
|
||||
/*
|
||||
** This file is in the public domain, so clarified as of
|
||||
** 1996-06-05 by Arthur David Olson.
|
||||
*/
|
||||
|
||||
/*
|
||||
** This header is for use ONLY with the time conversion code.
|
||||
** There is no guarantee that it will remain unchanged,
|
||||
** or that it will remain at all.
|
||||
** Do NOT copy it to any system include directory.
|
||||
** Thank you!
|
||||
*/
|
||||
|
||||
/*
|
||||
** Information about time zone files.
|
||||
*/
|
||||
|
||||
#ifndef TZDEFRULES
|
||||
#define TZDEFRULES "posixrules"
|
||||
#endif /* !defined TZDEFRULES */
|
||||
|
||||
/* See Internet RFC 8536 for more details about the following format. */
|
||||
|
||||
/*
|
||||
** Each file begins with. . .
|
||||
*/
|
||||
|
||||
#define TZ_MAGIC "TZif"
|
||||
|
||||
struct tzhead {
|
||||
char tzh_magic[4]; /* TZ_MAGIC */
|
||||
char tzh_version[1]; /* '\0' or '2'-'4' as of 2021 */
|
||||
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 */
|
||||
};
|
||||
|
||||
/*
|
||||
** . . .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,
|
||||
** transition time is local (wall clock)
|
||||
** time; if absent, transition times are
|
||||
** assumed to be local time
|
||||
** tzh_ttisutcnt (char)s indexed by type; if 1, transition
|
||||
** time is UT, if 0, transition time is
|
||||
** local time; if absent, transition
|
||||
** times are assumed to be local time.
|
||||
** When this is 1, the corresponding
|
||||
** std/wall indicator must also be 1.
|
||||
*/
|
||||
|
||||
/*
|
||||
** If tzh_version is '2' or greater, the above is followed by a second instance
|
||||
** of tzhead and a second instance of the data in which each coded transition
|
||||
** time uses 8 rather than 4 chars,
|
||||
** then a POSIX-TZ-environment-variable-style string for use in handling
|
||||
** instants after the last transition time stored in the file
|
||||
** (with nothing between the newlines if there is no POSIX representation for
|
||||
** such instants).
|
||||
**
|
||||
** If tz_version is '3' or greater, the above is extended as follows.
|
||||
** First, the POSIX TZ string's hour offset may range from -167
|
||||
** through 167 as compared to the POSIX-required 0 through 24.
|
||||
** Second, its DST start time may be January 1 at 00:00 and its stop
|
||||
** time December 31 at 24:00 plus the difference between DST and
|
||||
** standard time, indicating DST all year.
|
||||
*/
|
||||
|
||||
/*
|
||||
** In the current implementation, "tzset()" refuses to deal with files that
|
||||
** exceed any of the limits below.
|
||||
*/
|
||||
|
||||
#ifndef TZ_MAX_TIMES
|
||||
/* This must be at least 242 for Europe/London with 'zic -b fat'. */
|
||||
#define TZ_MAX_TIMES 2000
|
||||
#endif /* !defined TZ_MAX_TIMES */
|
||||
|
||||
#ifndef TZ_MAX_TYPES
|
||||
/* This must be at least 18 for Europe/Vilnius with 'zic -b fat'. */
|
||||
#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
|
||||
#endif /* !defined TZ_MAX_TYPES */
|
||||
|
||||
#ifndef TZ_MAX_CHARS
|
||||
/* This must be at least 40 for America/Anchorage. */
|
||||
#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
|
||||
/* This must be at least 27 for leap seconds from 1972 through mid-2023.
|
||||
There's a plan to discontinue leap seconds by 2035. */
|
||||
#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
|
||||
#endif /* !defined TZ_MAX_LEAPS */
|
||||
|
||||
#endif /* !defined TZFILE_H */
|
||||
116
Pods/abseil/absl/time/internal/cctz/src/zone_info_source.cc
generated
Normal file
116
Pods/abseil/absl/time/internal/cctz/src/zone_info_source.cc
generated
Normal file
@@ -0,0 +1,116 @@
|
||||
// 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 "absl/time/internal/cctz/include/cctz/zone_info_source.h"
|
||||
|
||||
#include "absl/base/config.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz {
|
||||
|
||||
// Defined out-of-line to avoid emitting a weak vtable in all TUs.
|
||||
ZoneInfoSource::~ZoneInfoSource() {}
|
||||
std::string ZoneInfoSource::Version() const { return std::string(); }
|
||||
|
||||
} // namespace cctz
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
namespace cctz_extension {
|
||||
|
||||
namespace {
|
||||
|
||||
// A default for cctz_extension::zone_info_source_factory, which simply
|
||||
// defers to the fallback factory.
|
||||
std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource> DefaultFactory(
|
||||
const std::string& name,
|
||||
const std::function<
|
||||
std::unique_ptr<absl::time_internal::cctz::ZoneInfoSource>(
|
||||
const std::string& name)>& fallback_factory) {
|
||||
return fallback_factory(name);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// A "weak" definition for cctz_extension::zone_info_source_factory.
|
||||
// The user may override this with their own "strong" definition (see
|
||||
// zone_info_source.h).
|
||||
#if !defined(__has_attribute)
|
||||
#define __has_attribute(x) 0
|
||||
#endif
|
||||
// MinGW is GCC on Windows, so while it asserts __has_attribute(weak), the
|
||||
// Windows linker cannot handle that. Nor does the MinGW compiler know how to
|
||||
// pass "#pragma comment(linker, ...)" to the Windows linker.
|
||||
#if (__has_attribute(weak) || defined(__GNUC__)) && !defined(__MINGW32__) && \
|
||||
!defined(__CYGWIN__)
|
||||
ZoneInfoSourceFactory zone_info_source_factory __attribute__((weak)) =
|
||||
DefaultFactory;
|
||||
#elif defined(_MSC_VER) && !defined(__MINGW32__) && !defined(_LIBCPP_VERSION)
|
||||
extern ZoneInfoSourceFactory zone_info_source_factory;
|
||||
extern ZoneInfoSourceFactory default_factory;
|
||||
ZoneInfoSourceFactory default_factory = DefaultFactory;
|
||||
#if defined(_M_IX86) || defined(_M_ARM)
|
||||
#pragma comment( \
|
||||
linker, \
|
||||
"/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
|
||||
"@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
|
||||
"@@ZA=?default_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
|
||||
"@ABV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@@std@@@std@@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
|
||||
"@@ZA")
|
||||
#elif defined(_M_IA_64) || defined(_M_AMD64) || defined(_M_ARM64)
|
||||
#pragma comment( \
|
||||
linker, \
|
||||
"/alternatename:?zone_info_source_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
|
||||
"@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
|
||||
"@@ZEA=?default_factory@cctz_extension@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@3P6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
|
||||
"@AEBV?$function@$$A6A?AV?$unique_ptr@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@U?$default_delete@VZoneInfoSource@cctz@time_internal@" ABSL_INTERNAL_MANGLED_NS \
|
||||
"@@@std@@@std@@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@2@@Z@" ABSL_INTERNAL_MANGLED_BACKREFERENCE \
|
||||
"@@ZEA")
|
||||
#else
|
||||
#error Unsupported MSVC platform
|
||||
#endif // _M_<PLATFORM>
|
||||
#else
|
||||
// Make it a "strong" definition if we have no other choice.
|
||||
ZoneInfoSourceFactory zone_info_source_factory = DefaultFactory;
|
||||
#endif
|
||||
|
||||
} // namespace cctz_extension
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
31
Pods/abseil/absl/time/internal/get_current_time_chrono.inc
generated
Normal file
31
Pods/abseil/absl/time/internal/get_current_time_chrono.inc
generated
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright 2018 The Abseil Authors.
|
||||
//
|
||||
// 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 <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
|
||||
static int64_t GetCurrentTimeNanosFromSystem() {
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::system_clock::now() -
|
||||
std::chrono::system_clock::from_time_t(0))
|
||||
.count();
|
||||
}
|
||||
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
24
Pods/abseil/absl/time/internal/get_current_time_posix.inc
generated
Normal file
24
Pods/abseil/absl/time/internal/get_current_time_posix.inc
generated
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "absl/time/clock.h"
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <ctime>
|
||||
#include <cstdint>
|
||||
|
||||
#include "absl/base/internal/raw_logging.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
namespace time_internal {
|
||||
|
||||
static int64_t GetCurrentTimeNanosFromSystem() {
|
||||
const int64_t kNanosPerSecond = 1000 * 1000 * 1000;
|
||||
struct timespec ts;
|
||||
ABSL_RAW_CHECK(clock_gettime(CLOCK_REALTIME, &ts) == 0,
|
||||
"Failed to read real-time clock.");
|
||||
return (int64_t{ts.tv_sec} * kNanosPerSecond +
|
||||
int64_t{ts.tv_nsec});
|
||||
}
|
||||
|
||||
} // namespace time_internal
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
507
Pods/abseil/absl/time/time.cc
generated
Normal file
507
Pods/abseil/absl/time/time.cc
generated
Normal file
@@ -0,0 +1,507 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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.
|
||||
|
||||
// The implementation of the absl::Time class, which is declared in
|
||||
// //absl/time.h.
|
||||
//
|
||||
// The representation for an absl::Time is an absl::Duration offset from the
|
||||
// epoch. We use the traditional Unix epoch (1970-01-01 00:00:00 +0000)
|
||||
// for convenience, but this is not exposed in the API and could be changed.
|
||||
//
|
||||
// NOTE: To keep type verbosity to a minimum, the following variable naming
|
||||
// conventions are used throughout this file.
|
||||
//
|
||||
// tz: An absl::TimeZone
|
||||
// ci: An absl::TimeZone::CivilInfo
|
||||
// ti: An absl::TimeZone::TimeInfo
|
||||
// cd: An absl::CivilDay or a cctz::civil_day
|
||||
// cs: An absl::CivilSecond or a cctz::civil_second
|
||||
// bd: An absl::Time::Breakdown
|
||||
// cl: A cctz::time_zone::civil_lookup
|
||||
// al: A cctz::time_zone::absolute_lookup
|
||||
|
||||
#include "absl/time/time.h"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <winsock2.h> // for timeval
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <limits>
|
||||
|
||||
#include "absl/time/internal/cctz/include/cctz/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
namespace cctz = absl::time_internal::cctz;
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
namespace {
|
||||
|
||||
inline cctz::time_point<cctz::seconds> unix_epoch() {
|
||||
return std::chrono::time_point_cast<cctz::seconds>(
|
||||
std::chrono::system_clock::from_time_t(0));
|
||||
}
|
||||
|
||||
// Floors d to the next unit boundary closer to negative infinity.
|
||||
inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
|
||||
absl::Duration rem;
|
||||
int64_t q = absl::IDivDuration(d, unit, &rem);
|
||||
return (q > 0 || rem >= ZeroDuration() ||
|
||||
q == std::numeric_limits<int64_t>::min())
|
||||
? q
|
||||
: q - 1;
|
||||
}
|
||||
|
||||
ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
|
||||
inline absl::Time::Breakdown InfiniteFutureBreakdown() {
|
||||
absl::Time::Breakdown bd;
|
||||
bd.year = std::numeric_limits<int64_t>::max();
|
||||
bd.month = 12;
|
||||
bd.day = 31;
|
||||
bd.hour = 23;
|
||||
bd.minute = 59;
|
||||
bd.second = 59;
|
||||
bd.subsecond = absl::InfiniteDuration();
|
||||
bd.weekday = 4;
|
||||
bd.yearday = 365;
|
||||
bd.offset = 0;
|
||||
bd.is_dst = false;
|
||||
bd.zone_abbr = "-00";
|
||||
return bd;
|
||||
}
|
||||
|
||||
inline absl::Time::Breakdown InfinitePastBreakdown() {
|
||||
Time::Breakdown bd;
|
||||
bd.year = std::numeric_limits<int64_t>::min();
|
||||
bd.month = 1;
|
||||
bd.day = 1;
|
||||
bd.hour = 0;
|
||||
bd.minute = 0;
|
||||
bd.second = 0;
|
||||
bd.subsecond = -absl::InfiniteDuration();
|
||||
bd.weekday = 7;
|
||||
bd.yearday = 1;
|
||||
bd.offset = 0;
|
||||
bd.is_dst = false;
|
||||
bd.zone_abbr = "-00";
|
||||
return bd;
|
||||
}
|
||||
ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
|
||||
|
||||
inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() {
|
||||
TimeZone::CivilInfo ci;
|
||||
ci.cs = CivilSecond::max();
|
||||
ci.subsecond = InfiniteDuration();
|
||||
ci.offset = 0;
|
||||
ci.is_dst = false;
|
||||
ci.zone_abbr = "-00";
|
||||
return ci;
|
||||
}
|
||||
|
||||
inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() {
|
||||
TimeZone::CivilInfo ci;
|
||||
ci.cs = CivilSecond::min();
|
||||
ci.subsecond = -InfiniteDuration();
|
||||
ci.offset = 0;
|
||||
ci.is_dst = false;
|
||||
ci.zone_abbr = "-00";
|
||||
return ci;
|
||||
}
|
||||
|
||||
ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
|
||||
inline absl::TimeConversion InfiniteFutureTimeConversion() {
|
||||
absl::TimeConversion tc;
|
||||
tc.pre = tc.trans = tc.post = absl::InfiniteFuture();
|
||||
tc.kind = absl::TimeConversion::UNIQUE;
|
||||
tc.normalized = true;
|
||||
return tc;
|
||||
}
|
||||
|
||||
inline TimeConversion InfinitePastTimeConversion() {
|
||||
absl::TimeConversion tc;
|
||||
tc.pre = tc.trans = tc.post = absl::InfinitePast();
|
||||
tc.kind = absl::TimeConversion::UNIQUE;
|
||||
tc.normalized = true;
|
||||
return tc;
|
||||
}
|
||||
ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
|
||||
|
||||
// Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as
|
||||
// necessary. If sec is min/max, then consult cs+tz to check for overflow.
|
||||
Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec,
|
||||
const cctz::civil_second& cs,
|
||||
const cctz::time_zone& tz,
|
||||
bool* normalized = nullptr) {
|
||||
const auto max = cctz::time_point<cctz::seconds>::max();
|
||||
const auto min = cctz::time_point<cctz::seconds>::min();
|
||||
if (sec == max) {
|
||||
const auto al = tz.lookup(max);
|
||||
if (cs > al.cs) {
|
||||
if (normalized) *normalized = true;
|
||||
return absl::InfiniteFuture();
|
||||
}
|
||||
}
|
||||
if (sec == min) {
|
||||
const auto al = tz.lookup(min);
|
||||
if (cs < al.cs) {
|
||||
if (normalized) *normalized = true;
|
||||
return absl::InfinitePast();
|
||||
}
|
||||
}
|
||||
const auto hi = (sec - unix_epoch()).count();
|
||||
return time_internal::FromUnixDuration(time_internal::MakeDuration(hi));
|
||||
}
|
||||
|
||||
// Returns Mon=1..Sun=7.
|
||||
inline int MapWeekday(const cctz::weekday& wd) {
|
||||
switch (wd) {
|
||||
case cctz::weekday::monday:
|
||||
return 1;
|
||||
case cctz::weekday::tuesday:
|
||||
return 2;
|
||||
case cctz::weekday::wednesday:
|
||||
return 3;
|
||||
case cctz::weekday::thursday:
|
||||
return 4;
|
||||
case cctz::weekday::friday:
|
||||
return 5;
|
||||
case cctz::weekday::saturday:
|
||||
return 6;
|
||||
case cctz::weekday::sunday:
|
||||
return 7;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool FindTransition(const cctz::time_zone& tz,
|
||||
bool (cctz::time_zone::*find_transition)(
|
||||
const cctz::time_point<cctz::seconds>& tp,
|
||||
cctz::time_zone::civil_transition* trans) const,
|
||||
Time t, TimeZone::CivilTransition* trans) {
|
||||
// Transitions are second-aligned, so we can discard any fractional part.
|
||||
const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t));
|
||||
cctz::time_zone::civil_transition tr;
|
||||
if (!(tz.*find_transition)(tp, &tr)) return false;
|
||||
trans->from = CivilSecond(tr.from);
|
||||
trans->to = CivilSecond(tr.to);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
//
|
||||
// Time
|
||||
//
|
||||
|
||||
ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
|
||||
absl::Time::Breakdown Time::In(absl::TimeZone tz) const {
|
||||
if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown();
|
||||
if (*this == absl::InfinitePast()) return InfinitePastBreakdown();
|
||||
|
||||
const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_));
|
||||
const auto al = cctz::time_zone(tz).lookup(tp);
|
||||
const auto cs = al.cs;
|
||||
const auto cd = cctz::civil_day(cs);
|
||||
|
||||
absl::Time::Breakdown bd;
|
||||
bd.year = cs.year();
|
||||
bd.month = cs.month();
|
||||
bd.day = cs.day();
|
||||
bd.hour = cs.hour();
|
||||
bd.minute = cs.minute();
|
||||
bd.second = cs.second();
|
||||
bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_));
|
||||
bd.weekday = MapWeekday(cctz::get_weekday(cd));
|
||||
bd.yearday = cctz::get_yearday(cd);
|
||||
bd.offset = al.offset;
|
||||
bd.is_dst = al.is_dst;
|
||||
bd.zone_abbr = al.abbr;
|
||||
return bd;
|
||||
}
|
||||
ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
|
||||
|
||||
//
|
||||
// Conversions from/to other time types.
|
||||
//
|
||||
|
||||
absl::Time FromUDate(double udate) {
|
||||
return time_internal::FromUnixDuration(absl::Milliseconds(udate));
|
||||
}
|
||||
|
||||
absl::Time FromUniversal(int64_t universal) {
|
||||
return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal);
|
||||
}
|
||||
|
||||
int64_t ToUnixNanos(Time t) {
|
||||
if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
|
||||
time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) {
|
||||
return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
|
||||
1000 * 1000 * 1000) +
|
||||
(time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4);
|
||||
}
|
||||
return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1));
|
||||
}
|
||||
|
||||
int64_t ToUnixMicros(Time t) {
|
||||
if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
|
||||
time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) {
|
||||
return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
|
||||
1000 * 1000) +
|
||||
(time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000);
|
||||
}
|
||||
return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1));
|
||||
}
|
||||
|
||||
int64_t ToUnixMillis(Time t) {
|
||||
if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
|
||||
time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) {
|
||||
return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) +
|
||||
(time_internal::GetRepLo(time_internal::ToUnixDuration(t)) /
|
||||
(4000 * 1000));
|
||||
}
|
||||
return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1));
|
||||
}
|
||||
|
||||
int64_t ToUnixSeconds(Time t) {
|
||||
return time_internal::GetRepHi(time_internal::ToUnixDuration(t));
|
||||
}
|
||||
|
||||
time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; }
|
||||
|
||||
double ToUDate(Time t) {
|
||||
return absl::FDivDuration(time_internal::ToUnixDuration(t),
|
||||
absl::Milliseconds(1));
|
||||
}
|
||||
|
||||
int64_t ToUniversal(absl::Time t) {
|
||||
return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
|
||||
}
|
||||
|
||||
absl::Time TimeFromTimespec(timespec ts) {
|
||||
return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts));
|
||||
}
|
||||
|
||||
absl::Time TimeFromTimeval(timeval tv) {
|
||||
return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv));
|
||||
}
|
||||
|
||||
timespec ToTimespec(Time t) {
|
||||
timespec ts;
|
||||
absl::Duration d = time_internal::ToUnixDuration(t);
|
||||
if (!time_internal::IsInfiniteDuration(d)) {
|
||||
ts.tv_sec = static_cast<decltype(ts.tv_sec)>(time_internal::GetRepHi(d));
|
||||
if (ts.tv_sec == time_internal::GetRepHi(d)) { // no time_t narrowing
|
||||
ts.tv_nsec = time_internal::GetRepLo(d) / 4; // floor
|
||||
return ts;
|
||||
}
|
||||
}
|
||||
if (d >= absl::ZeroDuration()) {
|
||||
ts.tv_sec = std::numeric_limits<time_t>::max();
|
||||
ts.tv_nsec = 1000 * 1000 * 1000 - 1;
|
||||
} else {
|
||||
ts.tv_sec = std::numeric_limits<time_t>::min();
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
timeval ToTimeval(Time t) {
|
||||
timeval tv;
|
||||
timespec ts = absl::ToTimespec(t);
|
||||
tv.tv_sec = static_cast<decltype(tv.tv_sec)>(ts.tv_sec);
|
||||
if (tv.tv_sec != ts.tv_sec) { // narrowing
|
||||
if (ts.tv_sec < 0) {
|
||||
tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
|
||||
tv.tv_usec = 0;
|
||||
} else {
|
||||
tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
|
||||
tv.tv_usec = 1000 * 1000 - 1;
|
||||
}
|
||||
return tv;
|
||||
}
|
||||
tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t
|
||||
return tv;
|
||||
}
|
||||
|
||||
Time FromChrono(const std::chrono::system_clock::time_point& tp) {
|
||||
return time_internal::FromUnixDuration(time_internal::FromChrono(
|
||||
tp - std::chrono::system_clock::from_time_t(0)));
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point ToChronoTime(absl::Time t) {
|
||||
using D = std::chrono::system_clock::duration;
|
||||
auto d = time_internal::ToUnixDuration(t);
|
||||
if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1}));
|
||||
return std::chrono::system_clock::from_time_t(0) +
|
||||
time_internal::ToChronoDuration<D>(d);
|
||||
}
|
||||
|
||||
//
|
||||
// TimeZone
|
||||
//
|
||||
|
||||
absl::TimeZone::CivilInfo TimeZone::At(Time t) const {
|
||||
if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo();
|
||||
if (t == absl::InfinitePast()) return InfinitePastCivilInfo();
|
||||
|
||||
const auto ud = time_internal::ToUnixDuration(t);
|
||||
const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud));
|
||||
const auto al = cz_.lookup(tp);
|
||||
|
||||
TimeZone::CivilInfo ci;
|
||||
ci.cs = CivilSecond(al.cs);
|
||||
ci.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(ud));
|
||||
ci.offset = al.offset;
|
||||
ci.is_dst = al.is_dst;
|
||||
ci.zone_abbr = al.abbr;
|
||||
return ci;
|
||||
}
|
||||
|
||||
absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const {
|
||||
const cctz::civil_second cs(ct);
|
||||
const auto cl = cz_.lookup(cs);
|
||||
|
||||
TimeZone::TimeInfo ti;
|
||||
switch (cl.kind) {
|
||||
case cctz::time_zone::civil_lookup::UNIQUE:
|
||||
ti.kind = TimeZone::TimeInfo::UNIQUE;
|
||||
break;
|
||||
case cctz::time_zone::civil_lookup::SKIPPED:
|
||||
ti.kind = TimeZone::TimeInfo::SKIPPED;
|
||||
break;
|
||||
case cctz::time_zone::civil_lookup::REPEATED:
|
||||
ti.kind = TimeZone::TimeInfo::REPEATED;
|
||||
break;
|
||||
}
|
||||
ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_);
|
||||
ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_);
|
||||
ti.post = MakeTimeWithOverflow(cl.post, cs, cz_);
|
||||
return ti;
|
||||
}
|
||||
|
||||
bool TimeZone::NextTransition(Time t, CivilTransition* trans) const {
|
||||
return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans);
|
||||
}
|
||||
|
||||
bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const {
|
||||
return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans);
|
||||
}
|
||||
|
||||
//
|
||||
// Conversions involving time zones.
|
||||
//
|
||||
ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
|
||||
absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
|
||||
int min, int sec, TimeZone tz) {
|
||||
// Avoids years that are too extreme for CivilSecond to normalize.
|
||||
if (year > 300000000000) return InfiniteFutureTimeConversion();
|
||||
if (year < -300000000000) return InfinitePastTimeConversion();
|
||||
|
||||
const CivilSecond cs(year, mon, day, hour, min, sec);
|
||||
const auto ti = tz.At(cs);
|
||||
|
||||
TimeConversion tc;
|
||||
tc.pre = ti.pre;
|
||||
tc.trans = ti.trans;
|
||||
tc.post = ti.post;
|
||||
switch (ti.kind) {
|
||||
case TimeZone::TimeInfo::UNIQUE:
|
||||
tc.kind = TimeConversion::UNIQUE;
|
||||
break;
|
||||
case TimeZone::TimeInfo::SKIPPED:
|
||||
tc.kind = TimeConversion::SKIPPED;
|
||||
break;
|
||||
case TimeZone::TimeInfo::REPEATED:
|
||||
tc.kind = TimeConversion::REPEATED;
|
||||
break;
|
||||
}
|
||||
tc.normalized = false;
|
||||
if (year != cs.year() || mon != cs.month() || day != cs.day() ||
|
||||
hour != cs.hour() || min != cs.minute() || sec != cs.second()) {
|
||||
tc.normalized = true;
|
||||
}
|
||||
return tc;
|
||||
}
|
||||
ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
|
||||
|
||||
absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
|
||||
civil_year_t tm_year = tm.tm_year;
|
||||
// Avoids years that are too extreme for CivilSecond to normalize.
|
||||
if (tm_year > 300000000000ll) return InfiniteFuture();
|
||||
if (tm_year < -300000000000ll) return InfinitePast();
|
||||
int tm_mon = tm.tm_mon;
|
||||
if (tm_mon == std::numeric_limits<int>::max()) {
|
||||
tm_mon -= 12;
|
||||
tm_year += 1;
|
||||
}
|
||||
const auto ti = tz.At(CivilSecond(tm_year + 1900, tm_mon + 1, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec));
|
||||
return tm.tm_isdst == 0 ? ti.post : ti.pre;
|
||||
}
|
||||
|
||||
struct tm ToTM(absl::Time t, absl::TimeZone tz) {
|
||||
struct tm tm = {};
|
||||
|
||||
const auto ci = tz.At(t);
|
||||
const auto& cs = ci.cs;
|
||||
tm.tm_sec = cs.second();
|
||||
tm.tm_min = cs.minute();
|
||||
tm.tm_hour = cs.hour();
|
||||
tm.tm_mday = cs.day();
|
||||
tm.tm_mon = cs.month() - 1;
|
||||
|
||||
// Saturates tm.tm_year in cases of over/underflow, accounting for the fact
|
||||
// that tm.tm_year is years since 1900.
|
||||
if (cs.year() < std::numeric_limits<int>::min() + 1900) {
|
||||
tm.tm_year = std::numeric_limits<int>::min();
|
||||
} else if (cs.year() > std::numeric_limits<int>::max()) {
|
||||
tm.tm_year = std::numeric_limits<int>::max() - 1900;
|
||||
} else {
|
||||
tm.tm_year = static_cast<int>(cs.year() - 1900);
|
||||
}
|
||||
|
||||
switch (GetWeekday(cs)) {
|
||||
case Weekday::sunday:
|
||||
tm.tm_wday = 0;
|
||||
break;
|
||||
case Weekday::monday:
|
||||
tm.tm_wday = 1;
|
||||
break;
|
||||
case Weekday::tuesday:
|
||||
tm.tm_wday = 2;
|
||||
break;
|
||||
case Weekday::wednesday:
|
||||
tm.tm_wday = 3;
|
||||
break;
|
||||
case Weekday::thursday:
|
||||
tm.tm_wday = 4;
|
||||
break;
|
||||
case Weekday::friday:
|
||||
tm.tm_wday = 5;
|
||||
break;
|
||||
case Weekday::saturday:
|
||||
tm.tm_wday = 6;
|
||||
break;
|
||||
}
|
||||
tm.tm_yday = GetYearDay(cs) - 1;
|
||||
tm.tm_isdst = ci.is_dst ? 1 : 0;
|
||||
|
||||
return tm;
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
1815
Pods/abseil/absl/time/time.h
generated
Normal file
1815
Pods/abseil/absl/time/time.h
generated
Normal file
@@ -0,0 +1,1815 @@
|
||||
// Copyright 2017 The Abseil Authors.
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
// -----------------------------------------------------------------------------
|
||||
// File: time.h
|
||||
// -----------------------------------------------------------------------------
|
||||
//
|
||||
// This header file defines abstractions for computing with absolute points
|
||||
// in time, durations of time, and formatting and parsing time within a given
|
||||
// time zone. The following abstractions are defined:
|
||||
//
|
||||
// * `absl::Time` defines an absolute, specific instance in time
|
||||
// * `absl::Duration` defines a signed, fixed-length span of time
|
||||
// * `absl::TimeZone` defines geopolitical time zone regions (as collected
|
||||
// within the IANA Time Zone database (https://www.iana.org/time-zones)).
|
||||
//
|
||||
// Note: Absolute times are distinct from civil times, which refer to the
|
||||
// human-scale time commonly represented by `YYYY-MM-DD hh:mm:ss`. The mapping
|
||||
// between absolute and civil times can be specified by use of time zones
|
||||
// (`absl::TimeZone` within this API). That is:
|
||||
//
|
||||
// Civil Time = F(Absolute Time, Time Zone)
|
||||
// Absolute Time = G(Civil Time, Time Zone)
|
||||
//
|
||||
// See civil_time.h for abstractions related to constructing and manipulating
|
||||
// civil time.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::TimeZone nyc;
|
||||
// // LoadTimeZone() may fail so it's always better to check for success.
|
||||
// if (!absl::LoadTimeZone("America/New_York", &nyc)) {
|
||||
// // handle error case
|
||||
// }
|
||||
//
|
||||
// // My flight leaves NYC on Jan 2, 2017 at 03:04:05
|
||||
// absl::CivilSecond cs(2017, 1, 2, 3, 4, 5);
|
||||
// absl::Time takeoff = absl::FromCivil(cs, nyc);
|
||||
//
|
||||
// absl::Duration flight_duration = absl::Hours(21) + absl::Minutes(35);
|
||||
// absl::Time landing = takeoff + flight_duration;
|
||||
//
|
||||
// absl::TimeZone syd;
|
||||
// if (!absl::LoadTimeZone("Australia/Sydney", &syd)) {
|
||||
// // handle error case
|
||||
// }
|
||||
// std::string s = absl::FormatTime(
|
||||
// "My flight will land in Sydney on %Y-%m-%d at %H:%M:%S",
|
||||
// landing, syd);
|
||||
|
||||
#ifndef ABSL_TIME_TIME_H_
|
||||
#define ABSL_TIME_TIME_H_
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
#include <sys/time.h>
|
||||
#else
|
||||
// We don't include `winsock2.h` because it drags in `windows.h` and friends,
|
||||
// and they define conflicting macros like OPAQUE, ERROR, and more. This has the
|
||||
// potential to break Abseil users.
|
||||
//
|
||||
// Instead we only forward declare `timeval` and require Windows users include
|
||||
// `winsock2.h` themselves. This is both inconsistent and troublesome, but so is
|
||||
// including 'windows.h' so we are picking the lesser of two evils here.
|
||||
struct timeval;
|
||||
#endif
|
||||
#include <chrono> // NOLINT(build/c++11)
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <ctime>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/base/config.h"
|
||||
#include "absl/base/macros.h"
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/time/civil_time.h"
|
||||
#include "absl/time/internal/cctz/include/cctz/time_zone.h"
|
||||
|
||||
namespace absl {
|
||||
ABSL_NAMESPACE_BEGIN
|
||||
|
||||
class Duration; // Defined below
|
||||
class Time; // Defined below
|
||||
class TimeZone; // Defined below
|
||||
|
||||
namespace time_internal {
|
||||
int64_t IDivDuration(bool satq, Duration num, Duration den, Duration* rem);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixDuration(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration ToUnixDuration(Time t);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t GetRepHi(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr uint32_t GetRepLo(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration MakeDuration(int64_t hi,
|
||||
uint32_t lo);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration MakeDuration(int64_t hi,
|
||||
int64_t lo);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration MakePosDoubleDuration(double n);
|
||||
constexpr int64_t kTicksPerNanosecond = 4;
|
||||
constexpr int64_t kTicksPerSecond = 1000 * 1000 * 1000 * kTicksPerNanosecond;
|
||||
template <std::intmax_t N>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v,
|
||||
std::ratio<1, N>);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v,
|
||||
std::ratio<60>);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v,
|
||||
std::ratio<3600>);
|
||||
template <typename T>
|
||||
using EnableIfIntegral = typename std::enable_if<
|
||||
std::is_integral<T>::value || std::is_enum<T>::value, int>::type;
|
||||
template <typename T>
|
||||
using EnableIfFloat =
|
||||
typename std::enable_if<std::is_floating_point<T>::value, int>::type;
|
||||
} // namespace time_internal
|
||||
|
||||
// Duration
|
||||
//
|
||||
// The `absl::Duration` class represents a signed, fixed-length amount of time.
|
||||
// A `Duration` is generated using a unit-specific factory function, or is
|
||||
// the result of subtracting one `absl::Time` from another. Durations behave
|
||||
// like unit-safe integers and they support all the natural integer-like
|
||||
// arithmetic operations. Arithmetic overflows and saturates at +/- infinity.
|
||||
// `Duration` should be passed by value rather than const reference.
|
||||
//
|
||||
// Factory functions `Nanoseconds()`, `Microseconds()`, `Milliseconds()`,
|
||||
// `Seconds()`, `Minutes()`, `Hours()` and `InfiniteDuration()` allow for
|
||||
// creation of constexpr `Duration` values
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// constexpr absl::Duration ten_ns = absl::Nanoseconds(10);
|
||||
// constexpr absl::Duration min = absl::Minutes(1);
|
||||
// constexpr absl::Duration hour = absl::Hours(1);
|
||||
// absl::Duration dur = 60 * min; // dur == hour
|
||||
// absl::Duration half_sec = absl::Milliseconds(500);
|
||||
// absl::Duration quarter_sec = 0.25 * absl::Seconds(1);
|
||||
//
|
||||
// `Duration` values can be easily converted to an integral number of units
|
||||
// using the division operator.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// constexpr absl::Duration dur = absl::Milliseconds(1500);
|
||||
// int64_t ns = dur / absl::Nanoseconds(1); // ns == 1500000000
|
||||
// int64_t ms = dur / absl::Milliseconds(1); // ms == 1500
|
||||
// int64_t sec = dur / absl::Seconds(1); // sec == 1 (subseconds truncated)
|
||||
// int64_t min = dur / absl::Minutes(1); // min == 0
|
||||
//
|
||||
// See the `IDivDuration()` and `FDivDuration()` functions below for details on
|
||||
// how to access the fractional parts of the quotient.
|
||||
//
|
||||
// Alternatively, conversions can be performed using helpers such as
|
||||
// `ToInt64Microseconds()` and `ToDoubleSeconds()`.
|
||||
class Duration {
|
||||
public:
|
||||
// Value semantics.
|
||||
constexpr Duration() : rep_hi_(0), rep_lo_(0) {} // zero-length duration
|
||||
|
||||
// Copyable.
|
||||
#if !defined(__clang__) && defined(_MSC_VER) && _MSC_VER < 1930
|
||||
// Explicitly defining the constexpr copy constructor avoids an MSVC bug.
|
||||
constexpr Duration(const Duration& d)
|
||||
: rep_hi_(d.rep_hi_), rep_lo_(d.rep_lo_) {}
|
||||
#else
|
||||
constexpr Duration(const Duration& d) = default;
|
||||
#endif
|
||||
Duration& operator=(const Duration& d) = default;
|
||||
|
||||
// Compound assignment operators.
|
||||
Duration& operator+=(Duration d);
|
||||
Duration& operator-=(Duration d);
|
||||
Duration& operator*=(int64_t r);
|
||||
Duration& operator*=(double r);
|
||||
Duration& operator/=(int64_t r);
|
||||
Duration& operator/=(double r);
|
||||
Duration& operator%=(Duration rhs);
|
||||
|
||||
// Overloads that forward to either the int64_t or double overloads above.
|
||||
// Integer operands must be representable as int64_t. Integer division is
|
||||
// truncating, so values less than the resolution will be returned as zero.
|
||||
// Floating-point multiplication and division is rounding (halfway cases
|
||||
// rounding away from zero), so values less than the resolution may be
|
||||
// returned as either the resolution or zero. In particular, `d / 2.0`
|
||||
// can produce `d` when it is the resolution and "even".
|
||||
template <typename T, time_internal::EnableIfIntegral<T> = 0>
|
||||
Duration& operator*=(T r) {
|
||||
int64_t x = r;
|
||||
return *this *= x;
|
||||
}
|
||||
|
||||
template <typename T, time_internal::EnableIfIntegral<T> = 0>
|
||||
Duration& operator/=(T r) {
|
||||
int64_t x = r;
|
||||
return *this /= x;
|
||||
}
|
||||
|
||||
template <typename T, time_internal::EnableIfFloat<T> = 0>
|
||||
Duration& operator*=(T r) {
|
||||
double x = r;
|
||||
return *this *= x;
|
||||
}
|
||||
|
||||
template <typename T, time_internal::EnableIfFloat<T> = 0>
|
||||
Duration& operator/=(T r) {
|
||||
double x = r;
|
||||
return *this /= x;
|
||||
}
|
||||
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, Duration d) {
|
||||
return H::combine(std::move(h), d.rep_hi_.Get(), d.rep_lo_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend constexpr int64_t time_internal::GetRepHi(Duration d);
|
||||
friend constexpr uint32_t time_internal::GetRepLo(Duration d);
|
||||
friend constexpr Duration time_internal::MakeDuration(int64_t hi,
|
||||
uint32_t lo);
|
||||
constexpr Duration(int64_t hi, uint32_t lo) : rep_hi_(hi), rep_lo_(lo) {}
|
||||
|
||||
// We store `rep_hi_` 4-byte rather than 8-byte aligned to avoid 4 bytes of
|
||||
// tail padding.
|
||||
class HiRep {
|
||||
public:
|
||||
// Default constructor default-initializes `hi_`, which has the same
|
||||
// semantics as default-initializing an `int64_t` (undetermined value).
|
||||
HiRep() = default;
|
||||
|
||||
HiRep(const HiRep&) = default;
|
||||
HiRep& operator=(const HiRep&) = default;
|
||||
|
||||
explicit constexpr HiRep(const int64_t value)
|
||||
: // C++17 forbids default-initialization in constexpr contexts. We can
|
||||
// remove this in C++20.
|
||||
#if defined(ABSL_IS_BIG_ENDIAN) && ABSL_IS_BIG_ENDIAN
|
||||
hi_(0),
|
||||
lo_(0)
|
||||
#else
|
||||
lo_(0),
|
||||
hi_(0)
|
||||
#endif
|
||||
{
|
||||
*this = value;
|
||||
}
|
||||
|
||||
constexpr int64_t Get() const {
|
||||
const uint64_t unsigned_value =
|
||||
(static_cast<uint64_t>(hi_) << 32) | static_cast<uint64_t>(lo_);
|
||||
// `static_cast<int64_t>(unsigned_value)` is implementation-defined
|
||||
// before c++20. On all supported platforms the behaviour is that mandated
|
||||
// by c++20, i.e. "If the destination type is signed, [...] the result is
|
||||
// the unique value of the destination type equal to the source value
|
||||
// modulo 2^n, where n is the number of bits used to represent the
|
||||
// destination type."
|
||||
static_assert(
|
||||
(static_cast<int64_t>((std::numeric_limits<uint64_t>::max)()) ==
|
||||
int64_t{-1}) &&
|
||||
(static_cast<int64_t>(static_cast<uint64_t>(
|
||||
(std::numeric_limits<int64_t>::max)()) +
|
||||
1) ==
|
||||
(std::numeric_limits<int64_t>::min)()),
|
||||
"static_cast<int64_t>(uint64_t) does not have c++20 semantics");
|
||||
return static_cast<int64_t>(unsigned_value);
|
||||
}
|
||||
|
||||
constexpr HiRep& operator=(const int64_t value) {
|
||||
// "If the destination type is unsigned, the resulting value is the
|
||||
// smallest unsigned value equal to the source value modulo 2^n
|
||||
// where `n` is the number of bits used to represent the destination
|
||||
// type".
|
||||
const auto unsigned_value = static_cast<uint64_t>(value);
|
||||
hi_ = static_cast<uint32_t>(unsigned_value >> 32);
|
||||
lo_ = static_cast<uint32_t>(unsigned_value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
// Notes:
|
||||
// - Ideally we would use a `char[]` and `std::bitcast`, but the latter
|
||||
// does not exist (and is not constexpr in `absl`) before c++20.
|
||||
// - Order is optimized depending on endianness so that the compiler can
|
||||
// turn `Get()` (resp. `operator=()`) into a single 8-byte load (resp.
|
||||
// store).
|
||||
#if defined(ABSL_IS_BIG_ENDIAN) && ABSL_IS_BIG_ENDIAN
|
||||
uint32_t hi_;
|
||||
uint32_t lo_;
|
||||
#else
|
||||
uint32_t lo_;
|
||||
uint32_t hi_;
|
||||
#endif
|
||||
};
|
||||
HiRep rep_hi_;
|
||||
uint32_t rep_lo_;
|
||||
};
|
||||
|
||||
// Relational Operators
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<(Duration lhs,
|
||||
Duration rhs);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator>(Duration lhs,
|
||||
Duration rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator>=(Duration lhs,
|
||||
Duration rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<=(Duration lhs,
|
||||
Duration rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator==(Duration lhs,
|
||||
Duration rhs);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator!=(Duration lhs,
|
||||
Duration rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
// Additive Operators
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration operator-(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration operator+(Duration lhs,
|
||||
Duration rhs) {
|
||||
return lhs += rhs;
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration operator-(Duration lhs,
|
||||
Duration rhs) {
|
||||
return lhs -= rhs;
|
||||
}
|
||||
|
||||
// Multiplicative Operators
|
||||
// Integer operands must be representable as int64_t.
|
||||
template <typename T>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration operator*(Duration lhs, T rhs) {
|
||||
return lhs *= rhs;
|
||||
}
|
||||
template <typename T>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration operator*(T lhs, Duration rhs) {
|
||||
return rhs *= lhs;
|
||||
}
|
||||
template <typename T>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration operator/(Duration lhs, T rhs) {
|
||||
return lhs /= rhs;
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t operator/(Duration lhs,
|
||||
Duration rhs) {
|
||||
return time_internal::IDivDuration(true, lhs, rhs,
|
||||
&lhs); // trunc towards zero
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration operator%(Duration lhs,
|
||||
Duration rhs) {
|
||||
return lhs %= rhs;
|
||||
}
|
||||
|
||||
// IDivDuration()
|
||||
//
|
||||
// Divides a numerator `Duration` by a denominator `Duration`, returning the
|
||||
// quotient and remainder. The remainder always has the same sign as the
|
||||
// numerator. The returned quotient and remainder respect the identity:
|
||||
//
|
||||
// numerator = denominator * quotient + remainder
|
||||
//
|
||||
// Returned quotients are capped to the range of `int64_t`, with the difference
|
||||
// spilling into the remainder to uphold the above identity. This means that the
|
||||
// remainder returned could differ from the remainder returned by
|
||||
// `Duration::operator%` for huge quotients.
|
||||
//
|
||||
// See also the notes on `InfiniteDuration()` below regarding the behavior of
|
||||
// division involving zero and infinite durations.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// constexpr absl::Duration a =
|
||||
// absl::Seconds(std::numeric_limits<int64_t>::max()); // big
|
||||
// constexpr absl::Duration b = absl::Nanoseconds(1); // small
|
||||
//
|
||||
// absl::Duration rem = a % b;
|
||||
// // rem == absl::ZeroDuration()
|
||||
//
|
||||
// // Here, q would overflow int64_t, so rem accounts for the difference.
|
||||
// int64_t q = absl::IDivDuration(a, b, &rem);
|
||||
// // q == std::numeric_limits<int64_t>::max(), rem == a - b * q
|
||||
inline int64_t IDivDuration(Duration num, Duration den, Duration* rem) {
|
||||
return time_internal::IDivDuration(true, num, den,
|
||||
rem); // trunc towards zero
|
||||
}
|
||||
|
||||
// FDivDuration()
|
||||
//
|
||||
// Divides a `Duration` numerator into a fractional number of units of a
|
||||
// `Duration` denominator.
|
||||
//
|
||||
// See also the notes on `InfiniteDuration()` below regarding the behavior of
|
||||
// division involving zero and infinite durations.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// double d = absl::FDivDuration(absl::Milliseconds(1500), absl::Seconds(1));
|
||||
// // d == 1.5
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION double FDivDuration(Duration num, Duration den);
|
||||
|
||||
// ZeroDuration()
|
||||
//
|
||||
// Returns a zero-length duration. This function behaves just like the default
|
||||
// constructor, but the name helps make the semantics clear at call sites.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration ZeroDuration() {
|
||||
return Duration();
|
||||
}
|
||||
|
||||
// AbsDuration()
|
||||
//
|
||||
// Returns the absolute value of a duration.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration AbsDuration(Duration d) {
|
||||
return (d < ZeroDuration()) ? -d : d;
|
||||
}
|
||||
|
||||
// Trunc()
|
||||
//
|
||||
// Truncates a duration (toward zero) to a multiple of a non-zero unit.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::Duration d = absl::Nanoseconds(123456789);
|
||||
// absl::Duration a = absl::Trunc(d, absl::Microseconds(1)); // 123456us
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration Trunc(Duration d, Duration unit);
|
||||
|
||||
// Floor()
|
||||
//
|
||||
// Floors a duration using the passed duration unit to its largest value not
|
||||
// greater than the duration.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::Duration d = absl::Nanoseconds(123456789);
|
||||
// absl::Duration b = absl::Floor(d, absl::Microseconds(1)); // 123456us
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration Floor(Duration d, Duration unit);
|
||||
|
||||
// Ceil()
|
||||
//
|
||||
// Returns the ceiling of a duration using the passed duration unit to its
|
||||
// smallest value not less than the duration.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::Duration d = absl::Nanoseconds(123456789);
|
||||
// absl::Duration c = absl::Ceil(d, absl::Microseconds(1)); // 123457us
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration Ceil(Duration d, Duration unit);
|
||||
|
||||
// InfiniteDuration()
|
||||
//
|
||||
// Returns an infinite `Duration`. To get a `Duration` representing negative
|
||||
// infinity, use `-InfiniteDuration()`.
|
||||
//
|
||||
// Duration arithmetic overflows to +/- infinity and saturates. In general,
|
||||
// arithmetic with `Duration` infinities is similar to IEEE 754 infinities
|
||||
// except where IEEE 754 NaN would be involved, in which case +/-
|
||||
// `InfiniteDuration()` is used in place of a "nan" Duration.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// constexpr absl::Duration inf = absl::InfiniteDuration();
|
||||
// const absl::Duration d = ... any finite duration ...
|
||||
//
|
||||
// inf == inf + inf
|
||||
// inf == inf + d
|
||||
// inf == inf - inf
|
||||
// -inf == d - inf
|
||||
//
|
||||
// inf == d * 1e100
|
||||
// inf == inf / 2
|
||||
// 0 == d / inf
|
||||
// INT64_MAX == inf / d
|
||||
//
|
||||
// d < inf
|
||||
// -inf < d
|
||||
//
|
||||
// // Division by zero returns infinity, or INT64_MIN/MAX where appropriate.
|
||||
// inf == d / 0
|
||||
// INT64_MAX == d / absl::ZeroDuration()
|
||||
//
|
||||
// The examples involving the `/` operator above also apply to `IDivDuration()`
|
||||
// and `FDivDuration()`.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration InfiniteDuration();
|
||||
|
||||
// Nanoseconds()
|
||||
// Microseconds()
|
||||
// Milliseconds()
|
||||
// Seconds()
|
||||
// Minutes()
|
||||
// Hours()
|
||||
//
|
||||
// Factory functions for constructing `Duration` values from an integral number
|
||||
// of the unit indicated by the factory function's name. The number must be
|
||||
// representable as int64_t.
|
||||
//
|
||||
// NOTE: no "Days()" factory function exists because "a day" is ambiguous.
|
||||
// Civil days are not always 24 hours long, and a 24-hour duration often does
|
||||
// not correspond with a civil day. If a 24-hour duration is needed, use
|
||||
// `absl::Hours(24)`. If you actually want a civil day, use absl::CivilDay
|
||||
// from civil_time.h.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::Duration a = absl::Seconds(60);
|
||||
// absl::Duration b = absl::Minutes(1); // b == a
|
||||
template <typename T, time_internal::EnableIfIntegral<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Nanoseconds(T n) {
|
||||
return time_internal::FromInt64(n, std::nano{});
|
||||
}
|
||||
template <typename T, time_internal::EnableIfIntegral<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Microseconds(T n) {
|
||||
return time_internal::FromInt64(n, std::micro{});
|
||||
}
|
||||
template <typename T, time_internal::EnableIfIntegral<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Milliseconds(T n) {
|
||||
return time_internal::FromInt64(n, std::milli{});
|
||||
}
|
||||
template <typename T, time_internal::EnableIfIntegral<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Seconds(T n) {
|
||||
return time_internal::FromInt64(n, std::ratio<1>{});
|
||||
}
|
||||
template <typename T, time_internal::EnableIfIntegral<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Minutes(T n) {
|
||||
return time_internal::FromInt64(n, std::ratio<60>{});
|
||||
}
|
||||
template <typename T, time_internal::EnableIfIntegral<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration Hours(T n) {
|
||||
return time_internal::FromInt64(n, std::ratio<3600>{});
|
||||
}
|
||||
|
||||
// Factory overloads for constructing `Duration` values from a floating-point
|
||||
// number of the unit indicated by the factory function's name. These functions
|
||||
// exist for convenience, but they are not as efficient as the integral
|
||||
// factories, which should be preferred.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// auto a = absl::Seconds(1.5); // OK
|
||||
// auto b = absl::Milliseconds(1500); // BETTER
|
||||
template <typename T, time_internal::EnableIfFloat<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration Nanoseconds(T n) {
|
||||
return n * Nanoseconds(1);
|
||||
}
|
||||
template <typename T, time_internal::EnableIfFloat<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration Microseconds(T n) {
|
||||
return n * Microseconds(1);
|
||||
}
|
||||
template <typename T, time_internal::EnableIfFloat<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration Milliseconds(T n) {
|
||||
return n * Milliseconds(1);
|
||||
}
|
||||
template <typename T, time_internal::EnableIfFloat<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration Seconds(T n) {
|
||||
if (n >= 0) { // Note: `NaN >= 0` is false.
|
||||
if (n >= static_cast<T>((std::numeric_limits<int64_t>::max)())) {
|
||||
return InfiniteDuration();
|
||||
}
|
||||
return time_internal::MakePosDoubleDuration(n);
|
||||
} else {
|
||||
if (std::isnan(n))
|
||||
return std::signbit(n) ? -InfiniteDuration() : InfiniteDuration();
|
||||
if (n <= (std::numeric_limits<int64_t>::min)()) return -InfiniteDuration();
|
||||
return -time_internal::MakePosDoubleDuration(-n);
|
||||
}
|
||||
}
|
||||
template <typename T, time_internal::EnableIfFloat<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration Minutes(T n) {
|
||||
return n * Minutes(1);
|
||||
}
|
||||
template <typename T, time_internal::EnableIfFloat<T> = 0>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration Hours(T n) {
|
||||
return n * Hours(1);
|
||||
}
|
||||
|
||||
// ToInt64Nanoseconds()
|
||||
// ToInt64Microseconds()
|
||||
// ToInt64Milliseconds()
|
||||
// ToInt64Seconds()
|
||||
// ToInt64Minutes()
|
||||
// ToInt64Hours()
|
||||
//
|
||||
// Helper functions that convert a Duration to an integral count of the
|
||||
// indicated unit. These return the same results as the `IDivDuration()`
|
||||
// function, though they usually do so more efficiently; see the
|
||||
// documentation of `IDivDuration()` for details about overflow, etc.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::Duration d = absl::Milliseconds(1500);
|
||||
// int64_t isec = absl::ToInt64Seconds(d); // isec == 1
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Nanoseconds(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Microseconds(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Milliseconds(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Seconds(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Minutes(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64Hours(Duration d);
|
||||
|
||||
// ToDoubleNanoseconds()
|
||||
// ToDoubleMicroseconds()
|
||||
// ToDoubleMilliseconds()
|
||||
// ToDoubleSeconds()
|
||||
// ToDoubleMinutes()
|
||||
// ToDoubleHours()
|
||||
//
|
||||
// Helper functions that convert a Duration to a floating point count of the
|
||||
// indicated unit. These functions are shorthand for the `FDivDuration()`
|
||||
// function above; see its documentation for details about overflow, etc.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::Duration d = absl::Milliseconds(1500);
|
||||
// double dsec = absl::ToDoubleSeconds(d); // dsec == 1.5
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleNanoseconds(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleMicroseconds(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleMilliseconds(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleSeconds(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleMinutes(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION double ToDoubleHours(Duration d);
|
||||
|
||||
// FromChrono()
|
||||
//
|
||||
// Converts any of the pre-defined std::chrono durations to an absl::Duration.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// std::chrono::milliseconds ms(123);
|
||||
// absl::Duration d = absl::FromChrono(ms);
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::nanoseconds& d);
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::microseconds& d);
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::milliseconds& d);
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::seconds& d);
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::minutes& d);
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::hours& d);
|
||||
|
||||
// ToChronoNanoseconds()
|
||||
// ToChronoMicroseconds()
|
||||
// ToChronoMilliseconds()
|
||||
// ToChronoSeconds()
|
||||
// ToChronoMinutes()
|
||||
// ToChronoHours()
|
||||
//
|
||||
// Converts an absl::Duration to any of the pre-defined std::chrono durations.
|
||||
// If overflow would occur, the returned value will saturate at the min/max
|
||||
// chrono duration value instead.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::Duration d = absl::Microseconds(123);
|
||||
// auto x = absl::ToChronoMicroseconds(d);
|
||||
// auto y = absl::ToChronoNanoseconds(d); // x == y
|
||||
// auto z = absl::ToChronoSeconds(absl::InfiniteDuration());
|
||||
// // z == std::chrono::seconds::max()
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::nanoseconds ToChronoNanoseconds(
|
||||
Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::microseconds ToChronoMicroseconds(
|
||||
Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::milliseconds ToChronoMilliseconds(
|
||||
Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::seconds ToChronoSeconds(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::minutes ToChronoMinutes(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::hours ToChronoHours(Duration d);
|
||||
|
||||
// FormatDuration()
|
||||
//
|
||||
// Returns a string representing the duration in the form "72h3m0.5s".
|
||||
// Returns "inf" or "-inf" for +/- `InfiniteDuration()`.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION std::string FormatDuration(Duration d);
|
||||
|
||||
// Output stream operator.
|
||||
inline std::ostream& operator<<(std::ostream& os, Duration d) {
|
||||
return os << FormatDuration(d);
|
||||
}
|
||||
|
||||
// Support for StrFormat(), StrCat() etc.
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, Duration d) {
|
||||
sink.Append(FormatDuration(d));
|
||||
}
|
||||
|
||||
// ParseDuration()
|
||||
//
|
||||
// Parses a duration string consisting of a possibly signed sequence of
|
||||
// decimal numbers, each with an optional fractional part and a unit
|
||||
// suffix. The valid suffixes are "ns", "us" "ms", "s", "m", and "h".
|
||||
// Simple examples include "300ms", "-1.5h", and "2h45m". Parses "0" as
|
||||
// `ZeroDuration()`. Parses "inf" and "-inf" as +/- `InfiniteDuration()`.
|
||||
bool ParseDuration(absl::string_view dur_string, Duration* d);
|
||||
|
||||
// AbslParseFlag()
|
||||
//
|
||||
// Parses a command-line flag string representation `text` into a Duration
|
||||
// value. Duration flags must be specified in a format that is valid input for
|
||||
// `absl::ParseDuration()`.
|
||||
bool AbslParseFlag(absl::string_view text, Duration* dst, std::string* error);
|
||||
|
||||
|
||||
// AbslUnparseFlag()
|
||||
//
|
||||
// Unparses a Duration value into a command-line string representation using
|
||||
// the format specified by `absl::ParseDuration()`.
|
||||
std::string AbslUnparseFlag(Duration d);
|
||||
|
||||
ABSL_DEPRECATED("Use AbslParseFlag() instead.")
|
||||
bool ParseFlag(const std::string& text, Duration* dst, std::string* error);
|
||||
ABSL_DEPRECATED("Use AbslUnparseFlag() instead.")
|
||||
std::string UnparseFlag(Duration d);
|
||||
|
||||
// Time
|
||||
//
|
||||
// An `absl::Time` represents a specific instant in time. Arithmetic operators
|
||||
// are provided for naturally expressing time calculations. Instances are
|
||||
// created using `absl::Now()` and the `absl::From*()` factory functions that
|
||||
// accept the gamut of other time representations. Formatting and parsing
|
||||
// functions are provided for conversion to and from strings. `absl::Time`
|
||||
// should be passed by value rather than const reference.
|
||||
//
|
||||
// `absl::Time` assumes there are 60 seconds in a minute, which means the
|
||||
// underlying time scales must be "smeared" to eliminate leap seconds.
|
||||
// See https://developers.google.com/time/smear.
|
||||
//
|
||||
// Even though `absl::Time` supports a wide range of timestamps, exercise
|
||||
// caution when using values in the distant past. `absl::Time` uses the
|
||||
// Proleptic Gregorian calendar, which extends the Gregorian calendar backward
|
||||
// to dates before its introduction in 1582.
|
||||
// See https://en.wikipedia.org/wiki/Proleptic_Gregorian_calendar
|
||||
// for more information. Use the ICU calendar classes to convert a date in
|
||||
// some other calendar (http://userguide.icu-project.org/datetime/calendar).
|
||||
//
|
||||
// Similarly, standardized time zones are a reasonably recent innovation, with
|
||||
// the Greenwich prime meridian being established in 1884. The TZ database
|
||||
// itself does not profess accurate offsets for timestamps prior to 1970. The
|
||||
// breakdown of future timestamps is subject to the whim of regional
|
||||
// governments.
|
||||
//
|
||||
// The `absl::Time` class represents an instant in time as a count of clock
|
||||
// ticks of some granularity (resolution) from some starting point (epoch).
|
||||
//
|
||||
// `absl::Time` uses a resolution that is high enough to avoid loss in
|
||||
// precision, and a range that is wide enough to avoid overflow, when
|
||||
// converting between tick counts in most Google time scales (i.e., resolution
|
||||
// of at least one nanosecond, and range +/-100 billion years). Conversions
|
||||
// between the time scales are performed by truncating (towards negative
|
||||
// infinity) to the nearest representable point.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// absl::Time t1 = ...;
|
||||
// absl::Time t2 = t1 + absl::Minutes(2);
|
||||
// absl::Duration d = t2 - t1; // == absl::Minutes(2)
|
||||
//
|
||||
class Time {
|
||||
public:
|
||||
// Value semantics.
|
||||
|
||||
// Returns the Unix epoch. However, those reading your code may not know
|
||||
// or expect the Unix epoch as the default value, so make your code more
|
||||
// readable by explicitly initializing all instances before use.
|
||||
//
|
||||
// Example:
|
||||
// absl::Time t = absl::UnixEpoch();
|
||||
// absl::Time t = absl::Now();
|
||||
// absl::Time t = absl::TimeFromTimeval(tv);
|
||||
// absl::Time t = absl::InfinitePast();
|
||||
constexpr Time() = default;
|
||||
|
||||
// Copyable.
|
||||
constexpr Time(const Time& t) = default;
|
||||
Time& operator=(const Time& t) = default;
|
||||
|
||||
// Assignment operators.
|
||||
Time& operator+=(Duration d) {
|
||||
rep_ += d;
|
||||
return *this;
|
||||
}
|
||||
Time& operator-=(Duration d) {
|
||||
rep_ -= d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Time::Breakdown
|
||||
//
|
||||
// The calendar and wall-clock (aka "civil time") components of an
|
||||
// `absl::Time` in a certain `absl::TimeZone`. This struct is not
|
||||
// intended to represent an instant in time. So, rather than passing
|
||||
// a `Time::Breakdown` to a function, pass an `absl::Time` and an
|
||||
// `absl::TimeZone`.
|
||||
//
|
||||
// Deprecated. Use `absl::TimeZone::CivilInfo`.
|
||||
struct ABSL_DEPRECATED("Use `absl::TimeZone::CivilInfo`.") Breakdown {
|
||||
int64_t year; // year (e.g., 2013)
|
||||
int month; // month of year [1:12]
|
||||
int day; // day of month [1:31]
|
||||
int hour; // hour of day [0:23]
|
||||
int minute; // minute of hour [0:59]
|
||||
int second; // second of minute [0:59]
|
||||
Duration subsecond; // [Seconds(0):Seconds(1)) if finite
|
||||
int weekday; // 1==Mon, ..., 7=Sun
|
||||
int yearday; // day of year [1:366]
|
||||
|
||||
// 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 FormatTime().
|
||||
// These fields are undefined for InfiniteFuture() and InfinitePast().
|
||||
int offset; // seconds east of UTC
|
||||
bool is_dst; // is offset non-standard?
|
||||
const char* zone_abbr; // time-zone abbreviation (e.g., "PST")
|
||||
};
|
||||
|
||||
// Time::In()
|
||||
//
|
||||
// Returns the breakdown of this instant in the given TimeZone.
|
||||
//
|
||||
// Deprecated. Use `absl::TimeZone::At(Time)`.
|
||||
ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
|
||||
ABSL_DEPRECATED("Use `absl::TimeZone::At(Time)`.")
|
||||
Breakdown In(TimeZone tz) const;
|
||||
ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
|
||||
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, Time t) {
|
||||
return H::combine(std::move(h), t.rep_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend constexpr Time time_internal::FromUnixDuration(Duration d);
|
||||
friend constexpr Duration time_internal::ToUnixDuration(Time t);
|
||||
friend constexpr bool operator<(Time lhs, Time rhs);
|
||||
friend constexpr bool operator==(Time lhs, Time rhs);
|
||||
friend Duration operator-(Time lhs, Time rhs);
|
||||
friend constexpr Time UniversalEpoch();
|
||||
friend constexpr Time InfiniteFuture();
|
||||
friend constexpr Time InfinitePast();
|
||||
constexpr explicit Time(Duration rep) : rep_(rep) {}
|
||||
Duration rep_;
|
||||
};
|
||||
|
||||
// Relational Operators
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<(Time lhs, Time rhs) {
|
||||
return lhs.rep_ < rhs.rep_;
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator>(Time lhs, Time rhs) {
|
||||
return rhs < lhs;
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator>=(Time lhs, Time rhs) {
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<=(Time lhs, Time rhs) {
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator==(Time lhs, Time rhs) {
|
||||
return lhs.rep_ == rhs.rep_;
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator!=(Time lhs, Time rhs) {
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
// Additive Operators
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline Time operator+(Time lhs, Duration rhs) {
|
||||
return lhs += rhs;
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline Time operator+(Duration lhs, Time rhs) {
|
||||
return rhs += lhs;
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline Time operator-(Time lhs, Duration rhs) {
|
||||
return lhs -= rhs;
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration operator-(Time lhs, Time rhs) {
|
||||
return lhs.rep_ - rhs.rep_;
|
||||
}
|
||||
|
||||
// UnixEpoch()
|
||||
//
|
||||
// Returns the `absl::Time` representing "1970-01-01 00:00:00.0 +0000".
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time UnixEpoch() { return Time(); }
|
||||
|
||||
// UniversalEpoch()
|
||||
//
|
||||
// Returns the `absl::Time` representing "0001-01-01 00:00:00.0 +0000", the
|
||||
// epoch of the ICU Universal Time Scale.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time UniversalEpoch() {
|
||||
// 719162 is the number of days from 0001-01-01 to 1970-01-01,
|
||||
// assuming the Gregorian calendar.
|
||||
return Time(
|
||||
time_internal::MakeDuration(-24 * 719162 * int64_t{3600}, uint32_t{0}));
|
||||
}
|
||||
|
||||
// InfiniteFuture()
|
||||
//
|
||||
// Returns an `absl::Time` that is infinitely far in the future.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time InfiniteFuture() {
|
||||
return Time(time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(),
|
||||
~uint32_t{0}));
|
||||
}
|
||||
|
||||
// InfinitePast()
|
||||
//
|
||||
// Returns an `absl::Time` that is infinitely far in the past.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time InfinitePast() {
|
||||
return Time(time_internal::MakeDuration((std::numeric_limits<int64_t>::min)(),
|
||||
~uint32_t{0}));
|
||||
}
|
||||
|
||||
// FromUnixNanos()
|
||||
// FromUnixMicros()
|
||||
// FromUnixMillis()
|
||||
// FromUnixSeconds()
|
||||
// FromTimeT()
|
||||
// FromUDate()
|
||||
// FromUniversal()
|
||||
//
|
||||
// Creates an `absl::Time` from a variety of other representations. See
|
||||
// https://unicode-org.github.io/icu/userguide/datetime/universaltimescale.html
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixNanos(int64_t ns);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixMicros(int64_t us);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixMillis(int64_t ms);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixSeconds(int64_t s);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromTimeT(time_t t);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Time FromUDate(double udate);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Time FromUniversal(int64_t universal);
|
||||
|
||||
// ToUnixNanos()
|
||||
// ToUnixMicros()
|
||||
// ToUnixMillis()
|
||||
// ToUnixSeconds()
|
||||
// ToTimeT()
|
||||
// ToUDate()
|
||||
// ToUniversal()
|
||||
//
|
||||
// Converts an `absl::Time` to a variety of other representations. See
|
||||
// https://unicode-org.github.io/icu/userguide/datetime/universaltimescale.html
|
||||
//
|
||||
// Note that these operations round down toward negative infinity where
|
||||
// necessary to adjust to the resolution of the result type. Beware of
|
||||
// possible time_t over/underflow in ToTime{T,val,spec}() on 32-bit platforms.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToUnixNanos(Time t);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToUnixMicros(Time t);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToUnixMillis(Time t);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToUnixSeconds(Time t);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION time_t ToTimeT(Time t);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION double ToUDate(Time t);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToUniversal(Time t);
|
||||
|
||||
// DurationFromTimespec()
|
||||
// DurationFromTimeval()
|
||||
// ToTimespec()
|
||||
// ToTimeval()
|
||||
// TimeFromTimespec()
|
||||
// TimeFromTimeval()
|
||||
// ToTimespec()
|
||||
// ToTimeval()
|
||||
//
|
||||
// Some APIs use a timespec or a timeval as a Duration (e.g., nanosleep(2)
|
||||
// and select(2)), while others use them as a Time (e.g. clock_gettime(2)
|
||||
// and gettimeofday(2)), so conversion functions are provided for both cases.
|
||||
// The "to timespec/val" direction is easily handled via overloading, but
|
||||
// for "from timespec/val" the desired type is part of the function name.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration DurationFromTimespec(timespec ts);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Duration DurationFromTimeval(timeval tv);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION timespec ToTimespec(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION timeval ToTimeval(Duration d);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Time TimeFromTimespec(timespec ts);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION Time TimeFromTimeval(timeval tv);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION timespec ToTimespec(Time t);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION timeval ToTimeval(Time t);
|
||||
|
||||
// FromChrono()
|
||||
//
|
||||
// Converts a std::chrono::system_clock::time_point to an absl::Time.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// auto tp = std::chrono::system_clock::from_time_t(123);
|
||||
// absl::Time t = absl::FromChrono(tp);
|
||||
// // t == absl::FromTimeT(123)
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION Time
|
||||
FromChrono(const std::chrono::system_clock::time_point& tp);
|
||||
|
||||
// ToChronoTime()
|
||||
//
|
||||
// Converts an absl::Time to a std::chrono::system_clock::time_point. If
|
||||
// overflow would occur, the returned value will saturate at the min/max time
|
||||
// point value instead.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::Time t = absl::FromTimeT(123);
|
||||
// auto tp = absl::ToChronoTime(t);
|
||||
// // tp == std::chrono::system_clock::from_time_t(123);
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION std::chrono::system_clock::time_point
|
||||
ToChronoTime(Time);
|
||||
|
||||
// AbslParseFlag()
|
||||
//
|
||||
// Parses the command-line flag string representation `text` into a Time value.
|
||||
// Time flags must be specified in a format that matches absl::RFC3339_full.
|
||||
//
|
||||
// For example:
|
||||
//
|
||||
// --start_time=2016-01-02T03:04:05.678+08:00
|
||||
//
|
||||
// Note: A UTC offset (or 'Z' indicating a zero-offset from UTC) is required.
|
||||
//
|
||||
// Additionally, if you'd like to specify a time as a count of
|
||||
// seconds/milliseconds/etc from the Unix epoch, use an absl::Duration flag
|
||||
// and add that duration to absl::UnixEpoch() to get an absl::Time.
|
||||
bool AbslParseFlag(absl::string_view text, Time* t, std::string* error);
|
||||
|
||||
// AbslUnparseFlag()
|
||||
//
|
||||
// Unparses a Time value into a command-line string representation using
|
||||
// the format specified by `absl::ParseTime()`.
|
||||
std::string AbslUnparseFlag(Time t);
|
||||
|
||||
ABSL_DEPRECATED("Use AbslParseFlag() instead.")
|
||||
bool ParseFlag(const std::string& text, Time* t, std::string* error);
|
||||
ABSL_DEPRECATED("Use AbslUnparseFlag() instead.")
|
||||
std::string UnparseFlag(Time t);
|
||||
|
||||
// TimeZone
|
||||
//
|
||||
// The `absl::TimeZone` is an opaque, small, value-type class representing a
|
||||
// geo-political region within which particular rules are used for converting
|
||||
// between absolute and civil times (see https://git.io/v59Ly). `absl::TimeZone`
|
||||
// values are named using the TZ identifiers from the IANA Time Zone Database,
|
||||
// such as "America/Los_Angeles" or "Australia/Sydney". `absl::TimeZone` values
|
||||
// are created from factory functions such as `absl::LoadTimeZone()`. Note:
|
||||
// strings like "PST" and "EDT" are not valid TZ identifiers. Prefer to pass by
|
||||
// value rather than const reference.
|
||||
//
|
||||
// For more on the fundamental concepts of time zones, absolute times, and civil
|
||||
// times, see https://github.com/google/cctz#fundamental-concepts
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// absl::TimeZone utc = absl::UTCTimeZone();
|
||||
// absl::TimeZone pst = absl::FixedTimeZone(-8 * 60 * 60);
|
||||
// absl::TimeZone loc = absl::LocalTimeZone();
|
||||
// absl::TimeZone lax;
|
||||
// if (!absl::LoadTimeZone("America/Los_Angeles", &lax)) {
|
||||
// // handle error case
|
||||
// }
|
||||
//
|
||||
// See also:
|
||||
// - https://github.com/google/cctz
|
||||
// - https://www.iana.org/time-zones
|
||||
// - https://en.wikipedia.org/wiki/Zoneinfo
|
||||
class TimeZone {
|
||||
public:
|
||||
explicit TimeZone(time_internal::cctz::time_zone tz) : cz_(tz) {}
|
||||
TimeZone() = default; // UTC, but prefer UTCTimeZone() to be explicit.
|
||||
|
||||
// Copyable.
|
||||
TimeZone(const TimeZone&) = default;
|
||||
TimeZone& operator=(const TimeZone&) = default;
|
||||
|
||||
explicit operator time_internal::cctz::time_zone() const { return cz_; }
|
||||
|
||||
std::string name() const { return cz_.name(); }
|
||||
|
||||
// TimeZone::CivilInfo
|
||||
//
|
||||
// Information about the civil time corresponding to an absolute time.
|
||||
// This struct is not intended to represent an instant in time. So, rather
|
||||
// than passing a `TimeZone::CivilInfo` to a function, pass an `absl::Time`
|
||||
// and an `absl::TimeZone`.
|
||||
struct CivilInfo {
|
||||
CivilSecond cs;
|
||||
Duration subsecond;
|
||||
|
||||
// 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 FormatTime().
|
||||
// These fields are undefined for InfiniteFuture() and InfinitePast().
|
||||
int offset; // seconds east of UTC
|
||||
bool is_dst; // is offset non-standard?
|
||||
const char* zone_abbr; // time-zone abbreviation (e.g., "PST")
|
||||
};
|
||||
|
||||
// TimeZone::At(Time)
|
||||
//
|
||||
// Returns the civil time for this TimeZone at a certain `absl::Time`.
|
||||
// If the input time is infinite, the output civil second will be set to
|
||||
// CivilSecond::max() or min(), and the subsecond will be infinite.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// const auto epoch = lax.At(absl::UnixEpoch());
|
||||
// // epoch.cs == 1969-12-31 16:00:00
|
||||
// // epoch.subsecond == absl::ZeroDuration()
|
||||
// // epoch.offset == -28800
|
||||
// // epoch.is_dst == false
|
||||
// // epoch.abbr == "PST"
|
||||
CivilInfo At(Time t) const;
|
||||
|
||||
// TimeZone::TimeInfo
|
||||
//
|
||||
// Information about the absolute times corresponding to a civil time.
|
||||
// (Subseconds must be handled separately.)
|
||||
//
|
||||
// It is possible for a caller to pass a civil-time value that does
|
||||
// not represent an actual or unique instant in time (due to a shift
|
||||
// in UTC offset in the TimeZone, which results in a discontinuity in
|
||||
// the civil-time components). For example, a daylight-saving-time
|
||||
// transition skips or repeats civil times---in the United States,
|
||||
// March 13, 2011 02:15 never occurred, while November 6, 2011 01:15
|
||||
// occurred twice---so requests for such times are not well-defined.
|
||||
// To account for these possibilities, `absl::TimeZone::TimeInfo` is
|
||||
// richer than just a single `absl::Time`.
|
||||
struct TimeInfo {
|
||||
enum CivilKind {
|
||||
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 pre; // time calculated using the pre-transition offset
|
||||
Time trans; // when the civil-time discontinuity occurred
|
||||
Time post; // time calculated using the post-transition offset
|
||||
};
|
||||
|
||||
// TimeZone::At(CivilSecond)
|
||||
//
|
||||
// Returns an `absl::TimeInfo` containing the absolute time(s) for this
|
||||
// TimeZone at an `absl::CivilSecond`. When the civil time is skipped or
|
||||
// repeated, returns times calculated using the pre-transition and post-
|
||||
// transition UTC offsets, plus the transition time itself.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// // A unique civil time
|
||||
// const auto jan01 = lax.At(absl::CivilSecond(2011, 1, 1, 0, 0, 0));
|
||||
// // jan01.kind == TimeZone::TimeInfo::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
|
||||
// const auto mar13 = lax.At(absl::CivilSecond(2011, 3, 13, 2, 15, 0));
|
||||
// // mar13.kind == TimeZone::TimeInfo::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
|
||||
// const auto nov06 = lax.At(absl::CivilSecond(2011, 11, 6, 1, 15, 0));
|
||||
// // nov06.kind == TimeZone::TimeInfo::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
|
||||
TimeInfo At(CivilSecond ct) const;
|
||||
|
||||
// TimeZone::NextTransition()
|
||||
// TimeZone::PrevTransition()
|
||||
//
|
||||
// Finds the time of the next/previous offset change in this time zone.
|
||||
//
|
||||
// By definition, `NextTransition(t, &trans)` returns false when `t` is
|
||||
// `InfiniteFuture()`, and `PrevTransition(t, &trans)` returns false
|
||||
// when `t` is `InfinitePast()`. If the zone has no transitions, the
|
||||
// result will also be false no matter what the argument.
|
||||
//
|
||||
// Otherwise, when `t` is `InfinitePast()`, `NextTransition(t, &trans)`
|
||||
// returns true and sets `trans` to the first recorded transition. Chains
|
||||
// of calls to `NextTransition()/PrevTransition()` will eventually return
|
||||
// false, but it is unspecified exactly when `NextTransition(t, &trans)`
|
||||
// jumps to false, or what time is set by `PrevTransition(t, &trans)` for
|
||||
// a very distant `t`.
|
||||
//
|
||||
// Note: Enumeration of time-zone transitions is for informational purposes
|
||||
// only. Modern time-related code should not care about when offset changes
|
||||
// occur.
|
||||
//
|
||||
// Example:
|
||||
// absl::TimeZone nyc;
|
||||
// if (!absl::LoadTimeZone("America/New_York", &nyc)) { ... }
|
||||
// const auto now = absl::Now();
|
||||
// auto t = absl::InfinitePast();
|
||||
// absl::TimeZone::CivilTransition trans;
|
||||
// while (t <= now && nyc.NextTransition(t, &trans)) {
|
||||
// // transition: trans.from -> trans.to
|
||||
// t = nyc.At(trans.to).trans;
|
||||
// }
|
||||
struct CivilTransition {
|
||||
CivilSecond from; // the civil time we jump from
|
||||
CivilSecond to; // the civil time we jump to
|
||||
};
|
||||
bool NextTransition(Time t, CivilTransition* trans) const;
|
||||
bool PrevTransition(Time t, CivilTransition* trans) const;
|
||||
|
||||
template <typename H>
|
||||
friend H AbslHashValue(H h, TimeZone tz) {
|
||||
return H::combine(std::move(h), tz.cz_);
|
||||
}
|
||||
|
||||
private:
|
||||
friend bool operator==(TimeZone a, TimeZone b) { return a.cz_ == b.cz_; }
|
||||
friend bool operator!=(TimeZone a, TimeZone b) { return a.cz_ != b.cz_; }
|
||||
friend std::ostream& operator<<(std::ostream& os, TimeZone tz) {
|
||||
return os << tz.name();
|
||||
}
|
||||
|
||||
time_internal::cctz::time_zone cz_;
|
||||
};
|
||||
|
||||
// LoadTimeZone()
|
||||
//
|
||||
// Loads the named zone. May perform I/O on the initial load of the named
|
||||
// zone. If the name is invalid, or some other kind of error occurs, returns
|
||||
// `false` and `*tz` is set to the UTC time zone.
|
||||
inline bool LoadTimeZone(absl::string_view name, TimeZone* tz) {
|
||||
if (name == "localtime") {
|
||||
*tz = TimeZone(time_internal::cctz::local_time_zone());
|
||||
return true;
|
||||
}
|
||||
time_internal::cctz::time_zone cz;
|
||||
const bool b = time_internal::cctz::load_time_zone(std::string(name), &cz);
|
||||
*tz = TimeZone(cz);
|
||||
return b;
|
||||
}
|
||||
|
||||
// FixedTimeZone()
|
||||
//
|
||||
// Returns a TimeZone 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., no offset) instead.
|
||||
inline TimeZone FixedTimeZone(int seconds) {
|
||||
return TimeZone(
|
||||
time_internal::cctz::fixed_time_zone(std::chrono::seconds(seconds)));
|
||||
}
|
||||
|
||||
// UTCTimeZone()
|
||||
//
|
||||
// Convenience method returning the UTC time zone.
|
||||
inline TimeZone UTCTimeZone() {
|
||||
return TimeZone(time_internal::cctz::utc_time_zone());
|
||||
}
|
||||
|
||||
// LocalTimeZone()
|
||||
//
|
||||
// Convenience method returning the local time zone, or UTC if there is
|
||||
// no configured local zone. Warning: Be wary of using LocalTimeZone(),
|
||||
// and particularly so in a server process, as the zone configured for the
|
||||
// local machine should be irrelevant. Prefer an explicit zone name.
|
||||
inline TimeZone LocalTimeZone() {
|
||||
return TimeZone(time_internal::cctz::local_time_zone());
|
||||
}
|
||||
|
||||
// ToCivilSecond()
|
||||
// ToCivilMinute()
|
||||
// ToCivilHour()
|
||||
// ToCivilDay()
|
||||
// ToCivilMonth()
|
||||
// ToCivilYear()
|
||||
//
|
||||
// Helpers for TimeZone::At(Time) to return particularly aligned civil times.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::Time t = ...;
|
||||
// absl::TimeZone tz = ...;
|
||||
// const auto cd = absl::ToCivilDay(t, tz);
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilSecond ToCivilSecond(Time t,
|
||||
TimeZone tz) {
|
||||
return tz.At(t).cs; // already a CivilSecond
|
||||
}
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilMinute ToCivilMinute(Time t,
|
||||
TimeZone tz) {
|
||||
return CivilMinute(tz.At(t).cs);
|
||||
}
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilHour ToCivilHour(Time t, TimeZone tz) {
|
||||
return CivilHour(tz.At(t).cs);
|
||||
}
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilDay ToCivilDay(Time t, TimeZone tz) {
|
||||
return CivilDay(tz.At(t).cs);
|
||||
}
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilMonth ToCivilMonth(Time t,
|
||||
TimeZone tz) {
|
||||
return CivilMonth(tz.At(t).cs);
|
||||
}
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION inline CivilYear ToCivilYear(Time t, TimeZone tz) {
|
||||
return CivilYear(tz.At(t).cs);
|
||||
}
|
||||
|
||||
// FromCivil()
|
||||
//
|
||||
// Helper for TimeZone::At(CivilSecond) that provides "order-preserving
|
||||
// semantics." If the civil time maps to a unique time, that time is
|
||||
// returned. If the civil time is repeated in the given time zone, the
|
||||
// time using the pre-transition offset is returned. Otherwise, the
|
||||
// civil time is skipped in the given time zone, and the transition time
|
||||
// is returned. This means that for any two civil times, ct1 and ct2,
|
||||
// (ct1 < ct2) => (FromCivil(ct1) <= FromCivil(ct2)), the equal case
|
||||
// being when two non-existent civil times map to the same transition time.
|
||||
//
|
||||
// Note: Accepts civil times of any alignment.
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION inline Time FromCivil(CivilSecond ct,
|
||||
TimeZone tz) {
|
||||
const auto ti = tz.At(ct);
|
||||
if (ti.kind == TimeZone::TimeInfo::SKIPPED) return ti.trans;
|
||||
return ti.pre;
|
||||
}
|
||||
|
||||
// TimeConversion
|
||||
//
|
||||
// An `absl::TimeConversion` represents the conversion of year, month, day,
|
||||
// hour, minute, and second values (i.e., a civil time), in a particular
|
||||
// `absl::TimeZone`, to a time instant (an absolute time), as returned by
|
||||
// `absl::ConvertDateTime()`. Legacy version of `absl::TimeZone::TimeInfo`.
|
||||
//
|
||||
// Deprecated. Use `absl::TimeZone::TimeInfo`.
|
||||
struct ABSL_DEPRECATED("Use `absl::TimeZone::TimeInfo`.") TimeConversion {
|
||||
Time pre; // time calculated using the pre-transition offset
|
||||
Time trans; // when the civil-time discontinuity occurred
|
||||
Time post; // time calculated using the post-transition offset
|
||||
|
||||
enum Kind {
|
||||
UNIQUE, // the civil time was singular (pre == trans == post)
|
||||
SKIPPED, // the civil time did not exist
|
||||
REPEATED, // the civil time was ambiguous
|
||||
};
|
||||
Kind kind;
|
||||
|
||||
bool normalized; // input values were outside their valid ranges
|
||||
};
|
||||
|
||||
// ConvertDateTime()
|
||||
//
|
||||
// Legacy version of `absl::TimeZone::At(absl::CivilSecond)` that takes
|
||||
// the civil time as six, separate values (YMDHMS).
|
||||
//
|
||||
// The input month, day, hour, minute, and second values can be outside
|
||||
// of their valid ranges, in which case they will be "normalized" during
|
||||
// the conversion.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// // "October 32" normalizes to "November 1".
|
||||
// absl::TimeConversion tc =
|
||||
// absl::ConvertDateTime(2013, 10, 32, 8, 30, 0, lax);
|
||||
// // tc.kind == TimeConversion::UNIQUE && tc.normalized == true
|
||||
// // absl::ToCivilDay(tc.pre, tz).month() == 11
|
||||
// // absl::ToCivilDay(tc.pre, tz).day() == 1
|
||||
//
|
||||
// Deprecated. Use `absl::TimeZone::At(CivilSecond)`.
|
||||
ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
|
||||
ABSL_DEPRECATED("Use `absl::TimeZone::At(CivilSecond)`.")
|
||||
TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
|
||||
int min, int sec, TimeZone tz);
|
||||
ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
|
||||
|
||||
// FromDateTime()
|
||||
//
|
||||
// A convenience wrapper for `absl::ConvertDateTime()` that simply returns
|
||||
// the "pre" `absl::Time`. That is, the unique result, or the instant that
|
||||
// is correct using the pre-transition offset (as if the transition never
|
||||
// happened).
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::Time t = absl::FromDateTime(2017, 9, 26, 9, 30, 0, lax);
|
||||
// // t = 2017-09-26 09:30:00 -0700
|
||||
//
|
||||
// Deprecated. Use `absl::FromCivil(CivilSecond, TimeZone)`. Note that the
|
||||
// behavior of `FromCivil()` differs from `FromDateTime()` for skipped civil
|
||||
// times. If you care about that see `absl::TimeZone::At(absl::CivilSecond)`.
|
||||
ABSL_DEPRECATED("Use `absl::FromCivil(CivilSecond, TimeZone)`.")
|
||||
inline Time FromDateTime(int64_t year, int mon, int day, int hour, int min,
|
||||
int sec, TimeZone tz) {
|
||||
ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING
|
||||
return ConvertDateTime(year, mon, day, hour, min, sec, tz).pre;
|
||||
ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING
|
||||
}
|
||||
|
||||
// FromTM()
|
||||
//
|
||||
// Converts the `tm_year`, `tm_mon`, `tm_mday`, `tm_hour`, `tm_min`, and
|
||||
// `tm_sec` fields to an `absl::Time` using the given time zone. See ctime(3)
|
||||
// for a description of the expected values of the tm fields. If the civil time
|
||||
// is unique (see `absl::TimeZone::At(absl::CivilSecond)` above), the matching
|
||||
// time instant is returned. Otherwise, the `tm_isdst` field is consulted to
|
||||
// choose between the possible results. For a repeated civil time, `tm_isdst !=
|
||||
// 0` returns the matching DST instant, while `tm_isdst == 0` returns the
|
||||
// matching non-DST instant. For a skipped civil time there is no matching
|
||||
// instant, so `tm_isdst != 0` returns the DST instant, and `tm_isdst == 0`
|
||||
// returns the non-DST instant, that would have matched if the transition never
|
||||
// happened.
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION Time FromTM(const struct tm& tm, TimeZone tz);
|
||||
|
||||
// ToTM()
|
||||
//
|
||||
// Converts the given `absl::Time` to a struct tm using the given time zone.
|
||||
// See ctime(3) for a description of the values of the tm fields.
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION struct tm ToTM(Time t, TimeZone tz);
|
||||
|
||||
// RFC3339_full
|
||||
// RFC3339_sec
|
||||
//
|
||||
// FormatTime()/ParseTime() format specifiers for RFC3339 date/time strings,
|
||||
// with trailing zeros trimmed or with fractional seconds omitted altogether.
|
||||
//
|
||||
// Note that RFC3339_sec[] matches an ISO 8601 extended format for date and
|
||||
// time with UTC offset. Also note the use of "%Y": RFC3339 mandates that
|
||||
// years have exactly four digits, but we allow them to take their natural
|
||||
// width.
|
||||
ABSL_DLL extern const char RFC3339_full[]; // %Y-%m-%d%ET%H:%M:%E*S%Ez
|
||||
ABSL_DLL extern const char RFC3339_sec[]; // %Y-%m-%d%ET%H:%M:%S%Ez
|
||||
|
||||
// RFC1123_full
|
||||
// RFC1123_no_wday
|
||||
//
|
||||
// FormatTime()/ParseTime() format specifiers for RFC1123 date/time strings.
|
||||
ABSL_DLL extern const char RFC1123_full[]; // %a, %d %b %E4Y %H:%M:%S %z
|
||||
ABSL_DLL extern const char RFC1123_no_wday[]; // %d %b %E4Y %H:%M:%S %z
|
||||
|
||||
// FormatTime()
|
||||
//
|
||||
// Formats the given `absl::Time` in the `absl::TimeZone` 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)
|
||||
// - %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.
|
||||
//
|
||||
// We recommend that format strings include the UTC offset (%z, %Ez, or %E*z)
|
||||
// so that the result uniquely identifies a time instant.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// absl::CivilSecond cs(2013, 1, 2, 3, 4, 5);
|
||||
// absl::Time t = absl::FromCivil(cs, lax);
|
||||
// std::string f = absl::FormatTime("%H:%M:%S", t, lax); // "03:04:05"
|
||||
// f = absl::FormatTime("%H:%M:%E3S", t, lax); // "03:04:05.000"
|
||||
//
|
||||
// Note: If the given `absl::Time` is `absl::InfiniteFuture()`, the returned
|
||||
// string will be exactly "infinite-future". If the given `absl::Time` is
|
||||
// `absl::InfinitePast()`, the returned string will be exactly "infinite-past".
|
||||
// In both cases the given format string and `absl::TimeZone` are ignored.
|
||||
//
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION std::string FormatTime(absl::string_view format,
|
||||
Time t, TimeZone tz);
|
||||
|
||||
// Convenience functions that format the given time using the RFC3339_full
|
||||
// format. The first overload uses the provided TimeZone, while the second
|
||||
// uses LocalTimeZone().
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION std::string FormatTime(Time t, TimeZone tz);
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION std::string FormatTime(Time t);
|
||||
|
||||
// Output stream operator.
|
||||
inline std::ostream& operator<<(std::ostream& os, Time t) {
|
||||
return os << FormatTime(t);
|
||||
}
|
||||
|
||||
// Support for StrFormat(), StrCat() etc.
|
||||
template <typename Sink>
|
||||
void AbslStringify(Sink& sink, Time t) {
|
||||
sink.Append(FormatTime(t));
|
||||
}
|
||||
|
||||
// ParseTime()
|
||||
//
|
||||
// Parses an input string according to the provided format string and
|
||||
// returns the corresponding `absl::Time`. Uses strftime()-like formatting
|
||||
// options, with the same extensions as FormatTime(), 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 an absl::Time
|
||||
// that represents "1970-01-01 15:45:00.0 +0000".
|
||||
//
|
||||
// Note that since ParseTime() returns time instants, it makes the most sense
|
||||
// to parse fully-specified date/time strings that include a UTC offset (%z,
|
||||
// %Ez, or %E*z).
|
||||
//
|
||||
// Note also that `absl::ParseTime()` 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 `absl::CivilSecond` does. For example,
|
||||
// it is an error to parse the date "Oct 32, 2013" because 32 is out of range.
|
||||
//
|
||||
// A leap 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 and assigning an error message
|
||||
// to the "err" out param if it is non-null.
|
||||
//
|
||||
// Note: If the input string is exactly "infinite-future", the returned
|
||||
// `absl::Time` will be `absl::InfiniteFuture()` and `true` will be returned.
|
||||
// If the input string is "infinite-past", the returned `absl::Time` will be
|
||||
// `absl::InfinitePast()` and `true` will be returned.
|
||||
//
|
||||
bool ParseTime(absl::string_view format, absl::string_view input, Time* time,
|
||||
std::string* err);
|
||||
|
||||
// Like ParseTime() above, but if the format string does not contain a UTC
|
||||
// offset specification (%z/%Ez/%E*z) then the input is interpreted in the
|
||||
// given TimeZone. This means that the input, by itself, does not identify a
|
||||
// unique instant. Being time-zone dependent, it also admits the possibility
|
||||
// of ambiguity or non-existence, in which case the "pre" time (as defined
|
||||
// by TimeZone::TimeInfo) is returned. For these reasons we recommend that
|
||||
// all date/time strings include a UTC offset so they're context independent.
|
||||
bool ParseTime(absl::string_view format, absl::string_view input, TimeZone tz,
|
||||
Time* time, std::string* err);
|
||||
|
||||
// ============================================================================
|
||||
// Implementation Details Follow
|
||||
// ============================================================================
|
||||
|
||||
namespace time_internal {
|
||||
|
||||
// Creates a Duration with a given representation.
|
||||
// REQUIRES: hi,lo is a valid representation of a Duration as specified
|
||||
// in time/duration.cc.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration MakeDuration(int64_t hi,
|
||||
uint32_t lo = 0) {
|
||||
return Duration(hi, lo);
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration MakeDuration(int64_t hi,
|
||||
int64_t lo) {
|
||||
return MakeDuration(hi, static_cast<uint32_t>(lo));
|
||||
}
|
||||
|
||||
// Make a Duration value from a floating-point number, as long as that number
|
||||
// is in the range [ 0 .. numeric_limits<int64_t>::max ), that is, as long as
|
||||
// it's positive and can be converted to int64_t without risk of UB.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline Duration MakePosDoubleDuration(double n) {
|
||||
const int64_t int_secs = static_cast<int64_t>(n);
|
||||
const uint32_t ticks = static_cast<uint32_t>(
|
||||
std::round((n - static_cast<double>(int_secs)) * kTicksPerSecond));
|
||||
return ticks < kTicksPerSecond
|
||||
? MakeDuration(int_secs, ticks)
|
||||
: MakeDuration(int_secs + 1, ticks - kTicksPerSecond);
|
||||
}
|
||||
|
||||
// Creates a normalized Duration from an almost-normalized (sec,ticks)
|
||||
// pair. sec may be positive or negative. ticks must be in the range
|
||||
// -kTicksPerSecond < *ticks < kTicksPerSecond. If ticks is negative it
|
||||
// will be normalized to a positive value in the resulting Duration.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration MakeNormalizedDuration(
|
||||
int64_t sec, int64_t ticks) {
|
||||
return (ticks < 0) ? MakeDuration(sec - 1, ticks + kTicksPerSecond)
|
||||
: MakeDuration(sec, ticks);
|
||||
}
|
||||
|
||||
// Provide access to the Duration representation.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t GetRepHi(Duration d) {
|
||||
return d.rep_hi_.Get();
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr uint32_t GetRepLo(Duration d) {
|
||||
return d.rep_lo_;
|
||||
}
|
||||
|
||||
// Returns true iff d is positive or negative infinity.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool IsInfiniteDuration(Duration d) {
|
||||
return GetRepLo(d) == ~uint32_t{0};
|
||||
}
|
||||
|
||||
// Returns an infinite Duration with the opposite sign.
|
||||
// REQUIRES: IsInfiniteDuration(d)
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration OppositeInfinity(Duration d) {
|
||||
return GetRepHi(d) < 0
|
||||
? MakeDuration((std::numeric_limits<int64_t>::max)(), ~uint32_t{0})
|
||||
: MakeDuration((std::numeric_limits<int64_t>::min)(),
|
||||
~uint32_t{0});
|
||||
}
|
||||
|
||||
// Returns (-n)-1 (equivalently -(n+1)) without avoidable overflow.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr int64_t NegateAndSubtractOne(
|
||||
int64_t n) {
|
||||
// Note: Good compilers will optimize this expression to ~n when using
|
||||
// a two's-complement representation (which is required for int64_t).
|
||||
return (n < 0) ? -(n + 1) : (-n) - 1;
|
||||
}
|
||||
|
||||
// Map between a Time and a Duration since the Unix epoch. Note that these
|
||||
// functions depend on the above mentioned choice of the Unix epoch for the
|
||||
// Time representation (and both need to be Time friends). Without this
|
||||
// knowledge, we would need to add-in/subtract-out UnixEpoch() respectively.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixDuration(Duration d) {
|
||||
return Time(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration ToUnixDuration(Time t) {
|
||||
return t.rep_;
|
||||
}
|
||||
|
||||
template <std::intmax_t N>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v,
|
||||
std::ratio<1, N>) {
|
||||
static_assert(0 < N && N <= 1000 * 1000 * 1000, "Unsupported ratio");
|
||||
// Subsecond ratios cannot overflow.
|
||||
return MakeNormalizedDuration(
|
||||
v / N, v % N * kTicksPerNanosecond * 1000 * 1000 * 1000 / N);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v,
|
||||
std::ratio<60>) {
|
||||
return (v <= (std::numeric_limits<int64_t>::max)() / 60 &&
|
||||
v >= (std::numeric_limits<int64_t>::min)() / 60)
|
||||
? MakeDuration(v * 60)
|
||||
: v > 0 ? InfiniteDuration() : -InfiniteDuration();
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration FromInt64(int64_t v,
|
||||
std::ratio<3600>) {
|
||||
return (v <= (std::numeric_limits<int64_t>::max)() / 3600 &&
|
||||
v >= (std::numeric_limits<int64_t>::min)() / 3600)
|
||||
? MakeDuration(v * 3600)
|
||||
: v > 0 ? InfiniteDuration() : -InfiniteDuration();
|
||||
}
|
||||
|
||||
// IsValidRep64<T>(0) is true if the expression `int64_t{std::declval<T>()}` is
|
||||
// valid. That is, if a T can be assigned to an int64_t without narrowing.
|
||||
template <typename T>
|
||||
constexpr auto IsValidRep64(int) -> decltype(int64_t{std::declval<T>()} == 0) {
|
||||
return true;
|
||||
}
|
||||
template <typename T>
|
||||
constexpr auto IsValidRep64(char) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Converts a std::chrono::duration to an absl::Duration.
|
||||
template <typename Rep, typename Period>
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::duration<Rep, Period>& d) {
|
||||
static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid");
|
||||
return FromInt64(int64_t{d.count()}, Period{});
|
||||
}
|
||||
|
||||
template <typename Ratio>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION int64_t ToInt64(Duration d, Ratio) {
|
||||
// Note: This may be used on MSVC, which may have a system_clock period of
|
||||
// std::ratio<1, 10 * 1000 * 1000>
|
||||
return ToInt64Seconds(d * Ratio::den / Ratio::num);
|
||||
}
|
||||
// Fastpath implementations for the 6 common duration units.
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d, std::nano) {
|
||||
return ToInt64Nanoseconds(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d, std::micro) {
|
||||
return ToInt64Microseconds(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d, std::milli) {
|
||||
return ToInt64Milliseconds(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d,
|
||||
std::ratio<1>) {
|
||||
return ToInt64Seconds(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d,
|
||||
std::ratio<60>) {
|
||||
return ToInt64Minutes(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION inline int64_t ToInt64(Duration d,
|
||||
std::ratio<3600>) {
|
||||
return ToInt64Hours(d);
|
||||
}
|
||||
|
||||
// Converts an absl::Duration to a chrono duration of type T.
|
||||
template <typename T>
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION T ToChronoDuration(Duration d) {
|
||||
using Rep = typename T::rep;
|
||||
using Period = typename T::period;
|
||||
static_assert(IsValidRep64<Rep>(0), "duration::rep is invalid");
|
||||
if (time_internal::IsInfiniteDuration(d))
|
||||
return d < ZeroDuration() ? (T::min)() : (T::max)();
|
||||
const auto v = ToInt64(d, Period{});
|
||||
if (v > (std::numeric_limits<Rep>::max)()) return (T::max)();
|
||||
if (v < (std::numeric_limits<Rep>::min)()) return (T::min)();
|
||||
return T{v};
|
||||
}
|
||||
|
||||
} // namespace time_internal
|
||||
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator<(Duration lhs,
|
||||
Duration rhs) {
|
||||
return time_internal::GetRepHi(lhs) != time_internal::GetRepHi(rhs)
|
||||
? time_internal::GetRepHi(lhs) < time_internal::GetRepHi(rhs)
|
||||
: time_internal::GetRepHi(lhs) == (std::numeric_limits<int64_t>::min)()
|
||||
? time_internal::GetRepLo(lhs) + 1 <
|
||||
time_internal::GetRepLo(rhs) + 1
|
||||
: time_internal::GetRepLo(lhs) < time_internal::GetRepLo(rhs);
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr bool operator==(Duration lhs,
|
||||
Duration rhs) {
|
||||
return time_internal::GetRepHi(lhs) == time_internal::GetRepHi(rhs) &&
|
||||
time_internal::GetRepLo(lhs) == time_internal::GetRepLo(rhs);
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration operator-(Duration d) {
|
||||
// This is a little interesting because of the special cases.
|
||||
//
|
||||
// If rep_lo_ is zero, we have it easy; it's safe to negate rep_hi_, we're
|
||||
// dealing with an integral number of seconds, and the only special case is
|
||||
// the maximum negative finite duration, which can't be negated.
|
||||
//
|
||||
// Infinities stay infinite, and just change direction.
|
||||
//
|
||||
// Finally we're in the case where rep_lo_ is non-zero, and we can borrow
|
||||
// a second's worth of ticks and avoid overflow (as negating int64_t-min + 1
|
||||
// is safe).
|
||||
return time_internal::GetRepLo(d) == 0
|
||||
? time_internal::GetRepHi(d) ==
|
||||
(std::numeric_limits<int64_t>::min)()
|
||||
? InfiniteDuration()
|
||||
: time_internal::MakeDuration(-time_internal::GetRepHi(d))
|
||||
: time_internal::IsInfiniteDuration(d)
|
||||
? time_internal::OppositeInfinity(d)
|
||||
: time_internal::MakeDuration(
|
||||
time_internal::NegateAndSubtractOne(
|
||||
time_internal::GetRepHi(d)),
|
||||
time_internal::kTicksPerSecond -
|
||||
time_internal::GetRepLo(d));
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Duration InfiniteDuration() {
|
||||
return time_internal::MakeDuration((std::numeric_limits<int64_t>::max)(),
|
||||
~uint32_t{0});
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::nanoseconds& d) {
|
||||
return time_internal::FromChrono(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::microseconds& d) {
|
||||
return time_internal::FromChrono(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::milliseconds& d) {
|
||||
return time_internal::FromChrono(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::seconds& d) {
|
||||
return time_internal::FromChrono(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::minutes& d) {
|
||||
return time_internal::FromChrono(d);
|
||||
}
|
||||
ABSL_ATTRIBUTE_PURE_FUNCTION constexpr Duration FromChrono(
|
||||
const std::chrono::hours& d) {
|
||||
return time_internal::FromChrono(d);
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixNanos(int64_t ns) {
|
||||
return time_internal::FromUnixDuration(Nanoseconds(ns));
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixMicros(int64_t us) {
|
||||
return time_internal::FromUnixDuration(Microseconds(us));
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixMillis(int64_t ms) {
|
||||
return time_internal::FromUnixDuration(Milliseconds(ms));
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromUnixSeconds(int64_t s) {
|
||||
return time_internal::FromUnixDuration(Seconds(s));
|
||||
}
|
||||
|
||||
ABSL_ATTRIBUTE_CONST_FUNCTION constexpr Time FromTimeT(time_t t) {
|
||||
return time_internal::FromUnixDuration(Seconds(t));
|
||||
}
|
||||
|
||||
ABSL_NAMESPACE_END
|
||||
} // namespace absl
|
||||
|
||||
#endif // ABSL_TIME_TIME_H_
|
||||
Reference in New Issue
Block a user