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// http://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 CCTZ_TIME_ZONE_INFO_H_
16#define CCTZ_TIME_ZONE_INFO_H_
17
18#include <atomic>
19#include <cstddef>
20#include <cstdint>
21#include <string>
22#include <vector>
23
24#include "cctz/civil_time.h"
25#include "cctz/time_zone.h"
26#include "cctz/zone_info_source.h"
27#include "time_zone_if.h"
28#include "tzfile.h"
29
30namespace cctz {
31
32// A transition to a new UTC offset.
33struct Transition {
34 std::int_least64_t unix_time; // the instant of this transition
35 std::uint_least8_t type_index; // index of the transition type
36 civil_second civil_sec; // local civil time of transition
37 civil_second prev_civil_sec; // local civil time one second earlier
38
39 struct ByUnixTime {
40 inline bool operator()(const Transition& lhs, const Transition& rhs) const {
41 return lhs.unix_time < rhs.unix_time;
42 }
43 };
44 struct ByCivilTime {
45 inline bool operator()(const Transition& lhs, const Transition& rhs) const {
46 return lhs.civil_sec < rhs.civil_sec;
47 }
48 };
49};
50
51// The characteristics of a particular transition.
52struct TransitionType {
53 std::int_least32_t utc_offset; // the new prevailing UTC offset
54 civil_second civil_max; // max convertible civil time for offset
55 civil_second civil_min; // min convertible civil time for offset
56 bool is_dst; // did we move into daylight-saving time
57 std::uint_least8_t abbr_index; // index of the new abbreviation
58};
59
60// A time zone backed by the IANA Time Zone Database (zoneinfo).
61class TimeZoneInfo : public TimeZoneIf {
62 public:
63 TimeZoneInfo() = default;
64 TimeZoneInfo(const TimeZoneInfo&) = delete;
65 TimeZoneInfo& operator=(const TimeZoneInfo&) = delete;
66
67 // Loads the zoneinfo for the given name, returning true if successful.
68 bool Load(const std::string& name);
69
70 // TimeZoneIf implementations.
71 time_zone::absolute_lookup BreakTime(
72 const time_point<sys_seconds>& tp) const override;
73 time_zone::civil_lookup MakeTime(
74 const civil_second& cs) const override;
75 std::string Description() const override;
76 bool NextTransition(time_point<sys_seconds>* tp) const override;
77 bool PrevTransition(time_point<sys_seconds>* tp) const override;
78
79 private:
80 struct Header { // counts of:
81 std::size_t timecnt; // transition times
82 std::size_t typecnt; // transition types
83 std::size_t charcnt; // zone abbreviation characters
84 std::size_t leapcnt; // leap seconds (we expect none)
85 std::size_t ttisstdcnt; // UTC/local indicators (unused)
86 std::size_t ttisgmtcnt; // standard/wall indicators (unused)
87
88 bool Build(const tzhead& tzh);
89 std::size_t DataLength(std::size_t time_len) const;
90 };
91
92 void CheckTransition(const std::string& name, const TransitionType& tt,
93 std::int_fast32_t offset, bool is_dst,
94 const std::string& abbr) const;
95 bool EquivTransitions(std::uint_fast8_t tt1_index,
96 std::uint_fast8_t tt2_index) const;
97 void ExtendTransitions(const std::string& name, const Header& hdr);
98
99 bool ResetToBuiltinUTC(const sys_seconds& offset);
100 bool Load(const std::string& name, ZoneInfoSource* zip);
101
102 // Helpers for BreakTime() and MakeTime().
103 time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
104 const TransitionType& tt) const;
105 time_zone::absolute_lookup LocalTime(std::int_fast64_t unix_time,
106 const Transition& tr) const;
107 time_zone::civil_lookup TimeLocal(const civil_second& cs,
108 cctz::year_t c4_shift) const;
109
110 std::vector<Transition> transitions_; // ordered by unix_time and civil_sec
111 std::vector<TransitionType> transition_types_; // distinct transition types
112 std::uint_fast8_t default_transition_type_; // for before first transition
113 std::string abbreviations_; // all the NUL-terminated abbreviations
114
115 std::string future_spec_; // for after the last zic transition
116 bool extended_; // future_spec_ was used to generate transitions
117 cctz::year_t last_year_; // the final year of the generated transitions
118
119 // We remember the transitions found during the last BreakTime() and
120 // MakeTime() calls. If the next request is for the same transition we
121 // will avoid re-searching.
122 mutable std::atomic<std::size_t> local_time_hint_ = {}; // BreakTime() hint
123 mutable std::atomic<std::size_t> time_local_hint_ = {}; // MakeTime() hint
124};
125
126} // namespace cctz
127
128#endif // CCTZ_TIME_ZONE_INFO_H_
129