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