time_zone.h
Go to the documentation of this file.
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 // A library for translating between absolute times (represented by
16 // std::chrono::time_points of the std::chrono::system_clock) and civil
17 // times (represented by cctz::civil_second) using the rules defined by
18 // a time zone (cctz::time_zone).
19 
20 #ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
21 #define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
22 
23 #include <chrono>
24 #include <cstdint>
25 #include <string>
26 #include <utility>
27 
29 
30 namespace absl {
31 namespace time_internal {
32 namespace cctz {
33 
34 // Convenience aliases. Not intended as public API points.
35 template <typename D>
36 using time_point = std::chrono::time_point<std::chrono::system_clock, D>;
37 using seconds = std::chrono::duration<std::int_fast64_t>;
38 using sys_seconds = seconds; // Deprecated. Use cctz::seconds instead.
39 
40 namespace detail {
41 template <typename D>
42 inline std::pair<time_point<seconds>, D>
44  auto sec = std::chrono::time_point_cast<seconds>(tp);
45  auto sub = tp - sec;
46  if (sub.count() < 0) {
47  sec -= seconds(1);
48  sub += seconds(1);
49  }
50  return {sec, std::chrono::duration_cast<D>(sub)};
51 }
52 inline std::pair<time_point<seconds>, seconds>
54  return {tp, seconds::zero()};
55 }
56 } // namespace detail
57 
58 // cctz::time_zone is an opaque, small, value-type class representing a
59 // geo-political region within which particular rules are used for mapping
60 // between absolute and civil times. Time zones are named using the TZ
61 // identifiers from the IANA Time Zone Database, such as "America/Los_Angeles"
62 // or "Australia/Sydney". Time zones are created from factory functions such
63 // as load_time_zone(). Note: strings like "PST" and "EDT" are not valid TZ
64 // identifiers.
65 //
66 // Example:
67 // cctz::time_zone utc = cctz::utc_time_zone();
68 // cctz::time_zone pst = cctz::fixed_time_zone(std::chrono::hours(-8));
69 // cctz::time_zone loc = cctz::local_time_zone();
70 // cctz::time_zone lax;
71 // if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
72 //
73 // See also:
74 // - http://www.iana.org/time-zones
75 // - https://en.wikipedia.org/wiki/Zoneinfo
76 class time_zone {
77  public:
78  time_zone() : time_zone(nullptr) {} // Equivalent to UTC
79  time_zone(const time_zone&) = default;
80  time_zone& operator=(const time_zone&) = default;
81 
82  std::string name() const;
83 
84  // An absolute_lookup represents the civil time (cctz::civil_second) within
85  // this time_zone at the given absolute time (time_point). There are
86  // additionally a few other fields that may be useful when working with
87  // older APIs, such as std::tm.
88  //
89  // Example:
90  // const cctz::time_zone tz = ...
91  // const auto tp = std::chrono::system_clock::now();
92  // const cctz::time_zone::absolute_lookup al = tz.lookup(tp);
93  struct absolute_lookup {
95  // Note: The following fields exist for backward compatibility with older
96  // APIs. Accessing these fields directly is a sign of imprudent logic in
97  // the calling code. Modern time-related code should only access this data
98  // indirectly by way of cctz::format().
99  int offset; // civil seconds east of UTC
100  bool is_dst; // is offset non-standard?
101  const char* abbr; // time-zone abbreviation (e.g., "PST")
102  };
103  absolute_lookup lookup(const time_point<seconds>& tp) const;
104  template <typename D>
106  return lookup(detail::split_seconds(tp).first);
107  }
108 
109  // A civil_lookup represents the absolute time(s) (time_point) that
110  // correspond to the given civil time (cctz::civil_second) within this
111  // time_zone. Usually the given civil time represents a unique instant
112  // in time, in which case the conversion is unambiguous. However,
113  // within this time zone, the given civil time may be skipped (e.g.,
114  // during a positive UTC offset shift), or repeated (e.g., during a
115  // negative UTC offset shift). To account for these possibilities,
116  // civil_lookup is richer than just a single time_point.
117  //
118  // In all cases the civil_lookup::kind enum will indicate the nature
119  // of the given civil-time argument, and the pre, trans, and post
120  // members will give the absolute time answers using the pre-transition
121  // offset, the transition point itself, and the post-transition offset,
122  // respectively (all three times are equal if kind == UNIQUE). If any
123  // of these three absolute times is outside the representable range of a
124  // time_point<seconds> the field is set to its maximum/minimum value.
125  //
126  // Example:
127  // cctz::time_zone lax;
128  // if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
129  //
130  // // A unique civil time.
131  // auto jan01 = lax.lookup(cctz::civil_second(2011, 1, 1, 0, 0, 0));
132  // // jan01.kind == cctz::time_zone::civil_lookup::UNIQUE
133  // // jan01.pre is 2011/01/01 00:00:00 -0800
134  // // jan01.trans is 2011/01/01 00:00:00 -0800
135  // // jan01.post is 2011/01/01 00:00:00 -0800
136  //
137  // // A Spring DST transition, when there is a gap in civil time.
138  // auto mar13 = lax.lookup(cctz::civil_second(2011, 3, 13, 2, 15, 0));
139  // // mar13.kind == cctz::time_zone::civil_lookup::SKIPPED
140  // // mar13.pre is 2011/03/13 03:15:00 -0700
141  // // mar13.trans is 2011/03/13 03:00:00 -0700
142  // // mar13.post is 2011/03/13 01:15:00 -0800
143  //
144  // // A Fall DST transition, when civil times are repeated.
145  // auto nov06 = lax.lookup(cctz::civil_second(2011, 11, 6, 1, 15, 0));
146  // // nov06.kind == cctz::time_zone::civil_lookup::REPEATED
147  // // nov06.pre is 2011/11/06 01:15:00 -0700
148  // // nov06.trans is 2011/11/06 01:00:00 -0800
149  // // nov06.post is 2011/11/06 01:15:00 -0800
150  struct civil_lookup {
151  enum civil_kind {
152  UNIQUE, // the civil time was singular (pre == trans == post)
153  SKIPPED, // the civil time did not exist (pre >= trans > post)
154  REPEATED, // the civil time was ambiguous (pre < trans <= post)
155  } kind;
156  time_point<seconds> pre; // uses the pre-transition offset
157  time_point<seconds> trans; // instant of civil-offset change
158  time_point<seconds> post; // uses the post-transition offset
159  };
160  civil_lookup lookup(const civil_second& cs) const;
161 
162  // Finds the time of the next/previous offset change in this time zone.
163  //
164  // By definition, next_transition(tp, &trans) returns false when tp has
165  // its maximum value, and prev_transition(tp, &trans) returns false
166  // when tp has its minimum value. If the zone has no transitions, the
167  // result will also be false no matter what the argument.
168  //
169  // Otherwise, when tp has its minimum value, next_transition(tp, &trans)
170  // returns true and sets trans to the first recorded transition. Chains
171  // of calls to next_transition()/prev_transition() will eventually return
172  // false, but it is unspecified exactly when next_transition(tp, &trans)
173  // jumps to false, or what time is set by prev_transition(tp, &trans) for
174  // a very distant tp.
175  //
176  // Note: Enumeration of time-zone transitions is for informational purposes
177  // only. Modern time-related code should not care about when offset changes
178  // occur.
179  //
180  // Example:
181  // cctz::time_zone nyc;
182  // if (!cctz::load_time_zone("America/New_York", &nyc)) { ... }
183  // const auto now = std::chrono::system_clock::now();
184  // auto tp = cctz::time_point<cctz::seconds>::min();
185  // cctz::time_zone::civil_transition trans;
186  // while (tp <= now && nyc.next_transition(tp, &trans)) {
187  // // transition: trans.from -> trans.to
188  // tp = nyc.lookup(trans.to).trans;
189  // }
191  civil_second from; // the civil time we jump from
192  civil_second to; // the civil time we jump to
193  };
194  bool next_transition(const time_point<seconds>& tp,
195  civil_transition* trans) const;
196  template <typename D>
198  civil_transition* trans) const {
199  return next_transition(detail::split_seconds(tp).first, trans);
200  }
201  bool prev_transition(const time_point<seconds>& tp,
202  civil_transition* trans) const;
203  template <typename D>
205  civil_transition* trans) const {
206  return prev_transition(detail::split_seconds(tp).first, trans);
207  }
208 
209  // version() and description() provide additional information about the
210  // time zone. The content of each of the returned strings is unspecified,
211  // however, when the IANA Time Zone Database is the underlying data source
212  // the version() std::string will be in the familar form (e.g, "2018e") or
213  // empty when unavailable.
214  //
215  // Note: These functions are for informational or testing purposes only.
216  std::string version() const; // empty when unknown
217  std::string description() const;
218 
219  // Relational operators.
220  friend bool operator==(time_zone lhs, time_zone rhs) {
221  return &lhs.effective_impl() == &rhs.effective_impl();
222  }
223  friend bool operator!=(time_zone lhs, time_zone rhs) {
224  return !(lhs == rhs);
225  }
226 
227  template <typename H>
228  friend H AbslHashValue(H h, time_zone tz) {
229  return H::combine(std::move(h), &tz.effective_impl());
230  }
231 
232  class Impl;
233 
234  private:
235  explicit time_zone(const Impl* impl) : impl_(impl) {}
236  const Impl& effective_impl() const; // handles implicit UTC
237  const Impl* impl_;
238 };
239 
240 // Loads the named time zone. May perform I/O on the initial load.
241 // If the name is invalid, or some other kind of error occurs, returns
242 // false and "*tz" is set to the UTC time zone.
243 bool load_time_zone(const std::string& name, time_zone* tz);
244 
245 // Returns a time_zone representing UTC. Cannot fail.
247 
248 // Returns a time zone that is a fixed offset (seconds east) from UTC.
249 // Note: If the absolute value of the offset is greater than 24 hours
250 // you'll get UTC (i.e., zero offset) instead.
251 time_zone fixed_time_zone(const seconds& offset);
252 
253 // Returns a time zone representing the local time zone. Falls back to UTC.
254 // Note: local_time_zone.name() may only be something like "localtime".
256 
257 // Returns the civil time (cctz::civil_second) within the given time zone at
258 // the given absolute time (time_point). Since the additional fields provided
259 // by the time_zone::absolute_lookup struct should rarely be needed in modern
260 // code, this convert() function is simpler and should be preferred.
261 template <typename D>
262 inline civil_second convert(const time_point<D>& tp, const time_zone& tz) {
263  return tz.lookup(tp).cs;
264 }
265 
266 // Returns the absolute time (time_point) that corresponds to the given civil
267 // time within the given time zone. If the civil time is not unique (i.e., if
268 // it was either repeated or non-existent), then the returned time_point is
269 // the best estimate that preserves relative order. That is, this function
270 // guarantees that if cs1 < cs2, then convert(cs1, tz) <= convert(cs2, tz).
272  const time_zone& tz) {
273  const time_zone::civil_lookup cl = tz.lookup(cs);
274  if (cl.kind == time_zone::civil_lookup::SKIPPED) return cl.trans;
275  return cl.pre;
276 }
277 
278 namespace detail {
279 using femtoseconds = std::chrono::duration<std::int_fast64_t, std::femto>;
280 std::string format(const std::string&, const time_point<seconds>&,
281  const femtoseconds&, const time_zone&);
282 bool parse(const std::string&, const std::string&, const time_zone&,
283  time_point<seconds>*, femtoseconds*, std::string* err = nullptr);
284 } // namespace detail
285 
286 // Formats the given time_point in the given cctz::time_zone according to
287 // the provided format string. Uses strftime()-like formatting options,
288 // with the following extensions:
289 //
290 // - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
291 // - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
292 // - %E#S - Seconds with # digits of fractional precision
293 // - %E*S - Seconds with full fractional precision (a literal '*')
294 // - %E#f - Fractional seconds with # digits of precision
295 // - %E*f - Fractional seconds with full precision (a literal '*')
296 // - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
297 //
298 // Note that %E0S behaves like %S, and %E0f produces no characters. In
299 // contrast %E*f always produces at least one digit, which may be '0'.
300 //
301 // Note that %Y produces as many characters as it takes to fully render the
302 // year. A year outside of [-999:9999] when formatted with %E4Y will produce
303 // more than four characters, just like %Y.
304 //
305 // Tip: Format strings should include the UTC offset (e.g., %z, %Ez, or %E*z)
306 // so that the resulting string uniquely identifies an absolute time.
307 //
308 // Example:
309 // cctz::time_zone lax;
310 // if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
311 // auto tp = cctz::convert(cctz::civil_second(2013, 1, 2, 3, 4, 5), lax);
312 // std::string f = cctz::format("%H:%M:%S", tp, lax); // "03:04:05"
313 // f = cctz::format("%H:%M:%E3S", tp, lax); // "03:04:05.000"
314 template <typename D>
315 inline std::string format(const std::string& fmt, const time_point<D>& tp,
316  const time_zone& tz) {
317  const auto p = detail::split_seconds(tp);
318  const auto n = std::chrono::duration_cast<detail::femtoseconds>(p.second);
319  return detail::format(fmt, p.first, n, tz);
320 }
321 
322 // Parses an input string according to the provided format string and
323 // returns the corresponding time_point. Uses strftime()-like formatting
324 // options, with the same extensions as cctz::format(), but with the
325 // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
326 // and %E*z also accept the same inputs.
327 //
328 // %Y consumes as many numeric characters as it can, so the matching data
329 // should always be terminated with a non-numeric. %E4Y always consumes
330 // exactly four characters, including any sign.
331 //
332 // Unspecified fields are taken from the default date and time of ...
333 //
334 // "1970-01-01 00:00:00.0 +0000"
335 //
336 // For example, parsing a string of "15:45" (%H:%M) will return a time_point
337 // that represents "1970-01-01 15:45:00.0 +0000".
338 //
339 // Note that parse() returns time instants, so it makes most sense to parse
340 // fully-specified date/time strings that include a UTC offset (%z, %Ez, or
341 // %E*z).
342 //
343 // Note also that parse() only heeds the fields year, month, day, hour,
344 // minute, (fractional) second, and UTC offset. Other fields, like weekday (%a
345 // or %A), while parsed for syntactic validity, are ignored in the conversion.
346 //
347 // Date and time fields that are out-of-range will be treated as errors rather
348 // than normalizing them like cctz::civil_second() would do. For example, it
349 // is an error to parse the date "Oct 32, 2013" because 32 is out of range.
350 //
351 // A second of ":60" is normalized to ":00" of the following minute with
352 // fractional seconds discarded. The following table shows how the given
353 // seconds and subseconds will be parsed:
354 //
355 // "59.x" -> 59.x // exact
356 // "60.x" -> 00.0 // normalized
357 // "00.x" -> 00.x // exact
358 //
359 // Errors are indicated by returning false.
360 //
361 // Example:
362 // const cctz::time_zone tz = ...
363 // std::chrono::system_clock::time_point tp;
364 // if (cctz::parse("%Y-%m-%d", "2015-10-09", tz, &tp)) {
365 // ...
366 // }
367 template <typename D>
368 inline bool parse(const std::string& fmt, const std::string& input,
369  const time_zone& tz, time_point<D>* tpp) {
372  const bool b = detail::parse(fmt, input, tz, &sec, &fs);
373  if (b) {
374  // TODO: Return false if unrepresentable as a time_point<D>.
375  *tpp = std::chrono::time_point_cast<D>(sec);
376  *tpp += std::chrono::duration_cast<D>(fs);
377  }
378  return b;
379 }
380 
381 } // namespace cctz
382 } // namespace time_internal
383 } // namespace absl
384 
385 #endif // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
friend bool operator!=(time_zone lhs, time_zone rhs)
Definition: time_zone.h:223
std::pair< time_point< seconds >, D > split_seconds(const time_point< D > &tp)
Definition: time_zone.h:43
time_zone fixed_time_zone(const seconds &offset)
uint32_t version
Definition: graphcycles.cc:278
absolute_lookup lookup(const time_point< seconds > &tp) const
friend bool operator==(time_zone lhs, time_zone rhs)
Definition: time_zone.h:220
bool prev_transition(const time_point< D > &tp, civil_transition *trans) const
Definition: time_zone.h:204
std::chrono::duration< std::int_fast64_t, std::femto > femtoseconds
Definition: time_zone.h:279
std::chrono::duration< std::int_fast64_t > seconds
Definition: time_zone.h:37
Definition: algorithm.h:29
absolute_lookup lookup(const time_point< D > &tp) const
Definition: time_zone.h:105
cctz::time_point< cctz::seconds > sec
Definition: format.cc:38
friend H AbslHashValue(H h, time_zone tz)
Definition: time_zone.h:228
bool next_transition(const time_point< D > &tp, civil_transition *trans) const
Definition: time_zone.h:197
std::string format(const std::string &, const time_point< seconds > &, const femtoseconds &, const time_zone &)
char name[1]
Definition: mutex.cc:296
bool parse(const std::string &, const std::string &, const time_zone &, time_point< seconds > *, femtoseconds *, std::string *err=nullptr)
enum absl::time_internal::cctz::time_zone::civil_lookup::civil_kind kind
std::chrono::time_point< std::chrono::system_clock, D > time_point
Definition: time_zone.h:36
uint64_t b
Definition: layout_test.cc:50
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: utility.h:219
bool load_time_zone(const std::string &name, time_zone *tz)
civil_second convert(const time_point< D > &tp, const time_zone &tz)
Definition: time_zone.h:262


abseil_cpp
Author(s):
autogenerated on Mon Feb 28 2022 21:31:20