time_zone.h
Go to the documentation of this file.
00001 // Copyright 2016 Google Inc. All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //   https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 //   Unless required by applicable law or agreed to in writing, software
00010 //   distributed under the License is distributed on an "AS IS" BASIS,
00011 //   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 //   See the License for the specific language governing permissions and
00013 //   limitations under the License.
00014 
00015 // A library for translating between absolute times (represented by
00016 // std::chrono::time_points of the std::chrono::system_clock) and civil
00017 // times (represented by cctz::civil_second) using the rules defined by
00018 // a time zone (cctz::time_zone).
00019 
00020 #ifndef ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
00021 #define ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_
00022 
00023 #include <chrono>
00024 #include <cstdint>
00025 #include <string>
00026 #include <utility>
00027 
00028 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
00029 
00030 namespace absl {
00031 namespace time_internal {
00032 namespace cctz {
00033 
00034 // Convenience aliases. Not intended as public API points.
00035 template <typename D>
00036 using time_point = std::chrono::time_point<std::chrono::system_clock, D>;
00037 using seconds = std::chrono::duration<std::int_fast64_t>;
00038 using sys_seconds = seconds;  // Deprecated.  Use cctz::seconds instead.
00039 
00040 namespace detail {
00041 template <typename D>
00042 inline std::pair<time_point<seconds>, D>
00043 split_seconds(const time_point<D>& tp) {
00044   auto sec = std::chrono::time_point_cast<seconds>(tp);
00045   auto sub = tp - sec;
00046   if (sub.count() < 0) {
00047     sec -= seconds(1);
00048     sub += seconds(1);
00049   }
00050   return {sec, std::chrono::duration_cast<D>(sub)};
00051 }
00052 inline std::pair<time_point<seconds>, seconds>
00053 split_seconds(const time_point<seconds>& tp) {
00054   return {tp, seconds::zero()};
00055 }
00056 }  // namespace detail
00057 
00058 // cctz::time_zone is an opaque, small, value-type class representing a
00059 // geo-political region within which particular rules are used for mapping
00060 // between absolute and civil times. Time zones are named using the TZ
00061 // identifiers from the IANA Time Zone Database, such as "America/Los_Angeles"
00062 // or "Australia/Sydney". Time zones are created from factory functions such
00063 // as load_time_zone(). Note: strings like "PST" and "EDT" are not valid TZ
00064 // identifiers.
00065 //
00066 // Example:
00067 //   cctz::time_zone utc = cctz::utc_time_zone();
00068 //   cctz::time_zone pst = cctz::fixed_time_zone(std::chrono::hours(-8));
00069 //   cctz::time_zone loc = cctz::local_time_zone();
00070 //   cctz::time_zone lax;
00071 //   if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
00072 //
00073 // See also:
00074 // - http://www.iana.org/time-zones
00075 // - https://en.wikipedia.org/wiki/Zoneinfo
00076 class time_zone {
00077  public:
00078   time_zone() : time_zone(nullptr) {}  // Equivalent to UTC
00079   time_zone(const time_zone&) = default;
00080   time_zone& operator=(const time_zone&) = default;
00081 
00082   std::string name() const;
00083 
00084   // An absolute_lookup represents the civil time (cctz::civil_second) within
00085   // this time_zone at the given absolute time (time_point). There are
00086   // additionally a few other fields that may be useful when working with
00087   // older APIs, such as std::tm.
00088   //
00089   // Example:
00090   //   const cctz::time_zone tz = ...
00091   //   const auto tp = std::chrono::system_clock::now();
00092   //   const cctz::time_zone::absolute_lookup al = tz.lookup(tp);
00093   struct absolute_lookup {
00094     civil_second cs;
00095     // Note: The following fields exist for backward compatibility with older
00096     // APIs. Accessing these fields directly is a sign of imprudent logic in
00097     // the calling code. Modern time-related code should only access this data
00098     // indirectly by way of cctz::format().
00099     int offset;        // civil seconds east of UTC
00100     bool is_dst;       // is offset non-standard?
00101     const char* abbr;  // time-zone abbreviation (e.g., "PST")
00102   };
00103   absolute_lookup lookup(const time_point<seconds>& tp) const;
00104   template <typename D>
00105   absolute_lookup lookup(const time_point<D>& tp) const {
00106     return lookup(detail::split_seconds(tp).first);
00107   }
00108 
00109   // A civil_lookup represents the absolute time(s) (time_point) that
00110   // correspond to the given civil time (cctz::civil_second) within this
00111   // time_zone. Usually the given civil time represents a unique instant
00112   // in time, in which case the conversion is unambiguous. However,
00113   // within this time zone, the given civil time may be skipped (e.g.,
00114   // during a positive UTC offset shift), or repeated (e.g., during a
00115   // negative UTC offset shift). To account for these possibilities,
00116   // civil_lookup is richer than just a single time_point.
00117   //
00118   // In all cases the civil_lookup::kind enum will indicate the nature
00119   // of the given civil-time argument, and the pre, trans, and post
00120   // members will give the absolute time answers using the pre-transition
00121   // offset, the transition point itself, and the post-transition offset,
00122   // respectively (all three times are equal if kind == UNIQUE). If any
00123   // of these three absolute times is outside the representable range of a
00124   // time_point<seconds> the field is set to its maximum/minimum value.
00125   //
00126   // Example:
00127   //   cctz::time_zone lax;
00128   //   if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
00129   //
00130   //   // A unique civil time.
00131   //   auto jan01 = lax.lookup(cctz::civil_second(2011, 1, 1, 0, 0, 0));
00132   //   // jan01.kind == cctz::time_zone::civil_lookup::UNIQUE
00133   //   // jan01.pre    is 2011/01/01 00:00:00 -0800
00134   //   // jan01.trans  is 2011/01/01 00:00:00 -0800
00135   //   // jan01.post   is 2011/01/01 00:00:00 -0800
00136   //
00137   //   // A Spring DST transition, when there is a gap in civil time.
00138   //   auto mar13 = lax.lookup(cctz::civil_second(2011, 3, 13, 2, 15, 0));
00139   //   // mar13.kind == cctz::time_zone::civil_lookup::SKIPPED
00140   //   // mar13.pre   is 2011/03/13 03:15:00 -0700
00141   //   // mar13.trans is 2011/03/13 03:00:00 -0700
00142   //   // mar13.post  is 2011/03/13 01:15:00 -0800
00143   //
00144   //   // A Fall DST transition, when civil times are repeated.
00145   //   auto nov06 = lax.lookup(cctz::civil_second(2011, 11, 6, 1, 15, 0));
00146   //   // nov06.kind == cctz::time_zone::civil_lookup::REPEATED
00147   //   // nov06.pre   is 2011/11/06 01:15:00 -0700
00148   //   // nov06.trans is 2011/11/06 01:00:00 -0800
00149   //   // nov06.post  is 2011/11/06 01:15:00 -0800
00150   struct civil_lookup {
00151     enum civil_kind {
00152       UNIQUE,    // the civil time was singular (pre == trans == post)
00153       SKIPPED,   // the civil time did not exist (pre >= trans > post)
00154       REPEATED,  // the civil time was ambiguous (pre < trans <= post)
00155     } kind;
00156     time_point<seconds> pre;    // uses the pre-transition offset
00157     time_point<seconds> trans;  // instant of civil-offset change
00158     time_point<seconds> post;   // uses the post-transition offset
00159   };
00160   civil_lookup lookup(const civil_second& cs) const;
00161 
00162   // Finds the time of the next/previous offset change in this time zone.
00163   //
00164   // By definition, next_transition(tp, &trans) returns false when tp has
00165   // its maximum value, and prev_transition(tp, &trans) returns false
00166   // when tp has its minimum value. If the zone has no transitions, the
00167   // result will also be false no matter what the argument.
00168   //
00169   // Otherwise, when tp has its minimum value, next_transition(tp, &trans)
00170   // returns true and sets trans to the first recorded transition. Chains
00171   // of calls to next_transition()/prev_transition() will eventually return
00172   // false, but it is unspecified exactly when next_transition(tp, &trans)
00173   // jumps to false, or what time is set by prev_transition(tp, &trans) for
00174   // a very distant tp.
00175   //
00176   // Note: Enumeration of time-zone transitions is for informational purposes
00177   // only. Modern time-related code should not care about when offset changes
00178   // occur.
00179   //
00180   // Example:
00181   //   cctz::time_zone nyc;
00182   //   if (!cctz::load_time_zone("America/New_York", &nyc)) { ... }
00183   //   const auto now = std::chrono::system_clock::now();
00184   //   auto tp = cctz::time_point<cctz::seconds>::min();
00185   //   cctz::time_zone::civil_transition trans;
00186   //   while (tp <= now && nyc.next_transition(tp, &trans)) {
00187   //     // transition: trans.from -> trans.to
00188   //     tp = nyc.lookup(trans.to).trans;
00189   //   }
00190   struct civil_transition {
00191     civil_second from;  // the civil time we jump from
00192     civil_second to;    // the civil time we jump to
00193   };
00194   bool next_transition(const time_point<seconds>& tp,
00195                        civil_transition* trans) const;
00196   template <typename D>
00197   bool next_transition(const time_point<D>& tp,
00198                        civil_transition* trans) const {
00199     return next_transition(detail::split_seconds(tp).first, trans);
00200   }
00201   bool prev_transition(const time_point<seconds>& tp,
00202                        civil_transition* trans) const;
00203   template <typename D>
00204   bool prev_transition(const time_point<D>& tp,
00205                        civil_transition* trans) const {
00206     return prev_transition(detail::split_seconds(tp).first, trans);
00207   }
00208 
00209   // version() and description() provide additional information about the
00210   // time zone. The content of each of the returned strings is unspecified,
00211   // however, when the IANA Time Zone Database is the underlying data source
00212   // the version() std::string will be in the familar form (e.g, "2018e") or
00213   // empty when unavailable.
00214   //
00215   // Note: These functions are for informational or testing purposes only.
00216   std::string version() const;  // empty when unknown
00217   std::string description() const;
00218 
00219   // Relational operators.
00220   friend bool operator==(time_zone lhs, time_zone rhs) {
00221     return &lhs.effective_impl() == &rhs.effective_impl();
00222   }
00223   friend bool operator!=(time_zone lhs, time_zone rhs) {
00224     return !(lhs == rhs);
00225   }
00226 
00227   template <typename H>
00228   friend H AbslHashValue(H h, time_zone tz) {
00229     return H::combine(std::move(h), &tz.effective_impl());
00230   }
00231 
00232   class Impl;
00233 
00234  private:
00235   explicit time_zone(const Impl* impl) : impl_(impl) {}
00236   const Impl& effective_impl() const;  // handles implicit UTC
00237   const Impl* impl_;
00238 };
00239 
00240 // Loads the named time zone. May perform I/O on the initial load.
00241 // If the name is invalid, or some other kind of error occurs, returns
00242 // false and "*tz" is set to the UTC time zone.
00243 bool load_time_zone(const std::string& name, time_zone* tz);
00244 
00245 // Returns a time_zone representing UTC. Cannot fail.
00246 time_zone utc_time_zone();
00247 
00248 // Returns a time zone that is a fixed offset (seconds east) from UTC.
00249 // Note: If the absolute value of the offset is greater than 24 hours
00250 // you'll get UTC (i.e., zero offset) instead.
00251 time_zone fixed_time_zone(const seconds& offset);
00252 
00253 // Returns a time zone representing the local time zone. Falls back to UTC.
00254 // Note: local_time_zone.name() may only be something like "localtime".
00255 time_zone local_time_zone();
00256 
00257 // Returns the civil time (cctz::civil_second) within the given time zone at
00258 // the given absolute time (time_point). Since the additional fields provided
00259 // by the time_zone::absolute_lookup struct should rarely be needed in modern
00260 // code, this convert() function is simpler and should be preferred.
00261 template <typename D>
00262 inline civil_second convert(const time_point<D>& tp, const time_zone& tz) {
00263   return tz.lookup(tp).cs;
00264 }
00265 
00266 // Returns the absolute time (time_point) that corresponds to the given civil
00267 // time within the given time zone. If the civil time is not unique (i.e., if
00268 // it was either repeated or non-existent), then the returned time_point is
00269 // the best estimate that preserves relative order. That is, this function
00270 // guarantees that if cs1 < cs2, then convert(cs1, tz) <= convert(cs2, tz).
00271 inline time_point<seconds> convert(const civil_second& cs,
00272                                    const time_zone& tz) {
00273   const time_zone::civil_lookup cl = tz.lookup(cs);
00274   if (cl.kind == time_zone::civil_lookup::SKIPPED) return cl.trans;
00275   return cl.pre;
00276 }
00277 
00278 namespace detail {
00279 using femtoseconds = std::chrono::duration<std::int_fast64_t, std::femto>;
00280 std::string format(const std::string&, const time_point<seconds>&,
00281                    const femtoseconds&, const time_zone&);
00282 bool parse(const std::string&, const std::string&, const time_zone&,
00283            time_point<seconds>*, femtoseconds*, std::string* err = nullptr);
00284 }  // namespace detail
00285 
00286 // Formats the given time_point in the given cctz::time_zone according to
00287 // the provided format string. Uses strftime()-like formatting options,
00288 // with the following extensions:
00289 //
00290 //   - %Ez  - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm)
00291 //   - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss)
00292 //   - %E#S - Seconds with # digits of fractional precision
00293 //   - %E*S - Seconds with full fractional precision (a literal '*')
00294 //   - %E#f - Fractional seconds with # digits of precision
00295 //   - %E*f - Fractional seconds with full precision (a literal '*')
00296 //   - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999)
00297 //
00298 // Note that %E0S behaves like %S, and %E0f produces no characters. In
00299 // contrast %E*f always produces at least one digit, which may be '0'.
00300 //
00301 // Note that %Y produces as many characters as it takes to fully render the
00302 // year. A year outside of [-999:9999] when formatted with %E4Y will produce
00303 // more than four characters, just like %Y.
00304 //
00305 // Tip: Format strings should include the UTC offset (e.g., %z, %Ez, or %E*z)
00306 // so that the resulting string uniquely identifies an absolute time.
00307 //
00308 // Example:
00309 //   cctz::time_zone lax;
00310 //   if (!cctz::load_time_zone("America/Los_Angeles", &lax)) { ... }
00311 //   auto tp = cctz::convert(cctz::civil_second(2013, 1, 2, 3, 4, 5), lax);
00312 //   std::string f = cctz::format("%H:%M:%S", tp, lax);  // "03:04:05"
00313 //   f = cctz::format("%H:%M:%E3S", tp, lax);            // "03:04:05.000"
00314 template <typename D>
00315 inline std::string format(const std::string& fmt, const time_point<D>& tp,
00316                           const time_zone& tz) {
00317   const auto p = detail::split_seconds(tp);
00318   const auto n = std::chrono::duration_cast<detail::femtoseconds>(p.second);
00319   return detail::format(fmt, p.first, n, tz);
00320 }
00321 
00322 // Parses an input string according to the provided format string and
00323 // returns the corresponding time_point. Uses strftime()-like formatting
00324 // options, with the same extensions as cctz::format(), but with the
00325 // exceptions that %E#S is interpreted as %E*S, and %E#f as %E*f. %Ez
00326 // and %E*z also accept the same inputs.
00327 //
00328 // %Y consumes as many numeric characters as it can, so the matching data
00329 // should always be terminated with a non-numeric. %E4Y always consumes
00330 // exactly four characters, including any sign.
00331 //
00332 // Unspecified fields are taken from the default date and time of ...
00333 //
00334 //   "1970-01-01 00:00:00.0 +0000"
00335 //
00336 // For example, parsing a string of "15:45" (%H:%M) will return a time_point
00337 // that represents "1970-01-01 15:45:00.0 +0000".
00338 //
00339 // Note that parse() returns time instants, so it makes most sense to parse
00340 // fully-specified date/time strings that include a UTC offset (%z, %Ez, or
00341 // %E*z).
00342 //
00343 // Note also that parse() only heeds the fields year, month, day, hour,
00344 // minute, (fractional) second, and UTC offset. Other fields, like weekday (%a
00345 // or %A), while parsed for syntactic validity, are ignored in the conversion.
00346 //
00347 // Date and time fields that are out-of-range will be treated as errors rather
00348 // than normalizing them like cctz::civil_second() would do. For example, it
00349 // is an error to parse the date "Oct 32, 2013" because 32 is out of range.
00350 //
00351 // A second of ":60" is normalized to ":00" of the following minute with
00352 // fractional seconds discarded. The following table shows how the given
00353 // seconds and subseconds will be parsed:
00354 //
00355 //   "59.x" -> 59.x  // exact
00356 //   "60.x" -> 00.0  // normalized
00357 //   "00.x" -> 00.x  // exact
00358 //
00359 // Errors are indicated by returning false.
00360 //
00361 // Example:
00362 //   const cctz::time_zone tz = ...
00363 //   std::chrono::system_clock::time_point tp;
00364 //   if (cctz::parse("%Y-%m-%d", "2015-10-09", tz, &tp)) {
00365 //     ...
00366 //   }
00367 template <typename D>
00368 inline bool parse(const std::string& fmt, const std::string& input,
00369                   const time_zone& tz, time_point<D>* tpp) {
00370   time_point<seconds> sec;
00371   detail::femtoseconds fs;
00372   const bool b = detail::parse(fmt, input, tz, &sec, &fs);
00373   if (b) {
00374     // TODO: Return false if unrepresentable as a time_point<D>.
00375     *tpp = std::chrono::time_point_cast<D>(sec);
00376     *tpp += std::chrono::duration_cast<D>(fs);
00377   }
00378   return b;
00379 }
00380 
00381 }  // namespace cctz
00382 }  // namespace time_internal
00383 }  // namespace absl
00384 
00385 #endif  // ABSL_TIME_INTERNAL_CCTZ_TIME_ZONE_H_


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15