tvl-depot/absl/time/time.cc

487 lines
14 KiB
C++
Raw Normal View History

2017-09-19 22:54:40 +02:00
// 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
2017-09-19 22:54:40 +02:00
//
// 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.
//
Changes imported from Abseil "staging" branch: - 43853019b439efb32c79d5d50e24508588e1bbe0 Undo the not applying qualifications to absl types in enc... by Derek Mauro <dmauro@google.com> - 06d62a10621c9864279ee57097069cfe3cb7b42a fix capitalization by Abseil Team <absl-team@google.com> - 22adbfee340bb452ba38b68975ade6f072859c4a Fix indices in str_split.h comments. by Derek Mauro <dmauro@google.com> - ae5143a559ad8633a78cd76620e30a781006d088 Fix the inconsistent licenses directives in the BUILD fil... by Derek Mauro <dmauro@google.com> - 0a76a3653b2ecfdad433d3e2f5b651c4ecdcf74b Remove strip.cc, fastmem.h, and fastmem_test.cc from the ... by Derek Mauro <dmauro@google.com> - 77908cfce5927aabca1f8d62481106f22cfc1936 Internal change. by Derek Mauro <dmauro@google.com> - d3277b4171f37e22ab346becb5e295c36c7a0219 Be consistent in (not) applying qualifications for enclos... by Abseil Team <absl-team@google.com> - 9ec7f8164e7d6a5f64288a7360a346628393cc50 Add std:: qualification to isnan and isinf in duration_te... by Derek Mauro <dmauro@google.com> - 9f7c87d7764ddba05286fabca1f4f15285f3250a Fix typos in string_view comments. by Abseil Team <absl-team@google.com> - 281860804f8053143d969b99876e3dbc6deb1236 Fix typo in container.h docs. by Abseil Team <absl-team@google.com> - 0b0a9388c7a9d7f72349d44b5b46132f45bde56c Add bazel-* symlinks to gitignore. by Michael Pratt <mpratt@google.com> GitOrigin-RevId: 43853019b439efb32c79d5d50e24508588e1bbe0 Change-Id: I9e74a5430816a34ecf1acb86486ed3b0bd12a1d6
2017-09-27 19:50:48 +02:00
// The representation for an absl::Time is an absl::Duration offset from the
2017-09-19 22:54:40 +02:00
// 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.
//
Changes imported from Abseil "staging" branch: - 43853019b439efb32c79d5d50e24508588e1bbe0 Undo the not applying qualifications to absl types in enc... by Derek Mauro <dmauro@google.com> - 06d62a10621c9864279ee57097069cfe3cb7b42a fix capitalization by Abseil Team <absl-team@google.com> - 22adbfee340bb452ba38b68975ade6f072859c4a Fix indices in str_split.h comments. by Derek Mauro <dmauro@google.com> - ae5143a559ad8633a78cd76620e30a781006d088 Fix the inconsistent licenses directives in the BUILD fil... by Derek Mauro <dmauro@google.com> - 0a76a3653b2ecfdad433d3e2f5b651c4ecdcf74b Remove strip.cc, fastmem.h, and fastmem_test.cc from the ... by Derek Mauro <dmauro@google.com> - 77908cfce5927aabca1f8d62481106f22cfc1936 Internal change. by Derek Mauro <dmauro@google.com> - d3277b4171f37e22ab346becb5e295c36c7a0219 Be consistent in (not) applying qualifications for enclos... by Abseil Team <absl-team@google.com> - 9ec7f8164e7d6a5f64288a7360a346628393cc50 Add std:: qualification to isnan and isinf in duration_te... by Derek Mauro <dmauro@google.com> - 9f7c87d7764ddba05286fabca1f4f15285f3250a Fix typos in string_view comments. by Abseil Team <absl-team@google.com> - 281860804f8053143d969b99876e3dbc6deb1236 Fix typo in container.h docs. by Abseil Team <absl-team@google.com> - 0b0a9388c7a9d7f72349d44b5b46132f45bde56c Add bazel-* symlinks to gitignore. by Michael Pratt <mpratt@google.com> GitOrigin-RevId: 43853019b439efb32c79d5d50e24508588e1bbe0 Change-Id: I9e74a5430816a34ecf1acb86486ed3b0bd12a1d6
2017-09-27 19:50:48 +02:00
// 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
2017-09-19 22:54:40 +02:00
// cl: A cctz::time_zone::civil_lookup
// al: A cctz::time_zone::absolute_lookup
#include "absl/time/time.h"
#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;
Export of internal Abseil changes. -- bdce7e57e9e886eff1114d0266781b443f7ec639 by Derek Mauro <dmauro@google.com>: Change {Get|Set}EnvironmentVariable to {Get|Set}EnvironmentVariableA for compatibility with /DUNICODE. PiperOrigin-RevId: 239229514 -- 2276ed502326a044a84060d34eb19d499e3a3be2 by Derek Mauro <dmauro@google.com>: Import of CCTZ from GitHub. PiperOrigin-RevId: 239228622 -- a462efb970ff43b08a362ef2343fb75ac1295a50 by Derek Mauro <dmauro@google.com>: Adding linking of CoreFoundation to CMakeLists in absl/time. Import https://github.com/abseil/abseil-cpp/pull/280. Fix #283 PiperOrigin-RevId: 239220785 -- fc23327b97f940c682aae1956cf7a1bf87f88c06 by Derek Mauro <dmauro@google.com>: Add hermetic test script that uses Docker to build with a very recent version of gcc (8.3.0 today) with libstdc++ and bazel. PiperOrigin-RevId: 239220448 -- 418c08a8f6a53e63b84e39473035774417ca3aa7 by Derek Mauro <dmauro@google.com>: Disable part of the variant exeception safety test on move assignment when using versions of libstd++ that contain a bug. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87431#c7 PiperOrigin-RevId: 239062455 -- 799722217aeda79679577843c91d5be62cbcbb42 by Matt Calabrese <calabrese@google.com>: Add internal-only IsSwappable traits corresponding to std::is_swappable and std::is_nothrow_swappable, which are used with the swap implementations of optional and variant. PiperOrigin-RevId: 239049448 -- aa46a036038a3de5c68ac5e5d3b4bf76f818d2ea by CJ Johnson <johnsoncj@google.com>: Make InlinedVectorStorage constructor explicit PiperOrigin-RevId: 239044361 -- 17949715b3aa21c794701f69f2154e91b6acabc3 by CJ Johnson <johnsoncj@google.com>: Add absl namesapce to internal/inlined_vector.h PiperOrigin-RevId: 239030789 -- 834628325953078cc08ed10d23bb8890e5bec897 by Derek Mauro <dmauro@google.com>: Add test script that uses Docker to build Abseil with gcc-4.8, libstdc++, and cmake. PiperOrigin-RevId: 239028433 -- 80fe24149ed73ed2ced995ad1e372fb060c60427 by CJ Johnson <johnsoncj@google.com>: Factors data members of InlinedVector into an impl type called InlinedVectorStorage so that (in future changes) the contents of a vector can be grouped together with a single pointer. PiperOrigin-RevId: 239021086 -- 585331436d5d4d79f845e45dcf79d918a0dc6169 by Derek Mauro <dmauro@google.com>: Add -Wno-missing-field-initializers to gcc compiler flags. gcc-4.x has spurious missing field initializer warnings. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750 PiperOrigin-RevId: 239017217 -- 94602fe4e33ee3a552a7f2939c0f57a992f55075 by Abseil Team <absl-team@google.com>: Formatting fixes. PiperOrigin-RevId: 238983038 -- a1c1b63c08505574e0a8c491561840cecb2bb93e by Derek Mauro <dmauro@google.com>: Add hermetic test script that uses Docker to build with a very recent version of clang with libc++ and bazel. PiperOrigin-RevId: 238669118 -- e525f8d20bc2f79a0d69336b902f63858f3bff9d by Derek Mauro <dmauro@google.com>: Disable the test optionalTest.InPlaceTSFINAEBug until libc++ is updated. PiperOrigin-RevId: 238661703 -- f99a2a0b5ec424a059678f7f226600f137b4c74e by Derek Mauro <dmauro@google.com>: Correct the check for the FlatHashMap-Any test bug (list conditions instead of platforms when possible) PiperOrigin-RevId: 238653344 -- 777928035dbcbf39f361eb7d10dc3696822f692f by Jon Cohen <cohenjon@google.com>: Add install rules for Abseil CMake. These are attempted to be limited to in-project installation. This serves two purposes -- first it's morally the same as using Abseil in-source, except you don't have to rebuild us every time. Second, the presence of an install rule makes life massively simpler for package manager maintainers. Currently this doesn't install absl tests or testonly libraries. This can be added in a follow-up patch. Fixes #38, Fixes #80, Closes #182 PiperOrigin-RevId: 238645836 -- ded1c6ce697c191b7a6ff14572b3e6d183117b2c by Derek Mauro <dmauro@google.com>: Add hermetic test script that uses Docker to build with a very recent version of clang with libstdc++ and bazel. PiperOrigin-RevId: 238517815 GitOrigin-RevId: bdce7e57e9e886eff1114d0266781b443f7ec639 Change-Id: I6f745869cb8ef63851891ccac05ae9a7dd241c4f
2019-03-19 19:14:01 +01:00
2017-09-19 22:54:40 +02:00
namespace absl {
namespace {
inline cctz::time_point<cctz::seconds> unix_epoch() {
return std::chrono::time_point_cast<cctz::seconds>(
2017-09-19 22:54:40 +02:00
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;
}
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";
2017-09-19 22:54:40 +02:00
return bd;
}
inline absl::Time::Breakdown InfinitePastBreakdown() {
2017-09-19 22:54:40 +02:00
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";
2017-09-19 22:54:40 +02:00
return bd;
}
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;
}
2017-09-19 22:54:40 +02:00
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;
}
// Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as
// necessary. If sec is min/max, then consult cs+tz to check for overlow.
Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec,
2017-09-19 22:54:40 +02:00
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();
2017-09-19 22:54:40 +02:00
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;
}
2017-09-19 22:54:40 +02:00
} // namespace
//
// Time
//
2017-09-19 22:54:40 +02:00
absl::Time::Breakdown Time::In(absl::TimeZone tz) const {
if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown();
if (*this == absl::InfinitePast()) return InfinitePastBreakdown();
2017-09-19 22:54:40 +02:00
const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_));
2017-09-19 22:54:40 +02:00
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);
2017-09-19 22:54:40 +02:00
bd.offset = al.offset;
bd.is_dst = al.is_dst;
bd.zone_abbr = al.abbr;
return bd;
}
//
// Conversions from/to other time types.
2017-09-19 22:54:40 +02:00
//
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));
}
2017-09-19 22:54:40 +02:00
timespec ToTimespec(Time t) {
timespec ts;
absl::Duration d = time_internal::ToUnixDuration(t);
if (!time_internal::IsInfiniteDuration(d)) {
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 = 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;
}
Changes imported from Abseil "staging" branch: - b527a3e4b36b644ac424e3c525b1cd393f6f6c40 Fix some typos in the usage examples by Jorg Brown <jorg@google.com> - 82be4a9adf3bb0ddafc0d46274969c99afffe870 Fix typo in optional.h comment. by Abseil Team <absl-team@google.com> - d6ee63bf8fc51fba074c23b33cebc28c808d7f07 Remove internal-only identifiers from code. by Daniel Katz <katzdm@google.com> - f9c3ad2f0d73f53b21603638af8b4bed636e79f4 Use easier understandable names for absl::StartsWith and ... by Abseil Team <absl-team@google.com> - 7c16c14fefee89c927b8789d6043c4691bcffc9b Add -Wno-missing-prototypes back to the LLVM copts. by Derek Mauro <dmauro@google.com> - 2f4b7d2e50c7023240242f1e15db60ccd7e8768d IWYU | absl/strings by Juemin Yang <jueminyang@google.com> - a99cbcc1daa34a2d6a2bb26de275e05173cc77e9 IWYU | absl/type by Juemin Yang <jueminyang@google.com> - 12e1146d0fc76c071d7e0ebaabb62f0a984fae66 Use LLVM_FLAGS and LLVM_TEST_FLAGS when --compiler=llvm. by Derek Mauro <dmauro@google.com> - cd6bea616abda558d0bace5bd77455662a233688 IWYU | absl/debugging by Juemin Yang <jueminyang@google.com> - d9a7382e59d46a8581b6b7a31cd5a48bb89326e9 IWYU | absl/synchronization by Juemin Yang <jueminyang@google.com> - 07ec7d6d5a4a666f4183c5d0ed9c342baa7b24bc IWYU | absl/numeric by Juemin Yang <jueminyang@google.com> - 12bfe40051f4270f8707e191af5652f83f2f750c Remove the RoundTrip{Float,Double}ToBuffer routines from ... by Jorg Brown <jorg@google.com> - eeb4fd67c9d97f66cb9475c3c5e51ab132f1c810 Adds conversion functions for converting between absl/tim... by Greg Miller <jgm@google.com> - 59a2108d05d4ea85dc5cc11e49b2cd2335d4295a Change Substitute to use %.6g formatting rather than 15/1... by Jorg Brown <jorg@google.com> - 394becb48e0fcd161642cdaac5120d32567e0ef8 IWYU | absl/meta by Juemin Yang <jueminyang@google.com> - 1e5da6e8da336699b2469dcf6dda025b9b0ec4c9 Rewrite atomic_hook.h to not use std::atomic<T*> under Wi... by Greg Falcon <gfalcon@google.com> GitOrigin-RevId: b527a3e4b36b644ac424e3c525b1cd393f6f6c40 Change-Id: I14e331d91c956ef045ac7927091a9f179716de0c
2017-09-24 17:20:48 +02:00
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::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::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
const CivilSecond cs(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
const auto ti = tz.At(cs);
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);
}
const CivilDay cd(cs);
switch (GetWeekday(cd)) {
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(cd) - 1;
tm.tm_isdst = ci.is_dst ? 1 : 0;
return tm;
}
2017-09-19 22:54:40 +02:00
} // namespace absl