13ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch// Copyright 2012 the V8 project authors. All rights reserved.
2b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch// found in the LICENSE file.
4b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
5b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/date.h"
6b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch
7b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/objects.h"
8b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch#include "src/objects-inl.h"
93ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochnamespace v8 {
113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochnamespace internal {
123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const int kDaysIn4Years = 4 * 365 + 1;
153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const int kDays1970to2000 = 30 * 365 + 7;
183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                               kDays1970to2000;
203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const int kYearsOffset = 400000;
213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochstatic const char kDaysInMonths[] =
223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid DateCache::ResetDateCache() {
263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static const int kMaxStamp = Smi::kMaxValue;
27b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  if (stamp_->value() >= kMaxStamp) {
283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    stamp_ = Smi::FromInt(0);
29b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  } else {
30b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    stamp_ = Smi::FromInt(stamp_->value() + 1);
313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
32b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(stamp_ != Smi::FromInt(kInvalidStamp));
333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 0; i < kDSTSize; ++i) {
343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ClearSegment(&dst_[i]);
353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  dst_usage_counter_ = 0;
373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  before_ = &dst_[0];
383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  after_ = &dst_[1];
393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  local_offset_ms_ = kInvalidLocalOffsetInMs;
403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ymd_valid_ = false;
41b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  base::OS::ClearTimezoneCache(tz_cache_);
423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid DateCache::ClearSegment(DST* segment) {
463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  segment->start_sec = kMaxEpochTimeInSec;
473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  segment->end_sec = -kMaxEpochTimeInSec;
483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  segment->offset_ms = 0;
493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  segment->last_used = 0;
503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid DateCache::YearMonthDayFromDays(
543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int days, int* year, int* month, int* day) {
553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (ymd_valid_) {
563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Check conservatively if the given 'days' has
573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // the same year and month as the cached 'days'.
583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int new_day = ymd_day_ + (days - ymd_days_);
593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (new_day >= 1 && new_day <= 28) {
603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ymd_day_ = new_day;
613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ymd_days_ = days;
623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      *year = ymd_year_;
633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      *month = ymd_month_;
643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      *day = new_day;
653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      return;
663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int save_days = days;
693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  days += kDaysOffset;
713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  *year = 400 * (days / kDaysIn400Years) - kYearsOffset;
723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  days %= kDaysIn400Years;
733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
74014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  DCHECK_EQ(save_days, DaysFromYearMonth(*year, 0) + days);
753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  days--;
773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int yd1 = days / kDaysIn100Years;
783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  days %= kDaysIn100Years;
793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  *year += 100 * yd1;
803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  days++;
823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int yd2 = days / kDaysIn4Years;
833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  days %= kDaysIn4Years;
843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  *year += 4 * yd2;
853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  days--;
873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int yd3 = days / 365;
883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  days %= 365;
893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  *year += yd3;
903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  bool is_leap = (!yd1 || yd2) && !yd3;
933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
94b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(days >= -1);
95b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(is_leap || (days >= 0));
96b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK((days < 365) || (is_leap && (days < 366)));
97b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(is_leap == ((*year % 4 == 0) && (*year % 100 || (*year % 400 == 0))));
98b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(is_leap || ((DaysFromYearMonth(*year, 0) + days) == save_days));
99b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(!is_leap || ((DaysFromYearMonth(*year, 0) + days + 1) == save_days));
1003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  days += is_leap;
1023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check if the date is after February.
104014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  if (days >= 31 + 28 + BoolToInt(is_leap)) {
105014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch    days -= 31 + 28 + BoolToInt(is_leap);
1063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Find the date starting from March.
1073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    for (int i = 2; i < 12; i++) {
1083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if (days < kDaysInMonths[i]) {
1093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        *month = i;
1103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        *day = days + 1;
1113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        break;
1123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
1133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      days -= kDaysInMonths[i];
1143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
1153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
1163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Check January and February.
1173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (days < 31) {
1183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      *month = 0;
1193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      *day = days + 1;
1203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    } else {
1213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      *month = 1;
1223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      *day = days - 31 + 1;
1233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
1243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
125b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(DaysFromYearMonth(*year, *month) + *day - 1 == save_days);
1263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ymd_valid_ = true;
1273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ymd_year_ = *year;
1283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ymd_month_ = *month;
1293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ymd_day_ = *day;
1303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ymd_days_ = save_days;
1313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
1323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochint DateCache::DaysFromYearMonth(int year, int month) {
1353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
1363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                       181, 212, 243, 273, 304, 334};
1373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
1383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                                            182, 213, 244, 274, 305, 335};
1393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  year += month / 12;
1413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  month %= 12;
1423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (month < 0) {
1433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    year--;
1443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    month += 12;
1453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
1463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
147b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(month >= 0);
148b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(month < 12);
1493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // year_delta is an arbitrary number such that:
1513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // a) year_delta = -1 (mod 400)
1523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // b) year + year_delta > 0 for years in the range defined by
1533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //    ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
1543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //    Jan 1 1970. This is required so that we don't run into integer
1553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //    division of negative numbers.
1563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // c) there shouldn't be an overflow for 32-bit integers in the following
1573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  //    operations.
1583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static const int year_delta = 399999;
1593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  static const int base_day = 365 * (1970 + year_delta) +
1603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                              (1970 + year_delta) / 4 -
1613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                              (1970 + year_delta) / 100 +
1623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                              (1970 + year_delta) / 400;
1633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int year1 = year + year_delta;
1653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int day_from_year = 365 * year1 +
1663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      year1 / 4 -
1673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      year1 / 100 +
1683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      year1 / 400 -
1693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch                      base_day;
1703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
1723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    return day_from_year + day_from_month[month];
1733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
1743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return day_from_year + day_from_month_leap[month];
1753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
1763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
178014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdochvoid DateCache::BreakDownTime(int64_t time_ms, int* year, int* month, int* day,
179014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                              int* weekday, int* hour, int* min, int* sec,
180014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch                              int* ms) {
181014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int const days = DaysFromTime(time_ms);
182014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  int const time_in_day_ms = TimeInDay(time_ms, days);
183014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  YearMonthDayFromDays(days, year, month, day);
184014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  *weekday = Weekday(days);
185014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  *hour = time_in_day_ms / (60 * 60 * 1000);
186014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  *min = (time_in_day_ms / (60 * 1000)) % 60;
187014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  *sec = (time_in_day_ms / 1000) % 60;
188014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch  *ms = time_in_day_ms % 1000;
189014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}
190014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
191014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch
1923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid DateCache::ExtendTheAfterSegment(int time_sec, int offset_ms) {
1933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (after_->offset_ms == offset_ms &&
1943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      after_->start_sec <= time_sec + kDefaultDSTDeltaInSec &&
1953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      time_sec <= after_->end_sec) {
1963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Extend the after_ segment.
1973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    after_->start_sec = time_sec;
1983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
1993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // The after_ segment is either invalid or starts too late.
2003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (after_->start_sec <= after_->end_sec) {
2013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      // If the after_ segment is valid, replace it with a new segment.
2023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      after_ = LeastRecentlyUsedDST(before_);
2033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
2043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    after_->start_sec = time_sec;
2053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    after_->end_sec = time_sec;
2063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    after_->offset_ms = offset_ms;
2073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    after_->last_used = ++dst_usage_counter_;
2083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
2103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochint DateCache::DaylightSavingsOffsetInMs(int64_t time_ms) {
2133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  int time_sec = (time_ms >= 0 && time_ms <= kMaxEpochTimeInMs)
2143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ? static_cast<int>(time_ms / 1000)
2153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      : static_cast<int>(EquivalentTime(time_ms) / 1000);
2163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Invalidate cache if the usage counter is close to overflow.
2183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Note that dst_usage_counter is incremented less than ten times
2193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // in this function.
2203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (dst_usage_counter_ >= kMaxInt - 10) {
2213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    dst_usage_counter_ = 0;
2223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    for (int i = 0; i < kDSTSize; ++i) {
2233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      ClearSegment(&dst_[i]);
2243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
2253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Optimistic fast check.
2283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (before_->start_sec <= time_sec &&
2293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      time_sec <= before_->end_sec) {
2303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Cache hit.
2313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    before_->last_used = ++dst_usage_counter_;
2323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    return before_->offset_ms;
2333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ProbeDST(time_sec);
2363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
237b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(InvalidSegment(before_) || before_->start_sec <= time_sec);
238b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(InvalidSegment(after_) || time_sec < after_->start_sec);
2393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (InvalidSegment(before_)) {
2413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Cache miss.
2423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    before_->start_sec = time_sec;
2433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    before_->end_sec = time_sec;
2443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    before_->offset_ms = GetDaylightSavingsOffsetFromOS(time_sec);
2453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    before_->last_used = ++dst_usage_counter_;
2463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    return before_->offset_ms;
2473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (time_sec <= before_->end_sec) {
2503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Cache hit.
2513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    before_->last_used = ++dst_usage_counter_;
2523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    return before_->offset_ms;
2533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2543ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (time_sec > before_->end_sec + kDefaultDSTDeltaInSec) {
2563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // If the before_ segment ends too early, then just
2573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // query for the offset of the time_sec
2583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int offset_ms = GetDaylightSavingsOffsetFromOS(time_sec);
2593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ExtendTheAfterSegment(time_sec, offset_ms);
2603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // This swap helps the optimistic fast check in subsequent invocations.
2613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    DST* temp = before_;
2623ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    before_ = after_;
2633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    after_ = temp;
2643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    return offset_ms;
2653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Now the time_sec is between
2683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // before_->end_sec and before_->end_sec + default DST delta.
2693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Update the usage counter of before_ since it is going to be used.
2703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  before_->last_used = ++dst_usage_counter_;
2713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Check if after_ segment is invalid or starts too late.
2733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Note that start_sec of invalid segments is kMaxEpochTimeInSec.
2743ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (before_->end_sec + kDefaultDSTDeltaInSec <= after_->start_sec) {
2753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int new_after_start_sec = before_->end_sec + kDefaultDSTDeltaInSec;
2763ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int new_offset_ms = GetDaylightSavingsOffsetFromOS(new_after_start_sec);
2773ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ExtendTheAfterSegment(new_after_start_sec, new_offset_ms);
2783ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  } else {
279b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch    DCHECK(!InvalidSegment(after_));
2803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Update the usage counter of after_ since it is going to be used.
2813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    after_->last_used = ++dst_usage_counter_;
2823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2843ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Now the time_sec is between before_->end_sec and after_->start_sec.
2853ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Only one daylight savings offset change can occur in this interval.
2863ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2873ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (before_->offset_ms == after_->offset_ms) {
2883ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    // Merge two segments if they have the same offset.
2893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    before_->end_sec = after_->end_sec;
2903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    ClearSegment(after_);
2913ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    return before_->offset_ms;
2923ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
2933ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
2943ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // Binary search for daylight savings offset change point,
2953ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // but give up if we don't find it in four iterations.
2963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 4; i >= 0; --i) {
2973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int delta = after_->start_sec - before_->end_sec;
2983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int middle_sec = (i == 0) ? time_sec : before_->end_sec + delta / 2;
2993ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    int offset_ms = GetDaylightSavingsOffsetFromOS(middle_sec);
3003ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (before_->offset_ms == offset_ms) {
3013ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      before_->end_sec = middle_sec;
3023ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if (time_sec <= before_->end_sec) {
3033ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        return offset_ms;
3043ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
3053ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    } else {
306b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch      DCHECK(after_->offset_ms == offset_ms);
3073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      after_->start_sec = middle_sec;
3083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if (time_sec >= after_->start_sec) {
3093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        // This swap helps the optimistic fast check in subsequent invocations.
3103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        DST* temp = before_;
3113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        before_ = after_;
3123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        after_ = temp;
3133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        return offset_ms;
3143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
3153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
3163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  UNREACHABLE();
3183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return 0;
3193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
3203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochvoid DateCache::ProbeDST(int time_sec) {
3233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  DST* before = NULL;
3243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  DST* after = NULL;
325b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(before_ != after_);
3263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 0; i < kDSTSize; ++i) {
3283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (dst_[i].start_sec <= time_sec) {
3293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if (before == NULL || before->start_sec < dst_[i].start_sec) {
3303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        before = &dst_[i];
3313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
3323ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    } else if (time_sec < dst_[i].end_sec) {
3333ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if (after == NULL || after->end_sec > dst_[i].end_sec) {
3343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        after = &dst_[i];
3353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      }
3363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
3373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3393ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // If before or after segments were not found,
3403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  // then set them to any invalid segment.
3413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (before == NULL) {
3423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    before = InvalidSegment(before_) ? before_ : LeastRecentlyUsedDST(after);
3433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if (after == NULL) {
3453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    after = InvalidSegment(after_) && before != after_
3463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch            ? after_ : LeastRecentlyUsedDST(before);
3473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
349b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(before != NULL);
350b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(after != NULL);
351b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(before != after);
352b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(InvalidSegment(before) || before->start_sec <= time_sec);
353b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(InvalidSegment(after) || time_sec < after->start_sec);
354b8a8cc1952d61a2f3a2568848933943a543b5d3eBen Murdoch  DCHECK(InvalidSegment(before) || InvalidSegment(after) ||
3553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch         before->end_sec < after->start_sec);
3563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3573ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  before_ = before;
3583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  after_ = after;
3593ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
3603ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3613ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
3623ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochDateCache::DST* DateCache::LeastRecentlyUsedDST(DST* skip) {
3633ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  DST* result = NULL;
3643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  for (int i = 0; i < kDSTSize; ++i) {
3653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (&dst_[i] == skip) continue;
3663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if (result == NULL || result->last_used > dst_[i].last_used) {
3673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      result = &dst_[i];
3683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    }
3693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  }
3703ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  ClearSegment(result);
3713ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  return result;
3723ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch}
3733ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
374014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace internal
375014dc512cdd3e367bee49a713fdc5ed92584a3e5Ben Murdoch}  // namespace v8
376