// 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) { … } // The number of days in non-leap and leap years respectively. const std::int_least32_t kDaysPerYear[2] = …; // 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] = …; // We reject leap-second encoded zoneinfo and so assume 60-second minutes. const std::int_least32_t kSecsPerDay = …; // 400-year chunks always have 146097 days (20871 weeks). const std::int_least64_t kSecsPer400Years = …; // Like kDaysPerYear[] but scaled up by a factor of kSecsPerDay. const std::int_least32_t kSecsPerYear[2] = …; // Convert a cctz::weekday to a POSIX TZ weekday number (0==Sun, ..., 6=Sat). inline int ToPosixWeekday(weekday wd) { … } // Single-byte, unsigned numeric values are encoded directly. inline std::uint_fast8_t Decode8(const char* cp) { … } // 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::int_fast64_t Decode64(const char* cp) { … } struct Header { … }; // Builds the in-memory header using the raw bytes from the file. bool Header::Build(const tzhead& tzh) { … } // 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 { … } // 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) { … } // Generate a year-relative offset for a PosixTransition. std::int_fast64_t TransOffset(bool leap_year, int jan1_weekday, const PosixTransition& pt) { … } inline time_zone::civil_lookup MakeUnique(const time_point<seconds>& tp) { … } inline time_zone::civil_lookup MakeUnique(std::int_fast64_t unix_time) { … } inline time_zone::civil_lookup MakeSkipped(const Transition& tr, const civil_second& cs) { … } inline time_zone::civil_lookup MakeRepeated(const Transition& tr, const civil_second& cs) { … } inline civil_second YearShift(const civil_second& cs, year_t shift) { … } } // 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) { … } // 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 { … } // 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() { … } namespace { FilePtr; // fopen(3) adaptor. inline FilePtr FOpen(const char* path, const char* mode) { … } // A stdio(3)-backed implementation of ZoneInfoSource. class FileZoneInfoSource : public ZoneInfoSource { … }; std::unique_ptr<ZoneInfoSource> FileZoneInfoSource::Open( const std::string& name) { … } class AndroidZoneInfoSource : public FileZoneInfoSource { … }; std::unique_ptr<ZoneInfoSource> AndroidZoneInfoSource::Open( const std::string& name) { … } // 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 { … }; std::unique_ptr<ZoneInfoSource> FuchsiaZoneInfoSource::Open( const std::string& name) { … } } // namespace // What (no leap-seconds) UTC+seconds zoneinfo would look like. bool TimeZoneInfo::ResetToBuiltinUTC(const seconds& offset) { … } bool TimeZoneInfo::Load(ZoneInfoSource* zip) { … } bool TimeZoneInfo::Load(const std::string& name) { … } std::unique_ptr<TimeZoneInfo> TimeZoneInfo::UTC() { … } std::unique_ptr<TimeZoneInfo> TimeZoneInfo::Make(const std::string& name) { … } // BreakTime() translation for a particular transition type. time_zone::absolute_lookup TimeZoneInfo::LocalTime( std::int_fast64_t unix_time, const TransitionType& tt) const { … } // BreakTime() translation for a particular transition. time_zone::absolute_lookup TimeZoneInfo::LocalTime(std::int_fast64_t unix_time, const Transition& tr) const { … } // 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 { … } time_zone::absolute_lookup TimeZoneInfo::BreakTime( const time_point<seconds>& tp) const { … } time_zone::civil_lookup TimeZoneInfo::MakeTime(const civil_second& cs) const { … } std::string TimeZoneInfo::Version() const { … } std::string TimeZoneInfo::Description() const { … } bool TimeZoneInfo::NextTransition(const time_point<seconds>& tp, time_zone::civil_transition* trans) const { … } bool TimeZoneInfo::PrevTransition(const time_point<seconds>& tp, time_zone::civil_transition* trans) const { … } } // namespace cctz } // namespace time_internal ABSL_NAMESPACE_END } // namespace absl