11cb0ef41Sopenharmony_ci// Copyright 2012 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#include "src/date/date.h" 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_ci#include "src/base/overflowing-math.h" 81cb0ef41Sopenharmony_ci#include "src/numbers/conversions.h" 91cb0ef41Sopenharmony_ci#include "src/objects/objects-inl.h" 101cb0ef41Sopenharmony_ci#ifdef V8_INTL_SUPPORT 111cb0ef41Sopenharmony_ci#include "src/objects/intl-objects.h" 121cb0ef41Sopenharmony_ci#endif 131cb0ef41Sopenharmony_ci#include "src/strings/string-stream.h" 141cb0ef41Sopenharmony_ci 151cb0ef41Sopenharmony_cinamespace v8 { 161cb0ef41Sopenharmony_cinamespace internal { 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_cistatic const int kDaysIn4Years = 4 * 365 + 1; 191cb0ef41Sopenharmony_cistatic const int kDaysIn100Years = 25 * kDaysIn4Years - 1; 201cb0ef41Sopenharmony_cistatic const int kDaysIn400Years = 4 * kDaysIn100Years + 1; 211cb0ef41Sopenharmony_cistatic const int kDays1970to2000 = 30 * 365 + 7; 221cb0ef41Sopenharmony_cistatic const int kDaysOffset = 231cb0ef41Sopenharmony_ci 1000 * kDaysIn400Years + 5 * kDaysIn400Years - kDays1970to2000; 241cb0ef41Sopenharmony_cistatic const int kYearsOffset = 400000; 251cb0ef41Sopenharmony_cistatic const char kDaysInMonths[] = {31, 28, 31, 30, 31, 30, 261cb0ef41Sopenharmony_ci 31, 31, 30, 31, 30, 31}; 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ciDateCache::DateCache() 291cb0ef41Sopenharmony_ci : stamp_(kNullAddress), 301cb0ef41Sopenharmony_ci tz_cache_( 311cb0ef41Sopenharmony_ci#ifdef V8_INTL_SUPPORT 321cb0ef41Sopenharmony_ci Intl::CreateTimeZoneCache() 331cb0ef41Sopenharmony_ci#else 341cb0ef41Sopenharmony_ci base::OS::CreateTimezoneCache() 351cb0ef41Sopenharmony_ci#endif 361cb0ef41Sopenharmony_ci ) { 371cb0ef41Sopenharmony_ci ResetDateCache(base::TimezoneCache::TimeZoneDetection::kSkip); 381cb0ef41Sopenharmony_ci} 391cb0ef41Sopenharmony_ci 401cb0ef41Sopenharmony_civoid DateCache::ResetDateCache( 411cb0ef41Sopenharmony_ci base::TimezoneCache::TimeZoneDetection time_zone_detection) { 421cb0ef41Sopenharmony_ci if (stamp_.value() >= Smi::kMaxValue) { 431cb0ef41Sopenharmony_ci stamp_ = Smi::zero(); 441cb0ef41Sopenharmony_ci } else { 451cb0ef41Sopenharmony_ci stamp_ = Smi::FromInt(stamp_.value() + 1); 461cb0ef41Sopenharmony_ci } 471cb0ef41Sopenharmony_ci DCHECK(stamp_ != Smi::FromInt(kInvalidStamp)); 481cb0ef41Sopenharmony_ci for (int i = 0; i < kDSTSize; ++i) { 491cb0ef41Sopenharmony_ci ClearSegment(&dst_[i]); 501cb0ef41Sopenharmony_ci } 511cb0ef41Sopenharmony_ci dst_usage_counter_ = 0; 521cb0ef41Sopenharmony_ci before_ = &dst_[0]; 531cb0ef41Sopenharmony_ci after_ = &dst_[1]; 541cb0ef41Sopenharmony_ci ymd_valid_ = false; 551cb0ef41Sopenharmony_ci#ifdef V8_INTL_SUPPORT 561cb0ef41Sopenharmony_ci if (!FLAG_icu_timezone_data) { 571cb0ef41Sopenharmony_ci#endif 581cb0ef41Sopenharmony_ci local_offset_ms_ = kInvalidLocalOffsetInMs; 591cb0ef41Sopenharmony_ci#ifdef V8_INTL_SUPPORT 601cb0ef41Sopenharmony_ci } 611cb0ef41Sopenharmony_ci#endif 621cb0ef41Sopenharmony_ci tz_cache_->Clear(time_zone_detection); 631cb0ef41Sopenharmony_ci tz_name_ = nullptr; 641cb0ef41Sopenharmony_ci dst_tz_name_ = nullptr; 651cb0ef41Sopenharmony_ci} 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci// ECMA 262 - ES#sec-timeclip TimeClip (time) 681cb0ef41Sopenharmony_cidouble DateCache::TimeClip(double time) { 691cb0ef41Sopenharmony_ci if (-kMaxTimeInMs <= time && time <= kMaxTimeInMs) { 701cb0ef41Sopenharmony_ci return DoubleToInteger(time); 711cb0ef41Sopenharmony_ci } 721cb0ef41Sopenharmony_ci return std::numeric_limits<double>::quiet_NaN(); 731cb0ef41Sopenharmony_ci} 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_civoid DateCache::ClearSegment(DST* segment) { 761cb0ef41Sopenharmony_ci segment->start_sec = kMaxEpochTimeInSec; 771cb0ef41Sopenharmony_ci segment->end_sec = -kMaxEpochTimeInSec; 781cb0ef41Sopenharmony_ci segment->offset_ms = 0; 791cb0ef41Sopenharmony_ci segment->last_used = 0; 801cb0ef41Sopenharmony_ci} 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_civoid DateCache::YearMonthDayFromDays(int days, int* year, int* month, 831cb0ef41Sopenharmony_ci int* day) { 841cb0ef41Sopenharmony_ci if (ymd_valid_) { 851cb0ef41Sopenharmony_ci // Check conservatively if the given 'days' has 861cb0ef41Sopenharmony_ci // the same year and month as the cached 'days'. 871cb0ef41Sopenharmony_ci int new_day = ymd_day_ + (days - ymd_days_); 881cb0ef41Sopenharmony_ci if (new_day >= 1 && new_day <= 28) { 891cb0ef41Sopenharmony_ci ymd_day_ = new_day; 901cb0ef41Sopenharmony_ci ymd_days_ = days; 911cb0ef41Sopenharmony_ci *year = ymd_year_; 921cb0ef41Sopenharmony_ci *month = ymd_month_; 931cb0ef41Sopenharmony_ci *day = new_day; 941cb0ef41Sopenharmony_ci return; 951cb0ef41Sopenharmony_ci } 961cb0ef41Sopenharmony_ci } 971cb0ef41Sopenharmony_ci int save_days = days; 981cb0ef41Sopenharmony_ci 991cb0ef41Sopenharmony_ci days += kDaysOffset; 1001cb0ef41Sopenharmony_ci *year = 400 * (days / kDaysIn400Years) - kYearsOffset; 1011cb0ef41Sopenharmony_ci days %= kDaysIn400Years; 1021cb0ef41Sopenharmony_ci 1031cb0ef41Sopenharmony_ci DCHECK_EQ(save_days, DaysFromYearMonth(*year, 0) + days); 1041cb0ef41Sopenharmony_ci 1051cb0ef41Sopenharmony_ci days--; 1061cb0ef41Sopenharmony_ci int yd1 = days / kDaysIn100Years; 1071cb0ef41Sopenharmony_ci days %= kDaysIn100Years; 1081cb0ef41Sopenharmony_ci *year += 100 * yd1; 1091cb0ef41Sopenharmony_ci 1101cb0ef41Sopenharmony_ci days++; 1111cb0ef41Sopenharmony_ci int yd2 = days / kDaysIn4Years; 1121cb0ef41Sopenharmony_ci days %= kDaysIn4Years; 1131cb0ef41Sopenharmony_ci *year += 4 * yd2; 1141cb0ef41Sopenharmony_ci 1151cb0ef41Sopenharmony_ci days--; 1161cb0ef41Sopenharmony_ci int yd3 = days / 365; 1171cb0ef41Sopenharmony_ci days %= 365; 1181cb0ef41Sopenharmony_ci *year += yd3; 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci bool is_leap = (!yd1 || yd2) && !yd3; 1211cb0ef41Sopenharmony_ci 1221cb0ef41Sopenharmony_ci DCHECK_GE(days, -1); 1231cb0ef41Sopenharmony_ci DCHECK(is_leap || (days >= 0)); 1241cb0ef41Sopenharmony_ci DCHECK((days < 365) || (is_leap && (days < 366))); 1251cb0ef41Sopenharmony_ci DCHECK(is_leap == ((*year % 4 == 0) && (*year % 100 || (*year % 400 == 0)))); 1261cb0ef41Sopenharmony_ci DCHECK(is_leap || ((DaysFromYearMonth(*year, 0) + days) == save_days)); 1271cb0ef41Sopenharmony_ci DCHECK(!is_leap || ((DaysFromYearMonth(*year, 0) + days + 1) == save_days)); 1281cb0ef41Sopenharmony_ci 1291cb0ef41Sopenharmony_ci days += is_leap; 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci // Check if the date is after February. 1321cb0ef41Sopenharmony_ci if (days >= 31 + 28 + (is_leap ? 1 : 0)) { 1331cb0ef41Sopenharmony_ci days -= 31 + 28 + (is_leap ? 1 : 0); 1341cb0ef41Sopenharmony_ci // Find the date starting from March. 1351cb0ef41Sopenharmony_ci for (int i = 2; i < 12; i++) { 1361cb0ef41Sopenharmony_ci if (days < kDaysInMonths[i]) { 1371cb0ef41Sopenharmony_ci *month = i; 1381cb0ef41Sopenharmony_ci *day = days + 1; 1391cb0ef41Sopenharmony_ci break; 1401cb0ef41Sopenharmony_ci } 1411cb0ef41Sopenharmony_ci days -= kDaysInMonths[i]; 1421cb0ef41Sopenharmony_ci } 1431cb0ef41Sopenharmony_ci } else { 1441cb0ef41Sopenharmony_ci // Check January and February. 1451cb0ef41Sopenharmony_ci if (days < 31) { 1461cb0ef41Sopenharmony_ci *month = 0; 1471cb0ef41Sopenharmony_ci *day = days + 1; 1481cb0ef41Sopenharmony_ci } else { 1491cb0ef41Sopenharmony_ci *month = 1; 1501cb0ef41Sopenharmony_ci *day = days - 31 + 1; 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci } 1531cb0ef41Sopenharmony_ci DCHECK(DaysFromYearMonth(*year, *month) + *day - 1 == save_days); 1541cb0ef41Sopenharmony_ci ymd_valid_ = true; 1551cb0ef41Sopenharmony_ci ymd_year_ = *year; 1561cb0ef41Sopenharmony_ci ymd_month_ = *month; 1571cb0ef41Sopenharmony_ci ymd_day_ = *day; 1581cb0ef41Sopenharmony_ci ymd_days_ = save_days; 1591cb0ef41Sopenharmony_ci} 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ciint DateCache::DaysFromYearMonth(int year, int month) { 1621cb0ef41Sopenharmony_ci static const int day_from_month[] = {0, 31, 59, 90, 120, 151, 1631cb0ef41Sopenharmony_ci 181, 212, 243, 273, 304, 334}; 1641cb0ef41Sopenharmony_ci static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152, 1651cb0ef41Sopenharmony_ci 182, 213, 244, 274, 305, 335}; 1661cb0ef41Sopenharmony_ci 1671cb0ef41Sopenharmony_ci year += month / 12; 1681cb0ef41Sopenharmony_ci month %= 12; 1691cb0ef41Sopenharmony_ci if (month < 0) { 1701cb0ef41Sopenharmony_ci year--; 1711cb0ef41Sopenharmony_ci month += 12; 1721cb0ef41Sopenharmony_ci } 1731cb0ef41Sopenharmony_ci 1741cb0ef41Sopenharmony_ci DCHECK_GE(month, 0); 1751cb0ef41Sopenharmony_ci DCHECK_LT(month, 12); 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci // year_delta is an arbitrary number such that: 1781cb0ef41Sopenharmony_ci // a) year_delta = -1 (mod 400) 1791cb0ef41Sopenharmony_ci // b) year + year_delta > 0 for years in the range defined by 1801cb0ef41Sopenharmony_ci // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of 1811cb0ef41Sopenharmony_ci // Jan 1 1970. This is required so that we don't run into integer 1821cb0ef41Sopenharmony_ci // division of negative numbers. 1831cb0ef41Sopenharmony_ci // c) there shouldn't be an overflow for 32-bit integers in the following 1841cb0ef41Sopenharmony_ci // operations. 1851cb0ef41Sopenharmony_ci static const int year_delta = 399999; 1861cb0ef41Sopenharmony_ci static const int base_day = 1871cb0ef41Sopenharmony_ci 365 * (1970 + year_delta) + (1970 + year_delta) / 4 - 1881cb0ef41Sopenharmony_ci (1970 + year_delta) / 100 + (1970 + year_delta) / 400; 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci int year1 = year + year_delta; 1911cb0ef41Sopenharmony_ci int day_from_year = 1921cb0ef41Sopenharmony_ci 365 * year1 + year1 / 4 - year1 / 100 + year1 / 400 - base_day; 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) { 1951cb0ef41Sopenharmony_ci return day_from_year + day_from_month[month]; 1961cb0ef41Sopenharmony_ci } 1971cb0ef41Sopenharmony_ci return day_from_year + day_from_month_leap[month]; 1981cb0ef41Sopenharmony_ci} 1991cb0ef41Sopenharmony_ci 2001cb0ef41Sopenharmony_civoid DateCache::BreakDownTime(int64_t time_ms, int* year, int* month, int* day, 2011cb0ef41Sopenharmony_ci int* weekday, int* hour, int* min, int* sec, 2021cb0ef41Sopenharmony_ci int* ms) { 2031cb0ef41Sopenharmony_ci int const days = DaysFromTime(time_ms); 2041cb0ef41Sopenharmony_ci int const time_in_day_ms = TimeInDay(time_ms, days); 2051cb0ef41Sopenharmony_ci YearMonthDayFromDays(days, year, month, day); 2061cb0ef41Sopenharmony_ci *weekday = Weekday(days); 2071cb0ef41Sopenharmony_ci *hour = time_in_day_ms / (60 * 60 * 1000); 2081cb0ef41Sopenharmony_ci *min = (time_in_day_ms / (60 * 1000)) % 60; 2091cb0ef41Sopenharmony_ci *sec = (time_in_day_ms / 1000) % 60; 2101cb0ef41Sopenharmony_ci *ms = time_in_day_ms % 1000; 2111cb0ef41Sopenharmony_ci} 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci// Implements LocalTimeZonedjustment(t, isUTC) 2141cb0ef41Sopenharmony_ci// ECMA 262 - ES#sec-local-time-zone-adjustment 2151cb0ef41Sopenharmony_ciint DateCache::GetLocalOffsetFromOS(int64_t time_ms, bool is_utc) { 2161cb0ef41Sopenharmony_ci double offset; 2171cb0ef41Sopenharmony_ci#ifdef V8_INTL_SUPPORT 2181cb0ef41Sopenharmony_ci if (FLAG_icu_timezone_data) { 2191cb0ef41Sopenharmony_ci offset = tz_cache_->LocalTimeOffset(static_cast<double>(time_ms), is_utc); 2201cb0ef41Sopenharmony_ci } else { 2211cb0ef41Sopenharmony_ci#endif 2221cb0ef41Sopenharmony_ci // When ICU timezone data is not used, we need to compute the timezone 2231cb0ef41Sopenharmony_ci // offset for a given local time. 2241cb0ef41Sopenharmony_ci // 2251cb0ef41Sopenharmony_ci // The following shows that using DST for (t - LocalTZA - hour) produces 2261cb0ef41Sopenharmony_ci // correct conversion where LocalTZA is the timezone offset in winter (no 2271cb0ef41Sopenharmony_ci // DST) and the timezone offset is assumed to have no historical change. 2281cb0ef41Sopenharmony_ci // Note that it does not work for the past and the future if LocalTZA (no 2291cb0ef41Sopenharmony_ci // DST) is different from the current LocalTZA (no DST). For instance, 2301cb0ef41Sopenharmony_ci // this will break for Europe/Moscow in 2012 ~ 2013 because LocalTZA was 2311cb0ef41Sopenharmony_ci // 4h instead of the current 3h (as of 2018). 2321cb0ef41Sopenharmony_ci // 2331cb0ef41Sopenharmony_ci // Consider transition to DST at local time L1. 2341cb0ef41Sopenharmony_ci // Let L0 = L1 - hour, L2 = L1 + hour, 2351cb0ef41Sopenharmony_ci // U1 = UTC time that corresponds to L1, 2361cb0ef41Sopenharmony_ci // U0 = U1 - hour. 2371cb0ef41Sopenharmony_ci // Transitioning to DST moves local clock one hour forward L1 => L2, so 2381cb0ef41Sopenharmony_ci // U0 = UTC time that corresponds to L0 = L0 - LocalTZA, 2391cb0ef41Sopenharmony_ci // U1 = UTC time that corresponds to L1 = L1 - LocalTZA, 2401cb0ef41Sopenharmony_ci // U1 = UTC time that corresponds to L2 = L2 - LocalTZA - hour. 2411cb0ef41Sopenharmony_ci // Note that DST(U0 - hour) = 0, DST(U0) = 0, DST(U1) = 1. 2421cb0ef41Sopenharmony_ci // U0 = L0 - LocalTZA - DST(L0 - LocalTZA - hour), 2431cb0ef41Sopenharmony_ci // U1 = L1 - LocalTZA - DST(L1 - LocalTZA - hour), 2441cb0ef41Sopenharmony_ci // U1 = L2 - LocalTZA - DST(L2 - LocalTZA - hour). 2451cb0ef41Sopenharmony_ci // 2461cb0ef41Sopenharmony_ci // Consider transition from DST at local time L1. 2471cb0ef41Sopenharmony_ci // Let L0 = L1 - hour, 2481cb0ef41Sopenharmony_ci // U1 = UTC time that corresponds to L1, 2491cb0ef41Sopenharmony_ci // U0 = U1 - hour, U2 = U1 + hour. 2501cb0ef41Sopenharmony_ci // Transitioning from DST moves local clock one hour back L1 => L0, so 2511cb0ef41Sopenharmony_ci // U0 = UTC time that corresponds to L0 (before transition) 2521cb0ef41Sopenharmony_ci // = L0 - LocalTZA - hour. 2531cb0ef41Sopenharmony_ci // U1 = UTC time that corresponds to L0 (after transition) 2541cb0ef41Sopenharmony_ci // = L0 - LocalTZA = L1 - LocalTZA - hour 2551cb0ef41Sopenharmony_ci // U2 = UTC time that corresponds to L1 = L1 - LocalTZA. 2561cb0ef41Sopenharmony_ci // Note that DST(U0) = 1, DST(U1) = 0, DST(U2) = 0. 2571cb0ef41Sopenharmony_ci // U0 = L0 - LocalTZA - DST(L0 - LocalTZA - hour) = L0 - LocalTZA - DST(U0). 2581cb0ef41Sopenharmony_ci // U2 = L1 - LocalTZA - DST(L1 - LocalTZA - hour) = L1 - LocalTZA - DST(U1). 2591cb0ef41Sopenharmony_ci // It is impossible to get U1 from local time. 2601cb0ef41Sopenharmony_ci if (local_offset_ms_ == kInvalidLocalOffsetInMs) { 2611cb0ef41Sopenharmony_ci // This gets the constant LocalTZA (arguments are ignored). 2621cb0ef41Sopenharmony_ci local_offset_ms_ = 2631cb0ef41Sopenharmony_ci tz_cache_->LocalTimeOffset(static_cast<double>(time_ms), is_utc); 2641cb0ef41Sopenharmony_ci } 2651cb0ef41Sopenharmony_ci offset = local_offset_ms_; 2661cb0ef41Sopenharmony_ci if (!is_utc) { 2671cb0ef41Sopenharmony_ci const int kMsPerHour = 3600 * 1000; 2681cb0ef41Sopenharmony_ci time_ms -= (offset + kMsPerHour); 2691cb0ef41Sopenharmony_ci } 2701cb0ef41Sopenharmony_ci offset += DaylightSavingsOffsetInMs(time_ms); 2711cb0ef41Sopenharmony_ci#ifdef V8_INTL_SUPPORT 2721cb0ef41Sopenharmony_ci } 2731cb0ef41Sopenharmony_ci#endif 2741cb0ef41Sopenharmony_ci DCHECK_LT(offset, kInvalidLocalOffsetInMs); 2751cb0ef41Sopenharmony_ci return static_cast<int>(offset); 2761cb0ef41Sopenharmony_ci} 2771cb0ef41Sopenharmony_ci 2781cb0ef41Sopenharmony_civoid DateCache::ExtendTheAfterSegment(int time_sec, int offset_ms) { 2791cb0ef41Sopenharmony_ci if (after_->offset_ms == offset_ms && 2801cb0ef41Sopenharmony_ci after_->start_sec - kDefaultDSTDeltaInSec <= time_sec && 2811cb0ef41Sopenharmony_ci time_sec <= after_->end_sec) { 2821cb0ef41Sopenharmony_ci // Extend the after_ segment. 2831cb0ef41Sopenharmony_ci after_->start_sec = time_sec; 2841cb0ef41Sopenharmony_ci } else { 2851cb0ef41Sopenharmony_ci // The after_ segment is either invalid or starts too late. 2861cb0ef41Sopenharmony_ci if (!InvalidSegment(after_)) { 2871cb0ef41Sopenharmony_ci // If the after_ segment is valid, replace it with a new segment. 2881cb0ef41Sopenharmony_ci after_ = LeastRecentlyUsedDST(before_); 2891cb0ef41Sopenharmony_ci } 2901cb0ef41Sopenharmony_ci after_->start_sec = time_sec; 2911cb0ef41Sopenharmony_ci after_->end_sec = time_sec; 2921cb0ef41Sopenharmony_ci after_->offset_ms = offset_ms; 2931cb0ef41Sopenharmony_ci after_->last_used = ++dst_usage_counter_; 2941cb0ef41Sopenharmony_ci } 2951cb0ef41Sopenharmony_ci} 2961cb0ef41Sopenharmony_ci 2971cb0ef41Sopenharmony_ciint DateCache::DaylightSavingsOffsetInMs(int64_t time_ms) { 2981cb0ef41Sopenharmony_ci int time_sec = (time_ms >= 0 && time_ms <= kMaxEpochTimeInMs) 2991cb0ef41Sopenharmony_ci ? static_cast<int>(time_ms / 1000) 3001cb0ef41Sopenharmony_ci : static_cast<int>(EquivalentTime(time_ms) / 1000); 3011cb0ef41Sopenharmony_ci 3021cb0ef41Sopenharmony_ci // Invalidate cache if the usage counter is close to overflow. 3031cb0ef41Sopenharmony_ci // Note that dst_usage_counter is incremented less than ten times 3041cb0ef41Sopenharmony_ci // in this function. 3051cb0ef41Sopenharmony_ci if (dst_usage_counter_ >= kMaxInt - 10) { 3061cb0ef41Sopenharmony_ci dst_usage_counter_ = 0; 3071cb0ef41Sopenharmony_ci for (int i = 0; i < kDSTSize; ++i) { 3081cb0ef41Sopenharmony_ci ClearSegment(&dst_[i]); 3091cb0ef41Sopenharmony_ci } 3101cb0ef41Sopenharmony_ci } 3111cb0ef41Sopenharmony_ci 3121cb0ef41Sopenharmony_ci // Optimistic fast check. 3131cb0ef41Sopenharmony_ci if (before_->start_sec <= time_sec && time_sec <= before_->end_sec) { 3141cb0ef41Sopenharmony_ci // Cache hit. 3151cb0ef41Sopenharmony_ci before_->last_used = ++dst_usage_counter_; 3161cb0ef41Sopenharmony_ci return before_->offset_ms; 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci 3191cb0ef41Sopenharmony_ci ProbeDST(time_sec); 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ci DCHECK(InvalidSegment(before_) || before_->start_sec <= time_sec); 3221cb0ef41Sopenharmony_ci DCHECK(InvalidSegment(after_) || time_sec < after_->start_sec); 3231cb0ef41Sopenharmony_ci 3241cb0ef41Sopenharmony_ci if (InvalidSegment(before_)) { 3251cb0ef41Sopenharmony_ci // Cache miss. 3261cb0ef41Sopenharmony_ci before_->start_sec = time_sec; 3271cb0ef41Sopenharmony_ci before_->end_sec = time_sec; 3281cb0ef41Sopenharmony_ci before_->offset_ms = GetDaylightSavingsOffsetFromOS(time_sec); 3291cb0ef41Sopenharmony_ci before_->last_used = ++dst_usage_counter_; 3301cb0ef41Sopenharmony_ci return before_->offset_ms; 3311cb0ef41Sopenharmony_ci } 3321cb0ef41Sopenharmony_ci 3331cb0ef41Sopenharmony_ci if (time_sec <= before_->end_sec) { 3341cb0ef41Sopenharmony_ci // Cache hit. 3351cb0ef41Sopenharmony_ci before_->last_used = ++dst_usage_counter_; 3361cb0ef41Sopenharmony_ci return before_->offset_ms; 3371cb0ef41Sopenharmony_ci } 3381cb0ef41Sopenharmony_ci 3391cb0ef41Sopenharmony_ci if (time_sec - kDefaultDSTDeltaInSec > before_->end_sec) { 3401cb0ef41Sopenharmony_ci // If the before_ segment ends too early, then just 3411cb0ef41Sopenharmony_ci // query for the offset of the time_sec 3421cb0ef41Sopenharmony_ci int offset_ms = GetDaylightSavingsOffsetFromOS(time_sec); 3431cb0ef41Sopenharmony_ci ExtendTheAfterSegment(time_sec, offset_ms); 3441cb0ef41Sopenharmony_ci // This swap helps the optimistic fast check in subsequent invocations. 3451cb0ef41Sopenharmony_ci DST* temp = before_; 3461cb0ef41Sopenharmony_ci before_ = after_; 3471cb0ef41Sopenharmony_ci after_ = temp; 3481cb0ef41Sopenharmony_ci return offset_ms; 3491cb0ef41Sopenharmony_ci } 3501cb0ef41Sopenharmony_ci 3511cb0ef41Sopenharmony_ci // Now the time_sec is between 3521cb0ef41Sopenharmony_ci // before_->end_sec and before_->end_sec + default DST delta. 3531cb0ef41Sopenharmony_ci // Update the usage counter of before_ since it is going to be used. 3541cb0ef41Sopenharmony_ci before_->last_used = ++dst_usage_counter_; 3551cb0ef41Sopenharmony_ci 3561cb0ef41Sopenharmony_ci // Check if after_ segment is invalid or starts too late. 3571cb0ef41Sopenharmony_ci // Note that start_sec of invalid segments is kMaxEpochTimeInSec. 3581cb0ef41Sopenharmony_ci int new_after_start_sec = 3591cb0ef41Sopenharmony_ci before_->end_sec < kMaxEpochTimeInSec - kDefaultDSTDeltaInSec 3601cb0ef41Sopenharmony_ci ? before_->end_sec + kDefaultDSTDeltaInSec 3611cb0ef41Sopenharmony_ci : kMaxEpochTimeInSec; 3621cb0ef41Sopenharmony_ci if (new_after_start_sec <= after_->start_sec) { 3631cb0ef41Sopenharmony_ci int new_offset_ms = GetDaylightSavingsOffsetFromOS(new_after_start_sec); 3641cb0ef41Sopenharmony_ci ExtendTheAfterSegment(new_after_start_sec, new_offset_ms); 3651cb0ef41Sopenharmony_ci } else { 3661cb0ef41Sopenharmony_ci DCHECK(!InvalidSegment(after_)); 3671cb0ef41Sopenharmony_ci // Update the usage counter of after_ since it is going to be used. 3681cb0ef41Sopenharmony_ci after_->last_used = ++dst_usage_counter_; 3691cb0ef41Sopenharmony_ci } 3701cb0ef41Sopenharmony_ci 3711cb0ef41Sopenharmony_ci // Now the time_sec is between before_->end_sec and after_->start_sec. 3721cb0ef41Sopenharmony_ci // Only one daylight savings offset change can occur in this interval. 3731cb0ef41Sopenharmony_ci 3741cb0ef41Sopenharmony_ci if (before_->offset_ms == after_->offset_ms) { 3751cb0ef41Sopenharmony_ci // Merge two segments if they have the same offset. 3761cb0ef41Sopenharmony_ci before_->end_sec = after_->end_sec; 3771cb0ef41Sopenharmony_ci ClearSegment(after_); 3781cb0ef41Sopenharmony_ci return before_->offset_ms; 3791cb0ef41Sopenharmony_ci } 3801cb0ef41Sopenharmony_ci 3811cb0ef41Sopenharmony_ci // Binary search for daylight savings offset change point, 3821cb0ef41Sopenharmony_ci // but give up if we don't find it in five iterations. 3831cb0ef41Sopenharmony_ci for (int i = 4; i >= 0; --i) { 3841cb0ef41Sopenharmony_ci int delta = after_->start_sec - before_->end_sec; 3851cb0ef41Sopenharmony_ci int middle_sec = (i == 0) ? time_sec : before_->end_sec + delta / 2; 3861cb0ef41Sopenharmony_ci int offset_ms = GetDaylightSavingsOffsetFromOS(middle_sec); 3871cb0ef41Sopenharmony_ci if (before_->offset_ms == offset_ms) { 3881cb0ef41Sopenharmony_ci before_->end_sec = middle_sec; 3891cb0ef41Sopenharmony_ci if (time_sec <= before_->end_sec) { 3901cb0ef41Sopenharmony_ci return offset_ms; 3911cb0ef41Sopenharmony_ci } 3921cb0ef41Sopenharmony_ci } else { 3931cb0ef41Sopenharmony_ci DCHECK(after_->offset_ms == offset_ms); 3941cb0ef41Sopenharmony_ci after_->start_sec = middle_sec; 3951cb0ef41Sopenharmony_ci if (time_sec >= after_->start_sec) { 3961cb0ef41Sopenharmony_ci // This swap helps the optimistic fast check in subsequent invocations. 3971cb0ef41Sopenharmony_ci DST* temp = before_; 3981cb0ef41Sopenharmony_ci before_ = after_; 3991cb0ef41Sopenharmony_ci after_ = temp; 4001cb0ef41Sopenharmony_ci return offset_ms; 4011cb0ef41Sopenharmony_ci } 4021cb0ef41Sopenharmony_ci } 4031cb0ef41Sopenharmony_ci } 4041cb0ef41Sopenharmony_ci return 0; 4051cb0ef41Sopenharmony_ci} 4061cb0ef41Sopenharmony_ci 4071cb0ef41Sopenharmony_civoid DateCache::ProbeDST(int time_sec) { 4081cb0ef41Sopenharmony_ci DST* before = nullptr; 4091cb0ef41Sopenharmony_ci DST* after = nullptr; 4101cb0ef41Sopenharmony_ci DCHECK(before_ != after_); 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_ci for (int i = 0; i < kDSTSize; ++i) { 4131cb0ef41Sopenharmony_ci if (dst_[i].start_sec <= time_sec) { 4141cb0ef41Sopenharmony_ci if (before == nullptr || before->start_sec < dst_[i].start_sec) { 4151cb0ef41Sopenharmony_ci before = &dst_[i]; 4161cb0ef41Sopenharmony_ci } 4171cb0ef41Sopenharmony_ci } else if (time_sec < dst_[i].end_sec) { 4181cb0ef41Sopenharmony_ci if (after == nullptr || after->end_sec > dst_[i].end_sec) { 4191cb0ef41Sopenharmony_ci after = &dst_[i]; 4201cb0ef41Sopenharmony_ci } 4211cb0ef41Sopenharmony_ci } 4221cb0ef41Sopenharmony_ci } 4231cb0ef41Sopenharmony_ci 4241cb0ef41Sopenharmony_ci // If before or after segments were not found, 4251cb0ef41Sopenharmony_ci // then set them to any invalid segment. 4261cb0ef41Sopenharmony_ci if (before == nullptr) { 4271cb0ef41Sopenharmony_ci before = InvalidSegment(before_) ? before_ : LeastRecentlyUsedDST(after); 4281cb0ef41Sopenharmony_ci } 4291cb0ef41Sopenharmony_ci if (after == nullptr) { 4301cb0ef41Sopenharmony_ci after = InvalidSegment(after_) && before != after_ 4311cb0ef41Sopenharmony_ci ? after_ 4321cb0ef41Sopenharmony_ci : LeastRecentlyUsedDST(before); 4331cb0ef41Sopenharmony_ci } 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(before); 4361cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(after); 4371cb0ef41Sopenharmony_ci DCHECK(before != after); 4381cb0ef41Sopenharmony_ci DCHECK(InvalidSegment(before) || before->start_sec <= time_sec); 4391cb0ef41Sopenharmony_ci DCHECK(InvalidSegment(after) || time_sec < after->start_sec); 4401cb0ef41Sopenharmony_ci DCHECK(InvalidSegment(before) || InvalidSegment(after) || 4411cb0ef41Sopenharmony_ci before->end_sec < after->start_sec); 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci before_ = before; 4441cb0ef41Sopenharmony_ci after_ = after; 4451cb0ef41Sopenharmony_ci} 4461cb0ef41Sopenharmony_ci 4471cb0ef41Sopenharmony_ciDateCache::DST* DateCache::LeastRecentlyUsedDST(DST* skip) { 4481cb0ef41Sopenharmony_ci DST* result = nullptr; 4491cb0ef41Sopenharmony_ci for (int i = 0; i < kDSTSize; ++i) { 4501cb0ef41Sopenharmony_ci if (&dst_[i] == skip) continue; 4511cb0ef41Sopenharmony_ci if (result == nullptr || result->last_used > dst_[i].last_used) { 4521cb0ef41Sopenharmony_ci result = &dst_[i]; 4531cb0ef41Sopenharmony_ci } 4541cb0ef41Sopenharmony_ci } 4551cb0ef41Sopenharmony_ci ClearSegment(result); 4561cb0ef41Sopenharmony_ci return result; 4571cb0ef41Sopenharmony_ci} 4581cb0ef41Sopenharmony_ci 4591cb0ef41Sopenharmony_cinamespace { 4601cb0ef41Sopenharmony_ci 4611cb0ef41Sopenharmony_ci// ES6 section 20.3.1.1 Time Values and Time Range 4621cb0ef41Sopenharmony_ciconst double kMinYear = -1000000.0; 4631cb0ef41Sopenharmony_ciconst double kMaxYear = -kMinYear; 4641cb0ef41Sopenharmony_ciconst double kMinMonth = -10000000.0; 4651cb0ef41Sopenharmony_ciconst double kMaxMonth = -kMinMonth; 4661cb0ef41Sopenharmony_ci 4671cb0ef41Sopenharmony_ciconst double kMsPerDay = 86400000.0; 4681cb0ef41Sopenharmony_ci 4691cb0ef41Sopenharmony_ciconst double kMsPerSecond = 1000.0; 4701cb0ef41Sopenharmony_ciconst double kMsPerMinute = 60000.0; 4711cb0ef41Sopenharmony_ciconst double kMsPerHour = 3600000.0; 4721cb0ef41Sopenharmony_ci 4731cb0ef41Sopenharmony_ci} // namespace 4741cb0ef41Sopenharmony_ci 4751cb0ef41Sopenharmony_cidouble MakeDate(double day, double time) { 4761cb0ef41Sopenharmony_ci if (std::isfinite(day) && std::isfinite(time)) { 4771cb0ef41Sopenharmony_ci return time + day * kMsPerDay; 4781cb0ef41Sopenharmony_ci } 4791cb0ef41Sopenharmony_ci return std::numeric_limits<double>::quiet_NaN(); 4801cb0ef41Sopenharmony_ci} 4811cb0ef41Sopenharmony_ci 4821cb0ef41Sopenharmony_cidouble MakeDay(double year, double month, double date) { 4831cb0ef41Sopenharmony_ci if ((kMinYear <= year && year <= kMaxYear) && 4841cb0ef41Sopenharmony_ci (kMinMonth <= month && month <= kMaxMonth) && std::isfinite(date)) { 4851cb0ef41Sopenharmony_ci int y = FastD2I(year); 4861cb0ef41Sopenharmony_ci int m = FastD2I(month); 4871cb0ef41Sopenharmony_ci y += m / 12; 4881cb0ef41Sopenharmony_ci m %= 12; 4891cb0ef41Sopenharmony_ci if (m < 0) { 4901cb0ef41Sopenharmony_ci m += 12; 4911cb0ef41Sopenharmony_ci y -= 1; 4921cb0ef41Sopenharmony_ci } 4931cb0ef41Sopenharmony_ci DCHECK_LE(0, m); 4941cb0ef41Sopenharmony_ci DCHECK_LT(m, 12); 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_ci // kYearDelta is an arbitrary number such that: 4971cb0ef41Sopenharmony_ci // a) kYearDelta = -1 (mod 400) 4981cb0ef41Sopenharmony_ci // b) year + kYearDelta > 0 for years in the range defined by 4991cb0ef41Sopenharmony_ci // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of 5001cb0ef41Sopenharmony_ci // Jan 1 1970. This is required so that we don't run into integer 5011cb0ef41Sopenharmony_ci // division of negative numbers. 5021cb0ef41Sopenharmony_ci // c) there shouldn't be an overflow for 32-bit integers in the following 5031cb0ef41Sopenharmony_ci // operations. 5041cb0ef41Sopenharmony_ci static const int kYearDelta = 399999; 5051cb0ef41Sopenharmony_ci static const int kBaseDay = 5061cb0ef41Sopenharmony_ci 365 * (1970 + kYearDelta) + (1970 + kYearDelta) / 4 - 5071cb0ef41Sopenharmony_ci (1970 + kYearDelta) / 100 + (1970 + kYearDelta) / 400; 5081cb0ef41Sopenharmony_ci int day_from_year = 365 * (y + kYearDelta) + (y + kYearDelta) / 4 - 5091cb0ef41Sopenharmony_ci (y + kYearDelta) / 100 + (y + kYearDelta) / 400 - 5101cb0ef41Sopenharmony_ci kBaseDay; 5111cb0ef41Sopenharmony_ci if ((y % 4 != 0) || (y % 100 == 0 && y % 400 != 0)) { 5121cb0ef41Sopenharmony_ci static const int kDayFromMonth[] = {0, 31, 59, 90, 120, 151, 5131cb0ef41Sopenharmony_ci 181, 212, 243, 273, 304, 334}; 5141cb0ef41Sopenharmony_ci day_from_year += kDayFromMonth[m]; 5151cb0ef41Sopenharmony_ci } else { 5161cb0ef41Sopenharmony_ci static const int kDayFromMonth[] = {0, 31, 60, 91, 121, 152, 5171cb0ef41Sopenharmony_ci 182, 213, 244, 274, 305, 335}; 5181cb0ef41Sopenharmony_ci day_from_year += kDayFromMonth[m]; 5191cb0ef41Sopenharmony_ci } 5201cb0ef41Sopenharmony_ci return static_cast<double>(day_from_year - 1) + DoubleToInteger(date); 5211cb0ef41Sopenharmony_ci } 5221cb0ef41Sopenharmony_ci return std::numeric_limits<double>::quiet_NaN(); 5231cb0ef41Sopenharmony_ci} 5241cb0ef41Sopenharmony_ci 5251cb0ef41Sopenharmony_cidouble MakeTime(double hour, double min, double sec, double ms) { 5261cb0ef41Sopenharmony_ci if (std::isfinite(hour) && std::isfinite(min) && std::isfinite(sec) && 5271cb0ef41Sopenharmony_ci std::isfinite(ms)) { 5281cb0ef41Sopenharmony_ci double const h = DoubleToInteger(hour); 5291cb0ef41Sopenharmony_ci double const m = DoubleToInteger(min); 5301cb0ef41Sopenharmony_ci double const s = DoubleToInteger(sec); 5311cb0ef41Sopenharmony_ci double const milli = DoubleToInteger(ms); 5321cb0ef41Sopenharmony_ci return h * kMsPerHour + m * kMsPerMinute + s * kMsPerSecond + milli; 5331cb0ef41Sopenharmony_ci } 5341cb0ef41Sopenharmony_ci return std::numeric_limits<double>::quiet_NaN(); 5351cb0ef41Sopenharmony_ci} 5361cb0ef41Sopenharmony_ci 5371cb0ef41Sopenharmony_cinamespace { 5381cb0ef41Sopenharmony_ci 5391cb0ef41Sopenharmony_ciconst char* kShortWeekDays[] = {"Sun", "Mon", "Tue", "Wed", 5401cb0ef41Sopenharmony_ci "Thu", "Fri", "Sat"}; 5411cb0ef41Sopenharmony_ciconst char* kShortMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 5421cb0ef41Sopenharmony_ci "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 5431cb0ef41Sopenharmony_ci 5441cb0ef41Sopenharmony_citemplate <class... Args> 5451cb0ef41Sopenharmony_ciDateBuffer FormatDate(const char* format, Args... args) { 5461cb0ef41Sopenharmony_ci DateBuffer buffer; 5471cb0ef41Sopenharmony_ci SmallStringOptimizedAllocator<DateBuffer::kInlineSize> allocator(&buffer); 5481cb0ef41Sopenharmony_ci StringStream sstream(&allocator); 5491cb0ef41Sopenharmony_ci sstream.Add(format, args...); 5501cb0ef41Sopenharmony_ci buffer.resize_no_init(sstream.length()); 5511cb0ef41Sopenharmony_ci return buffer; 5521cb0ef41Sopenharmony_ci} 5531cb0ef41Sopenharmony_ci 5541cb0ef41Sopenharmony_ci} // namespace 5551cb0ef41Sopenharmony_ci 5561cb0ef41Sopenharmony_ciDateBuffer ToDateString(double time_val, DateCache* date_cache, 5571cb0ef41Sopenharmony_ci ToDateStringMode mode) { 5581cb0ef41Sopenharmony_ci if (std::isnan(time_val)) { 5591cb0ef41Sopenharmony_ci return FormatDate("Invalid Date"); 5601cb0ef41Sopenharmony_ci } 5611cb0ef41Sopenharmony_ci int64_t time_ms = static_cast<int64_t>(time_val); 5621cb0ef41Sopenharmony_ci int64_t local_time_ms = mode != ToDateStringMode::kUTCDateAndTime 5631cb0ef41Sopenharmony_ci ? date_cache->ToLocal(time_ms) 5641cb0ef41Sopenharmony_ci : time_ms; 5651cb0ef41Sopenharmony_ci int year, month, day, weekday, hour, min, sec, ms; 5661cb0ef41Sopenharmony_ci date_cache->BreakDownTime(local_time_ms, &year, &month, &day, &weekday, &hour, 5671cb0ef41Sopenharmony_ci &min, &sec, &ms); 5681cb0ef41Sopenharmony_ci int timezone_offset = -date_cache->TimezoneOffset(time_ms); 5691cb0ef41Sopenharmony_ci int timezone_hour = std::abs(timezone_offset) / 60; 5701cb0ef41Sopenharmony_ci int timezone_min = std::abs(timezone_offset) % 60; 5711cb0ef41Sopenharmony_ci const char* local_timezone = date_cache->LocalTimezone(time_ms); 5721cb0ef41Sopenharmony_ci switch (mode) { 5731cb0ef41Sopenharmony_ci case ToDateStringMode::kLocalDate: 5741cb0ef41Sopenharmony_ci return FormatDate((year < 0) ? "%s %s %02d %05d" : "%s %s %02d %04d", 5751cb0ef41Sopenharmony_ci kShortWeekDays[weekday], kShortMonths[month], day, 5761cb0ef41Sopenharmony_ci year); 5771cb0ef41Sopenharmony_ci case ToDateStringMode::kLocalTime: 5781cb0ef41Sopenharmony_ci return FormatDate("%02d:%02d:%02d GMT%c%02d%02d (%s)", hour, min, sec, 5791cb0ef41Sopenharmony_ci (timezone_offset < 0) ? '-' : '+', timezone_hour, 5801cb0ef41Sopenharmony_ci timezone_min, local_timezone); 5811cb0ef41Sopenharmony_ci case ToDateStringMode::kLocalDateAndTime: 5821cb0ef41Sopenharmony_ci return FormatDate( 5831cb0ef41Sopenharmony_ci (year < 0) ? "%s %s %02d %05d %02d:%02d:%02d GMT%c%02d%02d (%s)" 5841cb0ef41Sopenharmony_ci : "%s %s %02d %04d %02d:%02d:%02d GMT%c%02d%02d (%s)", 5851cb0ef41Sopenharmony_ci kShortWeekDays[weekday], kShortMonths[month], day, year, hour, min, 5861cb0ef41Sopenharmony_ci sec, (timezone_offset < 0) ? '-' : '+', timezone_hour, timezone_min, 5871cb0ef41Sopenharmony_ci local_timezone); 5881cb0ef41Sopenharmony_ci case ToDateStringMode::kUTCDateAndTime: 5891cb0ef41Sopenharmony_ci return FormatDate((year < 0) ? "%s, %02d %s %05d %02d:%02d:%02d GMT" 5901cb0ef41Sopenharmony_ci : "%s, %02d %s %04d %02d:%02d:%02d GMT", 5911cb0ef41Sopenharmony_ci kShortWeekDays[weekday], day, kShortMonths[month], year, 5921cb0ef41Sopenharmony_ci hour, min, sec); 5931cb0ef41Sopenharmony_ci } 5941cb0ef41Sopenharmony_ci UNREACHABLE(); 5951cb0ef41Sopenharmony_ci} 5961cb0ef41Sopenharmony_ci 5971cb0ef41Sopenharmony_ci} // namespace internal 5981cb0ef41Sopenharmony_ci} // namespace v8 599