diff options
Diffstat (limited to 'absl/time/internal/cctz/src/time_zone_libc.cc')
-rw-r--r-- | absl/time/internal/cctz/src/time_zone_libc.cc | 61 |
1 files changed, 32 insertions, 29 deletions
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc index 887dd097..af9f063e 100644 --- a/absl/time/internal/cctz/src/time_zone_libc.cc +++ b/absl/time/internal/cctz/src/time_zone_libc.cc @@ -125,31 +125,30 @@ inline std::tm* local_time(const std::time_t* timep, std::tm* result) { #endif } -// Converts a civil second and "dst" flag into a time_t and UTC offset. +// Converts a civil second and "dst" flag into a time_t and a struct tm. // Returns false if time_t cannot represent the requested civil second. // Caller must have already checked that cs.year() will fit into a tm_year. -bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) { - std::tm tm; - tm.tm_year = static_cast<int>(cs.year() - year_t{1900}); - tm.tm_mon = cs.month() - 1; - tm.tm_mday = cs.day(); - tm.tm_hour = cs.hour(); - tm.tm_min = cs.minute(); - tm.tm_sec = cs.second(); - tm.tm_isdst = is_dst; - *t = std::mktime(&tm); +bool make_time(const civil_second& cs, int is_dst, std::time_t* t, + std::tm* tm) { + tm->tm_year = static_cast<int>(cs.year() - year_t{1900}); + tm->tm_mon = cs.month() - 1; + tm->tm_mday = cs.day(); + tm->tm_hour = cs.hour(); + tm->tm_min = cs.minute(); + tm->tm_sec = cs.second(); + tm->tm_isdst = is_dst; + *t = std::mktime(tm); if (*t == std::time_t{-1}) { std::tm tm2; const std::tm* tmp = local_time(t, &tm2); - if (tmp == nullptr || tmp->tm_year != tm.tm_year || - tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday || - tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min || - tmp->tm_sec != tm.tm_sec) { + if (tmp == nullptr || tmp->tm_year != tm->tm_year || + tmp->tm_mon != tm->tm_mon || tmp->tm_mday != tm->tm_mday || + tmp->tm_hour != tm->tm_hour || tmp->tm_min != tm->tm_min || + tmp->tm_sec != tm->tm_sec) { // A true error (not just one second before the epoch). return false; } } - *off = static_cast<int>(tm_gmtoff(tm)); return true; } @@ -254,33 +253,37 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const { // We probe with "is_dst" values of 0 and 1 to try to distinguish unique // civil seconds from skipped or repeated ones. This is not always possible // however, as the "dst" flag does not change over some offset transitions. - // We are also subject to the vagaries of mktime() implementations. + // We are also subject to the vagaries of mktime() implementations. For + // example, some implementations treat "tm_isdst" as a demand (useless), + // and some as a disambiguator (useful). std::time_t t0, t1; - int offset0, offset1; - if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) { - if (t0 == t1) { + std::tm tm0, tm1; + if (make_time(cs, 0, &t0, &tm0) && make_time(cs, 1, &t1, &tm1)) { + if (tm0.tm_isdst == tm1.tm_isdst) { // The civil time was singular (pre == trans == post). - const time_point<seconds> tp = FromUnixSeconds(t0); + const time_point<seconds> tp = FromUnixSeconds(tm0.tm_isdst ? t1 : t0); return {time_zone::civil_lookup::UNIQUE, tp, tp, tp}; } - if (t0 > t1) { + int offset = tm_gmtoff(tm0); + if (t0 < t1) { // negative DST std::swap(t0, t1); - std::swap(offset0, offset1); + offset = tm_gmtoff(tm1); } - const std::time_t tt = find_trans(t0, t1, offset1); + + const std::time_t tt = find_trans(t1, t0, offset); const time_point<seconds> trans = FromUnixSeconds(tt); - if (offset0 < offset1) { + if (tm0.tm_isdst) { // The civil time did not exist (pre >= trans > post). - const time_point<seconds> pre = FromUnixSeconds(t1); - const time_point<seconds> post = FromUnixSeconds(t0); + const time_point<seconds> pre = FromUnixSeconds(t0); + const time_point<seconds> post = FromUnixSeconds(t1); return {time_zone::civil_lookup::SKIPPED, pre, trans, post}; } // The civil time was ambiguous (pre < trans <= post). - const time_point<seconds> pre = FromUnixSeconds(t0); - const time_point<seconds> post = FromUnixSeconds(t1); + const time_point<seconds> pre = FromUnixSeconds(t1); + const time_point<seconds> post = FromUnixSeconds(t0); return {time_zone::civil_lookup::REPEATED, pre, trans, post}; } |