time.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
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 // The implementation of the absl::Time class, which is declared in
00016 // //absl/time.h.
00017 //
00018 // The representation for an absl::Time is an absl::Duration offset from the
00019 // epoch.  We use the traditional Unix epoch (1970-01-01 00:00:00 +0000)
00020 // for convenience, but this is not exposed in the API and could be changed.
00021 //
00022 // NOTE: To keep type verbosity to a minimum, the following variable naming
00023 // conventions are used throughout this file.
00024 //
00025 // tz: An absl::TimeZone
00026 // ci: An absl::TimeZone::CivilInfo
00027 // ti: An absl::TimeZone::TimeInfo
00028 // cd: An absl::CivilDay or a cctz::civil_day
00029 // cs: An absl::CivilSecond or a cctz::civil_second
00030 // bd: An absl::Time::Breakdown
00031 // cl: A cctz::time_zone::civil_lookup
00032 // al: A cctz::time_zone::absolute_lookup
00033 
00034 #include "absl/time/time.h"
00035 
00036 #include <cstring>
00037 #include <ctime>
00038 #include <limits>
00039 
00040 #include "absl/time/internal/cctz/include/cctz/civil_time.h"
00041 #include "absl/time/internal/cctz/include/cctz/time_zone.h"
00042 
00043 namespace cctz = absl::time_internal::cctz;
00044 
00045 namespace absl {
00046 
00047 namespace {
00048 
00049 inline cctz::time_point<cctz::seconds> unix_epoch() {
00050   return std::chrono::time_point_cast<cctz::seconds>(
00051       std::chrono::system_clock::from_time_t(0));
00052 }
00053 
00054 // Floors d to the next unit boundary closer to negative infinity.
00055 inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {
00056   absl::Duration rem;
00057   int64_t q = absl::IDivDuration(d, unit, &rem);
00058   return (q > 0 ||
00059           rem >= ZeroDuration() ||
00060           q == std::numeric_limits<int64_t>::min()) ? q : q - 1;
00061 }
00062 
00063 inline absl::Time::Breakdown InfiniteFutureBreakdown() {
00064   absl::Time::Breakdown bd;
00065   bd.year = std::numeric_limits<int64_t>::max();
00066   bd.month = 12;
00067   bd.day = 31;
00068   bd.hour = 23;
00069   bd.minute = 59;
00070   bd.second = 59;
00071   bd.subsecond = absl::InfiniteDuration();
00072   bd.weekday = 4;
00073   bd.yearday = 365;
00074   bd.offset = 0;
00075   bd.is_dst = false;
00076   bd.zone_abbr = "-00";
00077   return bd;
00078 }
00079 
00080 inline absl::Time::Breakdown InfinitePastBreakdown() {
00081   Time::Breakdown bd;
00082   bd.year = std::numeric_limits<int64_t>::min();
00083   bd.month = 1;
00084   bd.day = 1;
00085   bd.hour = 0;
00086   bd.minute = 0;
00087   bd.second = 0;
00088   bd.subsecond = -absl::InfiniteDuration();
00089   bd.weekday = 7;
00090   bd.yearday = 1;
00091   bd.offset = 0;
00092   bd.is_dst = false;
00093   bd.zone_abbr = "-00";
00094   return bd;
00095 }
00096 
00097 inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() {
00098   TimeZone::CivilInfo ci;
00099   ci.cs = CivilSecond::max();
00100   ci.subsecond = InfiniteDuration();
00101   ci.offset = 0;
00102   ci.is_dst = false;
00103   ci.zone_abbr = "-00";
00104   return ci;
00105 }
00106 
00107 inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() {
00108   TimeZone::CivilInfo ci;
00109   ci.cs = CivilSecond::min();
00110   ci.subsecond = -InfiniteDuration();
00111   ci.offset = 0;
00112   ci.is_dst = false;
00113   ci.zone_abbr = "-00";
00114   return ci;
00115 }
00116 
00117 inline absl::TimeConversion InfiniteFutureTimeConversion() {
00118   absl::TimeConversion tc;
00119   tc.pre = tc.trans = tc.post = absl::InfiniteFuture();
00120   tc.kind = absl::TimeConversion::UNIQUE;
00121   tc.normalized = true;
00122   return tc;
00123 }
00124 
00125 inline TimeConversion InfinitePastTimeConversion() {
00126   absl::TimeConversion tc;
00127   tc.pre = tc.trans = tc.post = absl::InfinitePast();
00128   tc.kind = absl::TimeConversion::UNIQUE;
00129   tc.normalized = true;
00130   return tc;
00131 }
00132 
00133 // Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as
00134 // necessary. If sec is min/max, then consult cs+tz to check for overlow.
00135 Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec,
00136                           const cctz::civil_second& cs,
00137                           const cctz::time_zone& tz,
00138                           bool* normalized = nullptr) {
00139   const auto max = cctz::time_point<cctz::seconds>::max();
00140   const auto min = cctz::time_point<cctz::seconds>::min();
00141   if (sec == max) {
00142     const auto al = tz.lookup(max);
00143     if (cs > al.cs) {
00144       if (normalized) *normalized = true;
00145       return absl::InfiniteFuture();
00146     }
00147   }
00148   if (sec == min) {
00149     const auto al = tz.lookup(min);
00150     if (cs < al.cs) {
00151       if (normalized) *normalized = true;
00152       return absl::InfinitePast();
00153     }
00154   }
00155   const auto hi = (sec - unix_epoch()).count();
00156   return time_internal::FromUnixDuration(time_internal::MakeDuration(hi));
00157 }
00158 
00159 // Returns Mon=1..Sun=7.
00160 inline int MapWeekday(const cctz::weekday& wd) {
00161   switch (wd) {
00162     case cctz::weekday::monday:
00163       return 1;
00164     case cctz::weekday::tuesday:
00165       return 2;
00166     case cctz::weekday::wednesday:
00167       return 3;
00168     case cctz::weekday::thursday:
00169       return 4;
00170     case cctz::weekday::friday:
00171       return 5;
00172     case cctz::weekday::saturday:
00173       return 6;
00174     case cctz::weekday::sunday:
00175       return 7;
00176   }
00177   return 1;
00178 }
00179 
00180 bool FindTransition(const cctz::time_zone& tz,
00181                     bool (cctz::time_zone::*find_transition)(
00182                         const cctz::time_point<cctz::seconds>& tp,
00183                         cctz::time_zone::civil_transition* trans) const,
00184                     Time t, TimeZone::CivilTransition* trans) {
00185   // Transitions are second-aligned, so we can discard any fractional part.
00186   const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t));
00187   cctz::time_zone::civil_transition tr;
00188   if (!(tz.*find_transition)(tp, &tr)) return false;
00189   trans->from = CivilSecond(tr.from);
00190   trans->to = CivilSecond(tr.to);
00191   return true;
00192 }
00193 
00194 }  // namespace
00195 
00196 //
00197 // Time
00198 //
00199 
00200 absl::Time::Breakdown Time::In(absl::TimeZone tz) const {
00201   if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown();
00202   if (*this == absl::InfinitePast()) return InfinitePastBreakdown();
00203 
00204   const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_));
00205   const auto al = cctz::time_zone(tz).lookup(tp);
00206   const auto cs = al.cs;
00207   const auto cd = cctz::civil_day(cs);
00208 
00209   absl::Time::Breakdown bd;
00210   bd.year = cs.year();
00211   bd.month = cs.month();
00212   bd.day = cs.day();
00213   bd.hour = cs.hour();
00214   bd.minute = cs.minute();
00215   bd.second = cs.second();
00216   bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_));
00217   bd.weekday = MapWeekday(cctz::get_weekday(cd));
00218   bd.yearday = cctz::get_yearday(cd);
00219   bd.offset = al.offset;
00220   bd.is_dst = al.is_dst;
00221   bd.zone_abbr = al.abbr;
00222   return bd;
00223 }
00224 
00225 //
00226 // Conversions from/to other time types.
00227 //
00228 
00229 absl::Time FromUDate(double udate) {
00230   return time_internal::FromUnixDuration(absl::Milliseconds(udate));
00231 }
00232 
00233 absl::Time FromUniversal(int64_t universal) {
00234   return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal);
00235 }
00236 
00237 int64_t ToUnixNanos(Time t) {
00238   if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
00239       time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) {
00240     return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
00241             1000 * 1000 * 1000) +
00242            (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4);
00243   }
00244   return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1));
00245 }
00246 
00247 int64_t ToUnixMicros(Time t) {
00248   if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
00249       time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) {
00250     return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *
00251             1000 * 1000) +
00252            (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000);
00253   }
00254   return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1));
00255 }
00256 
00257 int64_t ToUnixMillis(Time t) {
00258   if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&
00259       time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) {
00260     return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) +
00261            (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) /
00262             (4000 * 1000));
00263   }
00264   return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1));
00265 }
00266 
00267 int64_t ToUnixSeconds(Time t) {
00268   return time_internal::GetRepHi(time_internal::ToUnixDuration(t));
00269 }
00270 
00271 time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; }
00272 
00273 double ToUDate(Time t) {
00274   return absl::FDivDuration(time_internal::ToUnixDuration(t),
00275                             absl::Milliseconds(1));
00276 }
00277 
00278 int64_t ToUniversal(absl::Time t) {
00279   return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));
00280 }
00281 
00282 absl::Time TimeFromTimespec(timespec ts) {
00283   return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts));
00284 }
00285 
00286 absl::Time TimeFromTimeval(timeval tv) {
00287   return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv));
00288 }
00289 
00290 timespec ToTimespec(Time t) {
00291   timespec ts;
00292   absl::Duration d = time_internal::ToUnixDuration(t);
00293   if (!time_internal::IsInfiniteDuration(d)) {
00294     ts.tv_sec = time_internal::GetRepHi(d);
00295     if (ts.tv_sec == time_internal::GetRepHi(d)) {  // no time_t narrowing
00296       ts.tv_nsec = time_internal::GetRepLo(d) / 4;  // floor
00297       return ts;
00298     }
00299   }
00300   if (d >= absl::ZeroDuration()) {
00301     ts.tv_sec = std::numeric_limits<time_t>::max();
00302     ts.tv_nsec = 1000 * 1000 * 1000 - 1;
00303   } else {
00304     ts.tv_sec = std::numeric_limits<time_t>::min();
00305     ts.tv_nsec = 0;
00306   }
00307   return ts;
00308 }
00309 
00310 timeval ToTimeval(Time t) {
00311   timeval tv;
00312   timespec ts = absl::ToTimespec(t);
00313   tv.tv_sec = ts.tv_sec;
00314   if (tv.tv_sec != ts.tv_sec) {  // narrowing
00315     if (ts.tv_sec < 0) {
00316       tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();
00317       tv.tv_usec = 0;
00318     } else {
00319       tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();
00320       tv.tv_usec = 1000 * 1000 - 1;
00321     }
00322     return tv;
00323   }
00324   tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000);  // suseconds_t
00325   return tv;
00326 }
00327 
00328 Time FromChrono(const std::chrono::system_clock::time_point& tp) {
00329   return time_internal::FromUnixDuration(time_internal::FromChrono(
00330       tp - std::chrono::system_clock::from_time_t(0)));
00331 }
00332 
00333 std::chrono::system_clock::time_point ToChronoTime(absl::Time t) {
00334   using D = std::chrono::system_clock::duration;
00335   auto d = time_internal::ToUnixDuration(t);
00336   if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1}));
00337   return std::chrono::system_clock::from_time_t(0) +
00338          time_internal::ToChronoDuration<D>(d);
00339 }
00340 
00341 //
00342 // TimeZone
00343 //
00344 
00345 absl::TimeZone::CivilInfo TimeZone::At(Time t) const {
00346   if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo();
00347   if (t == absl::InfinitePast()) return InfinitePastCivilInfo();
00348 
00349   const auto ud = time_internal::ToUnixDuration(t);
00350   const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud));
00351   const auto al = cz_.lookup(tp);
00352 
00353   TimeZone::CivilInfo ci;
00354   ci.cs = CivilSecond(al.cs);
00355   ci.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(ud));
00356   ci.offset = al.offset;
00357   ci.is_dst = al.is_dst;
00358   ci.zone_abbr = al.abbr;
00359   return ci;
00360 }
00361 
00362 absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const {
00363   const cctz::civil_second cs(ct);
00364   const auto cl = cz_.lookup(cs);
00365 
00366   TimeZone::TimeInfo ti;
00367   switch (cl.kind) {
00368     case cctz::time_zone::civil_lookup::UNIQUE:
00369       ti.kind = TimeZone::TimeInfo::UNIQUE;
00370       break;
00371     case cctz::time_zone::civil_lookup::SKIPPED:
00372       ti.kind = TimeZone::TimeInfo::SKIPPED;
00373       break;
00374     case cctz::time_zone::civil_lookup::REPEATED:
00375       ti.kind = TimeZone::TimeInfo::REPEATED;
00376       break;
00377   }
00378   ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_);
00379   ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_);
00380   ti.post = MakeTimeWithOverflow(cl.post, cs, cz_);
00381   return ti;
00382 }
00383 
00384 bool TimeZone::NextTransition(Time t, CivilTransition* trans) const {
00385   return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans);
00386 }
00387 
00388 bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const {
00389   return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans);
00390 }
00391 
00392 //
00393 // Conversions involving time zones.
00394 //
00395 
00396 absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,
00397                                      int min, int sec, TimeZone tz) {
00398   // Avoids years that are too extreme for CivilSecond to normalize.
00399   if (year > 300000000000) return InfiniteFutureTimeConversion();
00400   if (year < -300000000000) return InfinitePastTimeConversion();
00401 
00402   const CivilSecond cs(year, mon, day, hour, min, sec);
00403   const auto ti = tz.At(cs);
00404 
00405   TimeConversion tc;
00406   tc.pre = ti.pre;
00407   tc.trans = ti.trans;
00408   tc.post = ti.post;
00409   switch (ti.kind) {
00410     case TimeZone::TimeInfo::UNIQUE:
00411       tc.kind = TimeConversion::UNIQUE;
00412       break;
00413     case TimeZone::TimeInfo::SKIPPED:
00414       tc.kind = TimeConversion::SKIPPED;
00415       break;
00416     case TimeZone::TimeInfo::REPEATED:
00417       tc.kind = TimeConversion::REPEATED;
00418       break;
00419   }
00420   tc.normalized = false;
00421   if (year != cs.year() || mon != cs.month() || day != cs.day() ||
00422       hour != cs.hour() || min != cs.minute() || sec != cs.second()) {
00423     tc.normalized = true;
00424   }
00425   return tc;
00426 }
00427 
00428 absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {
00429   const CivilSecond cs(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
00430                        tm.tm_hour, tm.tm_min, tm.tm_sec);
00431   const auto ti = tz.At(cs);
00432   return tm.tm_isdst == 0 ? ti.post : ti.pre;
00433 }
00434 
00435 struct tm ToTM(absl::Time t, absl::TimeZone tz) {
00436   struct tm tm = {};
00437 
00438   const auto ci = tz.At(t);
00439   const auto& cs = ci.cs;
00440   tm.tm_sec = cs.second();
00441   tm.tm_min = cs.minute();
00442   tm.tm_hour = cs.hour();
00443   tm.tm_mday = cs.day();
00444   tm.tm_mon = cs.month() - 1;
00445 
00446   // Saturates tm.tm_year in cases of over/underflow, accounting for the fact
00447   // that tm.tm_year is years since 1900.
00448   if (cs.year() < std::numeric_limits<int>::min() + 1900) {
00449     tm.tm_year = std::numeric_limits<int>::min();
00450   } else if (cs.year() > std::numeric_limits<int>::max()) {
00451     tm.tm_year = std::numeric_limits<int>::max() - 1900;
00452   } else {
00453     tm.tm_year = static_cast<int>(cs.year() - 1900);
00454   }
00455 
00456   const CivilDay cd(cs);
00457   switch (GetWeekday(cd)) {
00458     case Weekday::sunday:
00459       tm.tm_wday = 0;
00460       break;
00461     case Weekday::monday:
00462       tm.tm_wday = 1;
00463       break;
00464     case Weekday::tuesday:
00465       tm.tm_wday = 2;
00466       break;
00467     case Weekday::wednesday:
00468       tm.tm_wday = 3;
00469       break;
00470     case Weekday::thursday:
00471       tm.tm_wday = 4;
00472       break;
00473     case Weekday::friday:
00474       tm.tm_wday = 5;
00475       break;
00476     case Weekday::saturday:
00477       tm.tm_wday = 6;
00478       break;
00479   }
00480   tm.tm_yday = GetYearDay(cd) - 1;
00481   tm.tm_isdst = ci.is_dst ? 1 : 0;
00482 
00483   return tm;
00484 }
00485 
00486 }  // namespace absl


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