time.cc (15652B)
1 // Copyright 2017 The Abseil Authors. 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 // The implementation of the absl::Time class, which is declared in 16 // //absl/time.h. 17 // 18 // The representation for an absl::Time is an absl::Duration offset from the 19 // epoch. We use the traditional Unix epoch (1970-01-01 00:00:00 +0000) 20 // for convenience, but this is not exposed in the API and could be changed. 21 // 22 // NOTE: To keep type verbosity to a minimum, the following variable naming 23 // conventions are used throughout this file. 24 // 25 // tz: An absl::TimeZone 26 // ci: An absl::TimeZone::CivilInfo 27 // ti: An absl::TimeZone::TimeInfo 28 // cd: An absl::CivilDay or a cctz::civil_day 29 // cs: An absl::CivilSecond or a cctz::civil_second 30 // bd: An absl::Time::Breakdown 31 // cl: A cctz::time_zone::civil_lookup 32 // al: A cctz::time_zone::absolute_lookup 33 34 #include "absl/time/time.h" 35 36 #if defined(_MSC_VER) 37 #include <winsock2.h> // for timeval 38 #endif 39 40 #include <cstring> 41 #include <ctime> 42 #include <limits> 43 44 #include "absl/time/internal/cctz/include/cctz/civil_time.h" 45 #include "absl/time/internal/cctz/include/cctz/time_zone.h" 46 47 namespace cctz = absl::time_internal::cctz; 48 49 namespace absl { 50 ABSL_NAMESPACE_BEGIN 51 52 namespace { 53 54 inline cctz::time_point<cctz::seconds> unix_epoch() { 55 return std::chrono::time_point_cast<cctz::seconds>( 56 std::chrono::system_clock::from_time_t(0)); 57 } 58 59 // Floors d to the next unit boundary closer to negative infinity. 60 inline int64_t FloorToUnit(absl::Duration d, absl::Duration unit) { 61 absl::Duration rem; 62 int64_t q = absl::IDivDuration(d, unit, &rem); 63 return (q > 0 || rem >= ZeroDuration() || 64 q == std::numeric_limits<int64_t>::min()) 65 ? q 66 : q - 1; 67 } 68 69 ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING 70 inline absl::Time::Breakdown InfiniteFutureBreakdown() { 71 absl::Time::Breakdown bd; 72 bd.year = std::numeric_limits<int64_t>::max(); 73 bd.month = 12; 74 bd.day = 31; 75 bd.hour = 23; 76 bd.minute = 59; 77 bd.second = 59; 78 bd.subsecond = absl::InfiniteDuration(); 79 bd.weekday = 4; 80 bd.yearday = 365; 81 bd.offset = 0; 82 bd.is_dst = false; 83 bd.zone_abbr = "-00"; 84 return bd; 85 } 86 87 inline absl::Time::Breakdown InfinitePastBreakdown() { 88 Time::Breakdown bd; 89 bd.year = std::numeric_limits<int64_t>::min(); 90 bd.month = 1; 91 bd.day = 1; 92 bd.hour = 0; 93 bd.minute = 0; 94 bd.second = 0; 95 bd.subsecond = -absl::InfiniteDuration(); 96 bd.weekday = 7; 97 bd.yearday = 1; 98 bd.offset = 0; 99 bd.is_dst = false; 100 bd.zone_abbr = "-00"; 101 return bd; 102 } 103 ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING 104 105 inline absl::TimeZone::CivilInfo InfiniteFutureCivilInfo() { 106 TimeZone::CivilInfo ci; 107 ci.cs = CivilSecond::max(); 108 ci.subsecond = InfiniteDuration(); 109 ci.offset = 0; 110 ci.is_dst = false; 111 ci.zone_abbr = "-00"; 112 return ci; 113 } 114 115 inline absl::TimeZone::CivilInfo InfinitePastCivilInfo() { 116 TimeZone::CivilInfo ci; 117 ci.cs = CivilSecond::min(); 118 ci.subsecond = -InfiniteDuration(); 119 ci.offset = 0; 120 ci.is_dst = false; 121 ci.zone_abbr = "-00"; 122 return ci; 123 } 124 125 ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING 126 inline absl::TimeConversion InfiniteFutureTimeConversion() { 127 absl::TimeConversion tc; 128 tc.pre = tc.trans = tc.post = absl::InfiniteFuture(); 129 tc.kind = absl::TimeConversion::UNIQUE; 130 tc.normalized = true; 131 return tc; 132 } 133 134 inline TimeConversion InfinitePastTimeConversion() { 135 absl::TimeConversion tc; 136 tc.pre = tc.trans = tc.post = absl::InfinitePast(); 137 tc.kind = absl::TimeConversion::UNIQUE; 138 tc.normalized = true; 139 return tc; 140 } 141 ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING 142 143 // Makes a Time from sec, overflowing to InfiniteFuture/InfinitePast as 144 // necessary. If sec is min/max, then consult cs+tz to check for overflow. 145 Time MakeTimeWithOverflow(const cctz::time_point<cctz::seconds>& sec, 146 const cctz::civil_second& cs, 147 const cctz::time_zone& tz, 148 bool* normalized = nullptr) { 149 const auto max = cctz::time_point<cctz::seconds>::max(); 150 const auto min = cctz::time_point<cctz::seconds>::min(); 151 if (sec == max) { 152 const auto al = tz.lookup(max); 153 if (cs > al.cs) { 154 if (normalized) *normalized = true; 155 return absl::InfiniteFuture(); 156 } 157 } 158 if (sec == min) { 159 const auto al = tz.lookup(min); 160 if (cs < al.cs) { 161 if (normalized) *normalized = true; 162 return absl::InfinitePast(); 163 } 164 } 165 const auto hi = (sec - unix_epoch()).count(); 166 return time_internal::FromUnixDuration(time_internal::MakeDuration(hi)); 167 } 168 169 // Returns Mon=1..Sun=7. 170 inline int MapWeekday(const cctz::weekday& wd) { 171 switch (wd) { 172 case cctz::weekday::monday: 173 return 1; 174 case cctz::weekday::tuesday: 175 return 2; 176 case cctz::weekday::wednesday: 177 return 3; 178 case cctz::weekday::thursday: 179 return 4; 180 case cctz::weekday::friday: 181 return 5; 182 case cctz::weekday::saturday: 183 return 6; 184 case cctz::weekday::sunday: 185 return 7; 186 } 187 return 1; 188 } 189 190 bool FindTransition(const cctz::time_zone& tz, 191 bool (cctz::time_zone::*find_transition)( 192 const cctz::time_point<cctz::seconds>& tp, 193 cctz::time_zone::civil_transition* trans) const, 194 Time t, TimeZone::CivilTransition* trans) { 195 // Transitions are second-aligned, so we can discard any fractional part. 196 const auto tp = unix_epoch() + cctz::seconds(ToUnixSeconds(t)); 197 cctz::time_zone::civil_transition tr; 198 if (!(tz.*find_transition)(tp, &tr)) return false; 199 trans->from = CivilSecond(tr.from); 200 trans->to = CivilSecond(tr.to); 201 return true; 202 } 203 204 } // namespace 205 206 // 207 // Time 208 // 209 210 ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING 211 absl::Time::Breakdown Time::In(absl::TimeZone tz) const { 212 if (*this == absl::InfiniteFuture()) return InfiniteFutureBreakdown(); 213 if (*this == absl::InfinitePast()) return InfinitePastBreakdown(); 214 215 const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(rep_)); 216 const auto al = cctz::time_zone(tz).lookup(tp); 217 const auto cs = al.cs; 218 const auto cd = cctz::civil_day(cs); 219 220 absl::Time::Breakdown bd; 221 bd.year = cs.year(); 222 bd.month = cs.month(); 223 bd.day = cs.day(); 224 bd.hour = cs.hour(); 225 bd.minute = cs.minute(); 226 bd.second = cs.second(); 227 bd.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(rep_)); 228 bd.weekday = MapWeekday(cctz::get_weekday(cd)); 229 bd.yearday = cctz::get_yearday(cd); 230 bd.offset = al.offset; 231 bd.is_dst = al.is_dst; 232 bd.zone_abbr = al.abbr; 233 return bd; 234 } 235 ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING 236 237 // 238 // Conversions from/to other time types. 239 // 240 241 absl::Time FromUDate(double udate) { 242 return time_internal::FromUnixDuration(absl::Milliseconds(udate)); 243 } 244 245 absl::Time FromUniversal(int64_t universal) { 246 return absl::UniversalEpoch() + 100 * absl::Nanoseconds(universal); 247 } 248 249 int64_t ToUnixNanos(Time t) { 250 if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 && 251 time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 33 == 0) { 252 return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 253 1000 * 1000 * 1000) + 254 (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4); 255 } 256 return FloorToUnit(time_internal::ToUnixDuration(t), absl::Nanoseconds(1)); 257 } 258 259 int64_t ToUnixMicros(Time t) { 260 if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 && 261 time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 43 == 0) { 262 return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 263 1000 * 1000) + 264 (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 4000); 265 } 266 return FloorToUnit(time_internal::ToUnixDuration(t), absl::Microseconds(1)); 267 } 268 269 int64_t ToUnixMillis(Time t) { 270 if (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >= 0 && 271 time_internal::GetRepHi(time_internal::ToUnixDuration(t)) >> 53 == 0) { 272 return (time_internal::GetRepHi(time_internal::ToUnixDuration(t)) * 1000) + 273 (time_internal::GetRepLo(time_internal::ToUnixDuration(t)) / 274 (4000 * 1000)); 275 } 276 return FloorToUnit(time_internal::ToUnixDuration(t), absl::Milliseconds(1)); 277 } 278 279 int64_t ToUnixSeconds(Time t) { 280 return time_internal::GetRepHi(time_internal::ToUnixDuration(t)); 281 } 282 283 time_t ToTimeT(Time t) { return absl::ToTimespec(t).tv_sec; } 284 285 double ToUDate(Time t) { 286 return absl::FDivDuration(time_internal::ToUnixDuration(t), 287 absl::Milliseconds(1)); 288 } 289 290 int64_t ToUniversal(absl::Time t) { 291 return absl::FloorToUnit(t - absl::UniversalEpoch(), absl::Nanoseconds(100)); 292 } 293 294 absl::Time TimeFromTimespec(timespec ts) { 295 return time_internal::FromUnixDuration(absl::DurationFromTimespec(ts)); 296 } 297 298 absl::Time TimeFromTimeval(timeval tv) { 299 return time_internal::FromUnixDuration(absl::DurationFromTimeval(tv)); 300 } 301 302 timespec ToTimespec(Time t) { 303 timespec ts; 304 absl::Duration d = time_internal::ToUnixDuration(t); 305 if (!time_internal::IsInfiniteDuration(d)) { 306 ts.tv_sec = static_cast<decltype(ts.tv_sec)>(time_internal::GetRepHi(d)); 307 if (ts.tv_sec == time_internal::GetRepHi(d)) { // no time_t narrowing 308 ts.tv_nsec = time_internal::GetRepLo(d) / 4; // floor 309 return ts; 310 } 311 } 312 if (d >= absl::ZeroDuration()) { 313 ts.tv_sec = std::numeric_limits<time_t>::max(); 314 ts.tv_nsec = 1000 * 1000 * 1000 - 1; 315 } else { 316 ts.tv_sec = std::numeric_limits<time_t>::min(); 317 ts.tv_nsec = 0; 318 } 319 return ts; 320 } 321 322 timeval ToTimeval(Time t) { 323 timeval tv; 324 timespec ts = absl::ToTimespec(t); 325 tv.tv_sec = static_cast<decltype(tv.tv_sec)>(ts.tv_sec); 326 if (tv.tv_sec != ts.tv_sec) { // narrowing 327 if (ts.tv_sec < 0) { 328 tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::min(); 329 tv.tv_usec = 0; 330 } else { 331 tv.tv_sec = std::numeric_limits<decltype(tv.tv_sec)>::max(); 332 tv.tv_usec = 1000 * 1000 - 1; 333 } 334 return tv; 335 } 336 tv.tv_usec = static_cast<int>(ts.tv_nsec / 1000); // suseconds_t 337 return tv; 338 } 339 340 Time FromChrono(const std::chrono::system_clock::time_point& tp) { 341 return time_internal::FromUnixDuration(time_internal::FromChrono( 342 tp - std::chrono::system_clock::from_time_t(0))); 343 } 344 345 std::chrono::system_clock::time_point ToChronoTime(absl::Time t) { 346 using D = std::chrono::system_clock::duration; 347 auto d = time_internal::ToUnixDuration(t); 348 if (d < ZeroDuration()) d = Floor(d, FromChrono(D{1})); 349 return std::chrono::system_clock::from_time_t(0) + 350 time_internal::ToChronoDuration<D>(d); 351 } 352 353 // 354 // TimeZone 355 // 356 357 absl::TimeZone::CivilInfo TimeZone::At(Time t) const { 358 if (t == absl::InfiniteFuture()) return InfiniteFutureCivilInfo(); 359 if (t == absl::InfinitePast()) return InfinitePastCivilInfo(); 360 361 const auto ud = time_internal::ToUnixDuration(t); 362 const auto tp = unix_epoch() + cctz::seconds(time_internal::GetRepHi(ud)); 363 const auto al = cz_.lookup(tp); 364 365 TimeZone::CivilInfo ci; 366 ci.cs = CivilSecond(al.cs); 367 ci.subsecond = time_internal::MakeDuration(0, time_internal::GetRepLo(ud)); 368 ci.offset = al.offset; 369 ci.is_dst = al.is_dst; 370 ci.zone_abbr = al.abbr; 371 return ci; 372 } 373 374 absl::TimeZone::TimeInfo TimeZone::At(CivilSecond ct) const { 375 const cctz::civil_second cs(ct); 376 const auto cl = cz_.lookup(cs); 377 378 TimeZone::TimeInfo ti; 379 switch (cl.kind) { 380 case cctz::time_zone::civil_lookup::UNIQUE: 381 ti.kind = TimeZone::TimeInfo::UNIQUE; 382 break; 383 case cctz::time_zone::civil_lookup::SKIPPED: 384 ti.kind = TimeZone::TimeInfo::SKIPPED; 385 break; 386 case cctz::time_zone::civil_lookup::REPEATED: 387 ti.kind = TimeZone::TimeInfo::REPEATED; 388 break; 389 } 390 ti.pre = MakeTimeWithOverflow(cl.pre, cs, cz_); 391 ti.trans = MakeTimeWithOverflow(cl.trans, cs, cz_); 392 ti.post = MakeTimeWithOverflow(cl.post, cs, cz_); 393 return ti; 394 } 395 396 bool TimeZone::NextTransition(Time t, CivilTransition* trans) const { 397 return FindTransition(cz_, &cctz::time_zone::next_transition, t, trans); 398 } 399 400 bool TimeZone::PrevTransition(Time t, CivilTransition* trans) const { 401 return FindTransition(cz_, &cctz::time_zone::prev_transition, t, trans); 402 } 403 404 // 405 // Conversions involving time zones. 406 // 407 ABSL_INTERNAL_DISABLE_DEPRECATED_DECLARATION_WARNING 408 absl::TimeConversion ConvertDateTime(int64_t year, int mon, int day, int hour, 409 int min, int sec, TimeZone tz) { 410 // Avoids years that are too extreme for CivilSecond to normalize. 411 if (year > 300000000000) return InfiniteFutureTimeConversion(); 412 if (year < -300000000000) return InfinitePastTimeConversion(); 413 414 const CivilSecond cs(year, mon, day, hour, min, sec); 415 const auto ti = tz.At(cs); 416 417 TimeConversion tc; 418 tc.pre = ti.pre; 419 tc.trans = ti.trans; 420 tc.post = ti.post; 421 switch (ti.kind) { 422 case TimeZone::TimeInfo::UNIQUE: 423 tc.kind = TimeConversion::UNIQUE; 424 break; 425 case TimeZone::TimeInfo::SKIPPED: 426 tc.kind = TimeConversion::SKIPPED; 427 break; 428 case TimeZone::TimeInfo::REPEATED: 429 tc.kind = TimeConversion::REPEATED; 430 break; 431 } 432 tc.normalized = false; 433 if (year != cs.year() || mon != cs.month() || day != cs.day() || 434 hour != cs.hour() || min != cs.minute() || sec != cs.second()) { 435 tc.normalized = true; 436 } 437 return tc; 438 } 439 ABSL_INTERNAL_RESTORE_DEPRECATED_DECLARATION_WARNING 440 441 absl::Time FromTM(const struct tm& tm, absl::TimeZone tz) { 442 civil_year_t tm_year = tm.tm_year; 443 // Avoids years that are too extreme for CivilSecond to normalize. 444 if (tm_year > 300000000000ll) return InfiniteFuture(); 445 if (tm_year < -300000000000ll) return InfinitePast(); 446 int tm_mon = tm.tm_mon; 447 if (tm_mon == std::numeric_limits<int>::max()) { 448 tm_mon -= 12; 449 tm_year += 1; 450 } 451 const auto ti = tz.At(CivilSecond(tm_year + 1900, tm_mon + 1, tm.tm_mday, 452 tm.tm_hour, tm.tm_min, tm.tm_sec)); 453 return tm.tm_isdst == 0 ? ti.post : ti.pre; 454 } 455 456 struct tm ToTM(absl::Time t, absl::TimeZone tz) { 457 struct tm tm = {}; 458 459 const auto ci = tz.At(t); 460 const auto& cs = ci.cs; 461 tm.tm_sec = cs.second(); 462 tm.tm_min = cs.minute(); 463 tm.tm_hour = cs.hour(); 464 tm.tm_mday = cs.day(); 465 tm.tm_mon = cs.month() - 1; 466 467 // Saturates tm.tm_year in cases of over/underflow, accounting for the fact 468 // that tm.tm_year is years since 1900. 469 if (cs.year() < std::numeric_limits<int>::min() + 1900) { 470 tm.tm_year = std::numeric_limits<int>::min(); 471 } else if (cs.year() > std::numeric_limits<int>::max()) { 472 tm.tm_year = std::numeric_limits<int>::max() - 1900; 473 } else { 474 tm.tm_year = static_cast<int>(cs.year() - 1900); 475 } 476 477 switch (GetWeekday(cs)) { 478 case Weekday::sunday: 479 tm.tm_wday = 0; 480 break; 481 case Weekday::monday: 482 tm.tm_wday = 1; 483 break; 484 case Weekday::tuesday: 485 tm.tm_wday = 2; 486 break; 487 case Weekday::wednesday: 488 tm.tm_wday = 3; 489 break; 490 case Weekday::thursday: 491 tm.tm_wday = 4; 492 break; 493 case Weekday::friday: 494 tm.tm_wday = 5; 495 break; 496 case Weekday::saturday: 497 tm.tm_wday = 6; 498 break; 499 } 500 tm.tm_yday = GetYearDay(cs) - 1; 501 tm.tm_isdst = ci.is_dst ? 1 : 0; 502 503 return tm; 504 } 505 506 ABSL_NAMESPACE_END 507 } // namespace absl