1// Copyright 2016 Google Inc. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
16#define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
17
18#include <atomic>
19#include <cstddef>
20#include <cstdint>
21#include <string>
22#include <vector>
23
24#include "absl/time/internal/cctz/include/cctz/civil_time.h"
25#include "absl/time/internal/cctz/include/cctz/time_zone.h"
26#include "absl/time/internal/cctz/include/cctz/zone_info_source.h"
27#include "time_zone_if.h"
28#include "tzfile.h"
29
30namespace absl {
31namespace time_internal {
32namespace cctz {
33
34// A transition to a new UTC offset.
35struct Transition {
36 std::int_least64_t unix_time; // the instant of this transition
37 std::uint_least8_t type_index; // index of the transition type
38 civil_second civil_sec; // local civil time of transition
39 civil_second prev_civil_sec; // local civil time one second earlier
40
41 struct ByUnixTime {
42 inline bool operator()(const Transition& lhs, const Transition& rhs) const {
43 return lhs.unix_time < rhs.unix_time;
44 }
45 };
46 struct ByCivilTime {
47 inline bool operator()(const Transition& lhs, const Transition& rhs) const {
48 return lhs.civil_sec < rhs.civil_sec;
49 }
50 };
51};
52
53// The characteristics of a particular transition.
54struct TransitionType {
55 std::int_least32_t utc_offset; // the new prevailing UTC offset
56 civil_second civil_max; // max convertible civil time for offset
57 civil_second civil_min; // min convertible civil time for offset
58 bool is_dst; // did we move into daylight-saving time
59 std::uint_least8_t abbr_index; // index of the new abbreviation
60};
61
62// A time zone backed by the IANA Time Zone Database (zoneinfo).
63class TimeZoneInfo : public TimeZoneIf {
64 public:
65 TimeZoneInfo() = default;
66 TimeZoneInfo(const TimeZoneInfo&) = delete;
67 TimeZoneInfo& operator=(const TimeZoneInfo&) = delete;
68
69 // Loads the zoneinfo for the given name, returning true if successful.
70 bool Load(const std::string& name);
71
72 // TimeZoneIf implementations.
73 time_zone::absolute_lookup BreakTime(
74 const time_point<seconds>& tp) const override;
75 time_zone::civil_lookup MakeTime(
76 const civil_second& cs) const override;
77 bool NextTransition(const time_point<seconds>& tp,
78 time_zone::civil_transition* trans) const override;
79 bool PrevTransition(const time_point<seconds>& tp,
80 time_zone::civil_transition* trans) const override;
81 std::string Version() const override;
82 std::string Description() const override;
83
84 private:
85 struct Header { // counts of:
86 std::size_t timecnt; // transition times
87 std::size_t typecnt; // transition types
88 std::size_t charcnt; // zone abbreviation characters
89 std::size_t leapcnt; // leap seconds (we expect none)
90 std::size_t ttisstdcnt; // UTC/local indicators (unused)
91 std::size_t ttisgmtcnt; // standard/wall indicators (unused)
92
93 bool Build(const tzhead& tzh);
94 std::size_t DataLength(std::size_t time_len) const;
95 };
96
97 void CheckTransition(const std::string& name, const TransitionType& tt,
98 std::int_fast32_t offset, bool is_dst,
99 const std::string& abbr) const;
100 bool EquivTransitions(std::uint_fast8_t tt1_index,
101 std::uint_fast8_t tt2_index) const;
102 void ExtendTransitions(const std::string& name, const Header& hdr);
103
104 bool ResetToBuiltinUTC(const seconds& offset);
105 bool Load(const std::string& name, ZoneInfoSource* zip);
106
107 // Helpers for BreakTime() and MakeTime().
108 time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
109 const TransitionType& tt) const;
110 time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
111 const Transition& tr) const;
112 time_zone::civil_lookup TimeLocal(const civil_second& cs,
113 year_t c4_shift) const;
114
115 std::vector<Transition> transitions_; // ordered by unix_time and civil_sec
116 std::vector<TransitionType> transition_types_; // distinct transition types
117 std::uint_fast8_t default_transition_type_; // for before first transition
118 std::string abbreviations_; // all the NUL-terminated abbreviations
119
120 std::string version_; // the tzdata version if available
121 std::string future_spec_; // for after the last zic transition
122 bool extended_; // future_spec_ was used to generate transitions
123 year_t last_year_; // the final year of the generated transitions
124
125 // We remember the transitions found during the last BreakTime() and
126 // MakeTime() calls. If the next request is for the same transition we
127 // will avoid re-searching.
128 mutable std::atomic<std::size_t> local_time_hint_ = {}; // BreakTime() hint
129 mutable std::atomic<std::size_t> time_local_hint_ = {}; // MakeTime() hint
130};
131
132} // namespace cctz
133} // namespace time_internal
134} // namespace absl
135
136#endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_INFO_H_
137