7 #include "src/conversions.h" 8 #include "src/objects-inl.h" 10 #include "src/objects/intl-objects.h" 17 static const int kDaysIn4Years = 4 * 365 + 1;
18 static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
19 static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
20 static const int kDays1970to2000 = 30 * 365 + 7;
21 static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
23 static const int kYearsOffset = 400000;
24 static const char kDaysInMonths[] =
25 {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
27 DateCache::DateCache()
28 : stamp_(kNullAddress),
30 #ifdef V8_INTL_SUPPORT
31 Intl::CreateTimeZoneCache()
33 base::OS::CreateTimezoneCache()
39 void DateCache::ResetDateCache() {
40 if (stamp_->value() >= Smi::kMaxValue) {
43 stamp_ = Smi::FromInt(stamp_->value() + 1);
45 DCHECK(stamp_ != Smi::FromInt(kInvalidStamp));
46 for (
int i = 0;
i < kDSTSize; ++
i) {
47 ClearSegment(&dst_[
i]);
49 dst_usage_counter_ = 0;
53 #ifdef V8_INTL_SUPPORT 54 if (!FLAG_icu_timezone_data) {
56 local_offset_ms_ = kInvalidLocalOffsetInMs;
57 #ifdef V8_INTL_SUPPORT 62 dst_tz_name_ =
nullptr;
66 double DateCache::TimeClip(
double time) {
67 if (-kMaxTimeInMs <= time && time <= kMaxTimeInMs) {
68 return DoubleToInteger(time) + 0.0;
70 return std::numeric_limits<double>::quiet_NaN();
73 void DateCache::ClearSegment(DST* segment) {
74 segment->start_sec = kMaxEpochTimeInSec;
75 segment->end_sec = -kMaxEpochTimeInSec;
76 segment->offset_ms = 0;
77 segment->last_used = 0;
81 void DateCache::YearMonthDayFromDays(
82 int days,
int* year,
int* month,
int* day) {
86 int new_day = ymd_day_ + (days - ymd_days_);
87 if (new_day >= 1 && new_day <= 28) {
99 *year = 400 * (days / kDaysIn400Years) - kYearsOffset;
100 days %= kDaysIn400Years;
102 DCHECK_EQ(save_days, DaysFromYearMonth(*year, 0) + days);
105 int yd1 = days / kDaysIn100Years;
106 days %= kDaysIn100Years;
110 int yd2 = days / kDaysIn4Years;
111 days %= kDaysIn4Years;
115 int yd3 = days / 365;
120 bool is_leap = (!yd1 || yd2) && !yd3;
123 DCHECK(is_leap || (days >= 0));
124 DCHECK((days < 365) || (is_leap && (days < 366)));
125 DCHECK(is_leap == ((*year % 4 == 0) && (*year % 100 || (*year % 400 == 0))));
126 DCHECK(is_leap || ((DaysFromYearMonth(*year, 0) + days) == save_days));
127 DCHECK(!is_leap || ((DaysFromYearMonth(*year, 0) + days + 1) == save_days));
132 if (days >= 31 + 28 + BoolToInt(is_leap)) {
133 days -= 31 + 28 + BoolToInt(is_leap);
135 for (
int i = 2;
i < 12;
i++) {
136 if (days < kDaysInMonths[
i]) {
141 days -= kDaysInMonths[
i];
150 *day = days - 31 + 1;
153 DCHECK(DaysFromYearMonth(*year, *month) + *day - 1 == save_days);
158 ymd_days_ = save_days;
162 int DateCache::DaysFromYearMonth(
int year,
int month) {
163 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
164 181, 212, 243, 273, 304, 334};
165 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
166 182, 213, 244, 274, 305, 335};
176 DCHECK_LT(month, 12);
186 static const int year_delta = 399999;
187 static const int base_day = 365 * (1970 + year_delta) +
188 (1970 + year_delta) / 4 -
189 (1970 + year_delta) / 100 +
190 (1970 + year_delta) / 400;
192 int year1 = year + year_delta;
193 int day_from_year = 365 * year1 +
199 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
200 return day_from_year + day_from_month[month];
202 return day_from_year + day_from_month_leap[month];
206 void DateCache::BreakDownTime(
int64_t time_ms,
int* year,
int* month,
int* day,
207 int* weekday,
int* hour,
int* min,
int* sec,
209 int const days = DaysFromTime(time_ms);
210 int const time_in_day_ms = TimeInDay(time_ms, days);
211 YearMonthDayFromDays(days, year, month, day);
212 *weekday = Weekday(days);
213 *hour = time_in_day_ms / (60 * 60 * 1000);
214 *min = (time_in_day_ms / (60 * 1000)) % 60;
215 *sec = (time_in_day_ms / 1000) % 60;
216 *ms = time_in_day_ms % 1000;
221 int DateCache::GetLocalOffsetFromOS(
int64_t time_ms,
bool is_utc) {
223 #ifdef V8_INTL_SUPPORT 224 if (FLAG_icu_timezone_data) {
225 offset = tz_cache_->LocalTimeOffset(static_cast<double>(time_ms), is_utc);
266 if (local_offset_ms_ == kInvalidLocalOffsetInMs) {
269 tz_cache_->LocalTimeOffset(static_cast<double>(time_ms), is_utc);
271 offset = local_offset_ms_;
273 const int kMsPerHour = 3600 * 1000;
274 time_ms -= (offset + kMsPerHour);
276 offset += DaylightSavingsOffsetInMs(time_ms);
277 #ifdef V8_INTL_SUPPORT 280 DCHECK_LT(offset, kInvalidLocalOffsetInMs);
281 return static_cast<int>(offset);
284 void DateCache::ExtendTheAfterSegment(
int time_sec,
int offset_ms) {
285 if (after_->offset_ms == offset_ms &&
286 after_->start_sec <= time_sec + kDefaultDSTDeltaInSec &&
287 time_sec <= after_->end_sec) {
289 after_->start_sec = time_sec;
292 if (after_->start_sec <= after_->end_sec) {
294 after_ = LeastRecentlyUsedDST(before_);
296 after_->start_sec = time_sec;
297 after_->end_sec = time_sec;
298 after_->offset_ms = offset_ms;
299 after_->last_used = ++dst_usage_counter_;
304 int DateCache::DaylightSavingsOffsetInMs(
int64_t time_ms) {
305 int time_sec = (time_ms >= 0 && time_ms <= kMaxEpochTimeInMs)
306 ? static_cast<int>(time_ms / 1000)
307 :
static_cast<int>(EquivalentTime(time_ms) / 1000);
312 if (dst_usage_counter_ >= kMaxInt - 10) {
313 dst_usage_counter_ = 0;
314 for (
int i = 0;
i < kDSTSize; ++
i) {
315 ClearSegment(&dst_[
i]);
320 if (before_->start_sec <= time_sec &&
321 time_sec <= before_->end_sec) {
323 before_->last_used = ++dst_usage_counter_;
324 return before_->offset_ms;
329 DCHECK(InvalidSegment(before_) || before_->start_sec <= time_sec);
330 DCHECK(InvalidSegment(after_) || time_sec < after_->start_sec);
332 if (InvalidSegment(before_)) {
334 before_->start_sec = time_sec;
335 before_->end_sec = time_sec;
336 before_->offset_ms = GetDaylightSavingsOffsetFromOS(time_sec);
337 before_->last_used = ++dst_usage_counter_;
338 return before_->offset_ms;
341 if (time_sec <= before_->end_sec) {
343 before_->last_used = ++dst_usage_counter_;
344 return before_->offset_ms;
347 if (time_sec > before_->end_sec + kDefaultDSTDeltaInSec) {
350 int offset_ms = GetDaylightSavingsOffsetFromOS(time_sec);
351 ExtendTheAfterSegment(time_sec, offset_ms);
362 before_->last_used = ++dst_usage_counter_;
366 if (before_->end_sec + kDefaultDSTDeltaInSec <= after_->start_sec) {
367 int new_after_start_sec = before_->end_sec + kDefaultDSTDeltaInSec;
368 int new_offset_ms = GetDaylightSavingsOffsetFromOS(new_after_start_sec);
369 ExtendTheAfterSegment(new_after_start_sec, new_offset_ms);
371 DCHECK(!InvalidSegment(after_));
373 after_->last_used = ++dst_usage_counter_;
379 if (before_->offset_ms == after_->offset_ms) {
381 before_->end_sec = after_->end_sec;
382 ClearSegment(after_);
383 return before_->offset_ms;
388 for (
int i = 4;
i >= 0; --
i) {
389 int delta = after_->start_sec - before_->end_sec;
390 int middle_sec = (
i == 0) ? time_sec : before_->end_sec + delta / 2;
391 int offset_ms = GetDaylightSavingsOffsetFromOS(middle_sec);
392 if (before_->offset_ms == offset_ms) {
393 before_->end_sec = middle_sec;
394 if (time_sec <= before_->end_sec) {
398 DCHECK(after_->offset_ms == offset_ms);
399 after_->start_sec = middle_sec;
400 if (time_sec >= after_->start_sec) {
413 void DateCache::ProbeDST(
int time_sec) {
414 DST* before =
nullptr;
415 DST* after =
nullptr;
416 DCHECK(before_ != after_);
418 for (
int i = 0;
i < kDSTSize; ++
i) {
419 if (dst_[
i].start_sec <= time_sec) {
420 if (before ==
nullptr || before->start_sec < dst_[
i].start_sec) {
423 }
else if (time_sec < dst_[
i].end_sec) {
424 if (after ==
nullptr || after->end_sec > dst_[
i].end_sec) {
432 if (before ==
nullptr) {
433 before = InvalidSegment(before_) ? before_ : LeastRecentlyUsedDST(after);
435 if (after ==
nullptr) {
436 after = InvalidSegment(after_) && before != after_
437 ? after_ : LeastRecentlyUsedDST(before);
440 DCHECK_NOT_NULL(before);
441 DCHECK_NOT_NULL(after);
442 DCHECK(before != after);
443 DCHECK(InvalidSegment(before) || before->start_sec <= time_sec);
444 DCHECK(InvalidSegment(after) || time_sec < after->start_sec);
445 DCHECK(InvalidSegment(before) || InvalidSegment(after) ||
446 before->end_sec < after->start_sec);
453 DateCache::DST* DateCache::LeastRecentlyUsedDST(DST* skip) {
454 DST* result =
nullptr;
455 for (
int i = 0;
i < kDSTSize; ++
i) {
456 if (&dst_[
i] == skip)
continue;
457 if (result ==
nullptr || result->last_used > dst_[
i].last_used) {
461 ClearSegment(result);