| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499 | // Copyright 2017 The Abseil Authors.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////      https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.// The implementation of the absl::Time class, which is declared in// //absl/time.h.//// The representation for an absl::Time is an absl::Duration offset from the// epoch.  We use the traditional Unix epoch (1970-01-01 00:00:00 +0000)// for convenience, but this is not exposed in the API and could be changed.//// NOTE: To keep type verbosity to a minimum, the following variable naming// conventions are used throughout this file.//// tz: An absl::TimeZone// ci: An absl::TimeZone::CivilInfo// ti: An absl::TimeZone::TimeInfo// cd: An absl::CivilDay or a cctz::civil_day// cs: An absl::CivilSecond or a cctz::civil_second// bd: An absl::Time::Breakdown// cl: A cctz::time_zone::civil_lookup// al: A cctz::time_zone::absolute_lookup#include "absl/time/time.h"#if defined(_MSC_VER)#include <winsock2.h>  // for timeval#endif#include <cstring>#include <ctime>#include <limits>#include "absl/time/internal/cctz/include/cctz/civil_time.h"#include "absl/time/internal/cctz/include/cctz/time_zone.h"namespace cctz = absl::time_internal::cctz;namespace absl {ABSL_NAMESPACE_BEGINnamespace {inline cctz::time_point<cctz::seconds> unix_epoch() {  return std::chrono::time_point_cast<cctz::seconds>(      std::chrono::system_clock::from_time_t(0));}// Floors d to the next unit boundary closer to negative infinity.inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) {  absl::Duration rem;  int64_t q = absl::IDivDuration(d, unit, &rem);  return (q > 0 ||          rem >= ZeroDuration() ||          q == std::numeric_limits<int64_t>::min()) ? q : q - 1;}inline absl::Time::Breakdown InfiniteFutureBreakdown() {  absl::Time::Breakdown bd;  bd.year = std::numeric_limits<int64_t>::max();  bd.month = 12;  bd.day = 31;  bd.hour = 23;  bd.minute = 59;  bd.second = 59;  bd.subsecond = absl::InfiniteDuration();  bd.weekday = 4;  bd.yearday = 365;  bd.offset = 0;  bd.is_dst = false;  bd.zone_abbr = "-00";  return bd;}inline absl::Time::Breakdown InfinitePastBreakdown() {  Time::Breakdown bd;  bd.year = std::numeric_limits<int64_t>::min();  bd.month = 1;  bd.day = 1;  bd.hour = 0;  bd.minute = 0;  bd.second = 0;  bd.subsecond = -absl::InfiniteDuration();  bd.weekday = 7;  bd.yearday = 1;  bd.offset = 0;  bd.is_dst = false;  bd.zone_abbr = "-00";  return bd;}inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() {  TimeZone::CivilInfo ci;  ci.cs = CivilSecond::max();  ci.subsecond = InfiniteDuration();  ci.offset = 0;  ci.is_dst = false;  ci.zone_abbr = "-00";  return ci;}inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() {  TimeZone::CivilInfo ci;  ci.cs = CivilSecond::min();  ci.subsecond = -InfiniteDuration();  ci.offset = 0;  ci.is_dst = false;  ci.zone_abbr = "-00";  return ci;}inline absl::TimeConversion InfiniteFutureTimeConversion() {  absl::TimeConversion tc;  tc.pre = tc.trans = tc.post = absl::InfiniteFuture();  tc.kind = absl::TimeConversion::UNIQUE;  tc.normalized = true;  return tc;}inline TimeConversion InfinitePastTimeConversion() {  absl::TimeConversion tc;  tc.pre = tc.trans = tc.post = absl::InfinitePast();  tc.kind = absl::TimeConversion::UNIQUE;  tc.normalized = true;  return tc;}// Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as// necessary. If sec is min/max, then consult cs+tz to check for overlow.Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec,                          const cctz::civil_second& cs,                          const cctz::time_zone& tz,                          bool* normalized = nullptr) {  const auto max = cctz::time_point<cctz::seconds>::max();  const auto min = cctz::time_point<cctz::seconds>::min();  if (sec == max) {    const auto al = tz.lookup(max);    if (cs > al.cs) {      if (normalized) *normalized = true;      return absl::InfiniteFuture();    }  }  if (sec == min) {    const auto al = tz.lookup(min);    if (cs < al.cs) {      if (normalized) *normalized = true;      return absl::InfinitePast();    }  }  const auto hi = (sec - unix_epoch()).count();  return time_internal::FromUnixDuration(time_internal::MakeDuration(hi));}// Returns Mon=1..Sun=7.inline int MapWeekday(const cctz::weekday& wd) {  switch (wd) {    case cctz::weekday::monday:      return 1;    case cctz::weekday::tuesday:      return 2;    case cctz::weekday::wednesday:      return 3;    case cctz::weekday::thursday:      return 4;    case cctz::weekday::friday:      return 5;    case cctz::weekday::saturday:      return 6;    case cctz::weekday::sunday:      return 7;  }  return 1;}bool FindTransition(const cctz::time_zone& tz,                    bool (cctz::time_zone::*find_transition)(                        const cctz::time_point<cctz::seconds>& tp,                        cctz::time_zone::civil_transition* trans) const,                    Time t, TimeZone::CivilTransition* trans) {  // Transitions are second-aligned, so we can discard any fractional part.  const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t));  cctz::time_zone::civil_transition tr;  if (!(tz.*find_transition)(tp, &tr)) return false;  trans->from = CivilSecond(tr.from);  trans->to = CivilSecond(tr.to);  return true;}}  // namespace//// Time//absl::Time::Breakdown Time::In(absl::TimeZone tz) const {  if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown();  if (*this == absl::InfinitePast()) return InfinitePastBreakdown();  const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_));  const auto al = cctz::time_zone(tz).lookup(tp);  const auto cs = al.cs;  const auto cd = cctz::civil_day(cs);  absl::Time::Breakdown bd;  bd.year = cs.year();  bd.month = cs.month();  bd.day = cs.day();  bd.hour = cs.hour();  bd.minute = cs.minute();  bd.second = cs.second();  bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_));  bd.weekday = MapWeekday(cctz::get_weekday(cd));  bd.yearday = cctz::get_yearday(cd);  bd.offset = al.offset;  bd.is_dst = al.is_dst;  bd.zone_abbr = al.abbr;  return bd;}//// Conversions from/to other time types.//absl::Time FromUDate(double udate) {  return time_internal::FromUnixDuration(absl::Milliseconds(udate));}absl::Time FromUniversal(int64_t universal) {  return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal);}int64_t ToUnixNanos(Time t) {  if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&      time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) {    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *            1000 * 1000 * 1000) +           (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4);  }  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1));}int64_t ToUnixMicros(Time t) {  if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&      time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) {    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) *            1000 * 1000) +           (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000);  }  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1));}int64_t ToUnixMillis(Time t) {  if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 &&      time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) {    return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) +           (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) /            (4000 * 1000));  }  return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1));}int64_t ToUnixSeconds(Time t) {  return time_internal::GetRepHi(time_internal::ToUnixDuration(t));}time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; }double ToUDate(Time t) {  return absl::FDivDuration(time_internal::ToUnixDuration(t),                            absl::Milliseconds(1));}int64_t ToUniversal(absl::Time t) {  return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100));}absl::Time TimeFromTimespec(timespec ts) {  return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts));}absl::Time TimeFromTimeval(timeval tv) {  return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv));}timespec ToTimespec(Time t) {  timespec ts;  absl::Duration d = time_internal::ToUnixDuration(t);  if (!time_internal::IsInfiniteDuration(d)) {    ts.tv_sec = time_internal::GetRepHi(d);    if (ts.tv_sec == time_internal::GetRepHi(d)) {  // no time_t narrowing      ts.tv_nsec = time_internal::GetRepLo(d) / 4;  // floor      return ts;    }  }  if (d >= absl::ZeroDuration()) {    ts.tv_sec = std::numeric_limits<time_t>::max();    ts.tv_nsec = 1000 * 1000 * 1000 - 1;  } else {    ts.tv_sec = std::numeric_limits<time_t>::min();    ts.tv_nsec = 0;  }  return ts;}timeval ToTimeval(Time t) {  timeval tv;  timespec ts = absl::ToTimespec(t);  tv.tv_sec = ts.tv_sec;  if (tv.tv_sec != ts.tv_sec) {  // narrowing    if (ts.tv_sec < 0) {      tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min();      tv.tv_usec = 0;    } else {      tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max();      tv.tv_usec = 1000 * 1000 - 1;    }    return tv;  }  tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000);  // suseconds_t  return tv;}Time FromChrono(const std::chrono::system_clock::time_point& tp) {  return time_internal::FromUnixDuration(time_internal::FromChrono(      tp - std::chrono::system_clock::from_time_t(0)));}std::chrono::system_clock::time_point ToChronoTime(absl::Time t) {  using D = std::chrono::system_clock::duration;  auto d = time_internal::ToUnixDuration(t);  if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1}));  return std::chrono::system_clock::from_time_t(0) +         time_internal::ToChronoDuration<D>(d);}//// TimeZone//absl::TimeZone::CivilInfo TimeZone::At(Time t) const {  if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo();  if (t == absl::InfinitePast()) return InfinitePastCivilInfo();  const auto ud = time_internal::ToUnixDuration(t);  const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud));  const auto al = cz_.lookup(tp);  TimeZone::CivilInfo ci;  ci.cs = CivilSecond(al.cs);  ci.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(ud));  ci.offset = al.offset;  ci.is_dst = al.is_dst;  ci.zone_abbr = al.abbr;  return ci;}absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const {  const cctz::civil_second cs(ct);  const auto cl = cz_.lookup(cs);  TimeZone::TimeInfo ti;  switch (cl.kind) {    case cctz::time_zone::civil_lookup::UNIQUE:      ti.kind = TimeZone::TimeInfo::UNIQUE;      break;    case cctz::time_zone::civil_lookup::SKIPPED:      ti.kind = TimeZone::TimeInfo::SKIPPED;      break;    case cctz::time_zone::civil_lookup::REPEATED:      ti.kind = TimeZone::TimeInfo::REPEATED;      break;  }  ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_);  ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_);  ti.post = MakeTimeWithOverflow(cl.post, cs, cz_);  return ti;}bool TimeZone::NextTransition(Time t, CivilTransition* trans) const {  return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans);}bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const {  return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans);}//// Conversions involving time zones.//absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour,                                     int min, int sec, TimeZone tz) {  // Avoids years that are too extreme for CivilSecond to normalize.  if (year > 300000000000) return InfiniteFutureTimeConversion();  if (year < -300000000000) return InfinitePastTimeConversion();  const CivilSecond cs(year, mon, day, hour, min, sec);  const auto ti = tz.At(cs);  TimeConversion tc;  tc.pre = ti.pre;  tc.trans = ti.trans;  tc.post = ti.post;  switch (ti.kind) {    case TimeZone::TimeInfo::UNIQUE:      tc.kind = TimeConversion::UNIQUE;      break;    case TimeZone::TimeInfo::SKIPPED:      tc.kind = TimeConversion::SKIPPED;      break;    case TimeZone::TimeInfo::REPEATED:      tc.kind = TimeConversion::REPEATED;      break;  }  tc.normalized = false;  if (year != cs.year() || mon != cs.month() || day != cs.day() ||      hour != cs.hour() || min != cs.minute() || sec != cs.second()) {    tc.normalized = true;  }  return tc;}absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) {  civil_year_t tm_year = tm.tm_year;  // Avoids years that are too extreme for CivilSecond to normalize.  if (tm_year > 300000000000ll) return InfiniteFuture();  if (tm_year < -300000000000ll) return InfinitePast();  int tm_mon = tm.tm_mon;  if (tm_mon == std::numeric_limits<int>::max()) {    tm_mon -= 12;    tm_year += 1;  }  const auto ti = tz.At(CivilSecond(tm_year + 1900, tm_mon + 1, tm.tm_mday,                                    tm.tm_hour, tm.tm_min, tm.tm_sec));  return tm.tm_isdst == 0 ? ti.post : ti.pre;}struct tm ToTM(absl::Time t, absl::TimeZone tz) {  struct tm tm = {};  const auto ci = tz.At(t);  const auto& cs = ci.cs;  tm.tm_sec = cs.second();  tm.tm_min = cs.minute();  tm.tm_hour = cs.hour();  tm.tm_mday = cs.day();  tm.tm_mon = cs.month() - 1;  // Saturates tm.tm_year in cases of over/underflow, accounting for the fact  // that tm.tm_year is years since 1900.  if (cs.year() < std::numeric_limits<int>::min() + 1900) {    tm.tm_year = std::numeric_limits<int>::min();  } else if (cs.year() > std::numeric_limits<int>::max()) {    tm.tm_year = std::numeric_limits<int>::max() - 1900;  } else {    tm.tm_year = static_cast<int>(cs.year() - 1900);  }  switch (GetWeekday(cs)) {    case Weekday::sunday:      tm.tm_wday = 0;      break;    case Weekday::monday:      tm.tm_wday = 1;      break;    case Weekday::tuesday:      tm.tm_wday = 2;      break;    case Weekday::wednesday:      tm.tm_wday = 3;      break;    case Weekday::thursday:      tm.tm_wday = 4;      break;    case Weekday::friday:      tm.tm_wday = 5;      break;    case Weekday::saturday:      tm.tm_wday = 6;      break;  }  tm.tm_yday = GetYearDay(cs) - 1;  tm.tm_isdst = ci.is_dst ? 1 : 0;  return tm;}ABSL_NAMESPACE_END}  // namespace absl
 |