Line data Source code
1 : // Copyright 2012 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/date.h"
6 :
7 : #include "src/objects.h"
8 : #include "src/objects-inl.h"
9 :
10 : #ifdef V8_INTL_SUPPORT
11 : #include "src/intl.h"
12 : #endif
13 :
14 : namespace v8 {
15 : namespace internal {
16 :
17 :
18 : static const int kDaysIn4Years = 4 * 365 + 1;
19 : static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
20 : static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
21 : static const int kDays1970to2000 = 30 * 365 + 7;
22 : static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
23 : kDays1970to2000;
24 : static const int kYearsOffset = 400000;
25 : static const char kDaysInMonths[] =
26 : {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
27 :
28 60789 : DateCache::DateCache()
29 : : stamp_(0),
30 : tz_cache_(
31 : #ifdef V8_INTL_SUPPORT
32 : FLAG_icu_timezone_data ? new ICUTimezoneCache()
33 : : base::OS::CreateTimezoneCache()
34 : #else
35 : base::OS::CreateTimezoneCache()
36 : #endif
37 60789 : ) {
38 60789 : ResetDateCache();
39 60789 : }
40 :
41 60796 : void DateCache::ResetDateCache() {
42 : static const int kMaxStamp = Smi::kMaxValue;
43 121592 : if (stamp_->value() >= kMaxStamp) {
44 0 : stamp_ = Smi::kZero;
45 : } else {
46 121592 : stamp_ = Smi::FromInt(stamp_->value() + 1);
47 : }
48 : DCHECK(stamp_ != Smi::FromInt(kInvalidStamp));
49 1945472 : for (int i = 0; i < kDSTSize; ++i) {
50 1945472 : ClearSegment(&dst_[i]);
51 : }
52 60796 : dst_usage_counter_ = 0;
53 60796 : before_ = &dst_[0];
54 60796 : after_ = &dst_[1];
55 60796 : local_offset_ms_ = kInvalidLocalOffsetInMs;
56 60796 : ymd_valid_ = false;
57 60796 : tz_cache_->Clear();
58 60796 : tz_name_ = nullptr;
59 60796 : dst_tz_name_ = nullptr;
60 60796 : }
61 :
62 :
63 : void DateCache::ClearSegment(DST* segment) {
64 1981140 : segment->start_sec = kMaxEpochTimeInSec;
65 1981140 : segment->end_sec = -kMaxEpochTimeInSec;
66 1981140 : segment->offset_ms = 0;
67 1981140 : segment->last_used = 0;
68 : }
69 :
70 :
71 192427 : void DateCache::YearMonthDayFromDays(
72 : int days, int* year, int* month, int* day) {
73 192427 : if (ymd_valid_) {
74 : // Check conservatively if the given 'days' has
75 : // the same year and month as the cached 'days'.
76 192212 : int new_day = ymd_day_ + (days - ymd_days_);
77 192212 : if (new_day >= 1 && new_day <= 28) {
78 156783 : ymd_day_ = new_day;
79 156783 : ymd_days_ = days;
80 156783 : *year = ymd_year_;
81 156783 : *month = ymd_month_;
82 156783 : *day = new_day;
83 349210 : return;
84 : }
85 : }
86 : int save_days = days;
87 :
88 35644 : days += kDaysOffset;
89 35644 : *year = 400 * (days / kDaysIn400Years) - kYearsOffset;
90 35644 : days %= kDaysIn400Years;
91 :
92 : DCHECK_EQ(save_days, DaysFromYearMonth(*year, 0) + days);
93 :
94 35644 : days--;
95 35644 : int yd1 = days / kDaysIn100Years;
96 35644 : days %= kDaysIn100Years;
97 35644 : *year += 100 * yd1;
98 :
99 35644 : days++;
100 35644 : int yd2 = days / kDaysIn4Years;
101 35644 : days %= kDaysIn4Years;
102 35644 : *year += 4 * yd2;
103 :
104 35644 : days--;
105 35644 : int yd3 = days / 365;
106 35644 : days %= 365;
107 35644 : *year += yd3;
108 :
109 :
110 35644 : bool is_leap = (!yd1 || yd2) && !yd3;
111 :
112 : DCHECK(days >= -1);
113 : DCHECK(is_leap || (days >= 0));
114 : DCHECK((days < 365) || (is_leap && (days < 366)));
115 : DCHECK(is_leap == ((*year % 4 == 0) && (*year % 100 || (*year % 400 == 0))));
116 : DCHECK(is_leap || ((DaysFromYearMonth(*year, 0) + days) == save_days));
117 : DCHECK(!is_leap || ((DaysFromYearMonth(*year, 0) + days + 1) == save_days));
118 :
119 35644 : days += is_leap;
120 :
121 : // Check if the date is after February.
122 35644 : if (days >= 31 + 28 + BoolToInt(is_leap)) {
123 30603 : days -= 31 + 28 + BoolToInt(is_leap);
124 : // Find the date starting from March.
125 169036 : for (int i = 2; i < 12; i++) {
126 169036 : if (days < kDaysInMonths[i]) {
127 30603 : *month = i;
128 30603 : *day = days + 1;
129 30603 : break;
130 : }
131 138433 : days -= kDaysInMonths[i];
132 : }
133 : } else {
134 : // Check January and February.
135 5041 : if (days < 31) {
136 3281 : *month = 0;
137 3281 : *day = days + 1;
138 : } else {
139 1760 : *month = 1;
140 1760 : *day = days - 31 + 1;
141 : }
142 : }
143 : DCHECK(DaysFromYearMonth(*year, *month) + *day - 1 == save_days);
144 35644 : ymd_valid_ = true;
145 35644 : ymd_year_ = *year;
146 35644 : ymd_month_ = *month;
147 35644 : ymd_day_ = *day;
148 35644 : ymd_days_ = save_days;
149 : }
150 :
151 :
152 200601 : int DateCache::DaysFromYearMonth(int year, int month) {
153 : static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
154 : 181, 212, 243, 273, 304, 334};
155 : static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
156 : 182, 213, 244, 274, 305, 335};
157 :
158 200601 : year += month / 12;
159 200601 : month %= 12;
160 200601 : if (month < 0) {
161 0 : year--;
162 0 : month += 12;
163 : }
164 :
165 : DCHECK(month >= 0);
166 : DCHECK(month < 12);
167 :
168 : // year_delta is an arbitrary number such that:
169 : // a) year_delta = -1 (mod 400)
170 : // b) year + year_delta > 0 for years in the range defined by
171 : // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
172 : // Jan 1 1970. This is required so that we don't run into integer
173 : // division of negative numbers.
174 : // c) there shouldn't be an overflow for 32-bit integers in the following
175 : // operations.
176 : static const int year_delta = 399999;
177 : static const int base_day = 365 * (1970 + year_delta) +
178 : (1970 + year_delta) / 4 -
179 : (1970 + year_delta) / 100 +
180 : (1970 + year_delta) / 400;
181 :
182 200601 : int year1 = year + year_delta;
183 401202 : int day_from_year = 365 * year1 +
184 401202 : year1 / 4 -
185 401202 : year1 / 100 +
186 200601 : year1 / 400 -
187 200601 : base_day;
188 :
189 200601 : if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
190 157097 : return day_from_year + day_from_month[month];
191 : }
192 43504 : return day_from_year + day_from_month_leap[month];
193 : }
194 :
195 :
196 89344 : void DateCache::BreakDownTime(int64_t time_ms, int* year, int* month, int* day,
197 : int* weekday, int* hour, int* min, int* sec,
198 : int* ms) {
199 : int const days = DaysFromTime(time_ms);
200 : int const time_in_day_ms = TimeInDay(time_ms, days);
201 89344 : YearMonthDayFromDays(days, year, month, day);
202 89344 : *weekday = Weekday(days);
203 89344 : *hour = time_in_day_ms / (60 * 60 * 1000);
204 89344 : *min = (time_in_day_ms / (60 * 1000)) % 60;
205 89344 : *sec = (time_in_day_ms / 1000) % 60;
206 89344 : *ms = time_in_day_ms % 1000;
207 89344 : }
208 :
209 :
210 24889 : void DateCache::ExtendTheAfterSegment(int time_sec, int offset_ms) {
211 35714 : if (after_->offset_ms == offset_ms &&
212 12129 : after_->start_sec <= time_sec + kDefaultDSTDeltaInSec &&
213 1304 : time_sec <= after_->end_sec) {
214 : // Extend the after_ segment.
215 1304 : after_->start_sec = time_sec;
216 : } else {
217 : // The after_ segment is either invalid or starts too late.
218 23585 : if (after_->start_sec <= after_->end_sec) {
219 : // If the after_ segment is valid, replace it with a new segment.
220 15932 : after_ = LeastRecentlyUsedDST(before_);
221 : }
222 23585 : after_->start_sec = time_sec;
223 23585 : after_->end_sec = time_sec;
224 23585 : after_->offset_ms = offset_ms;
225 23585 : after_->last_used = ++dst_usage_counter_;
226 : }
227 24889 : }
228 :
229 :
230 287046 : int DateCache::DaylightSavingsOffsetInMs(int64_t time_ms) {
231 287046 : int time_sec = (time_ms >= 0 && time_ms <= kMaxEpochTimeInMs)
232 229635 : ? static_cast<int>(time_ms / 1000)
233 516681 : : static_cast<int>(EquivalentTime(time_ms) / 1000);
234 :
235 : // Invalidate cache if the usage counter is close to overflow.
236 : // Note that dst_usage_counter is incremented less than ten times
237 : // in this function.
238 287046 : if (dst_usage_counter_ >= kMaxInt - 10) {
239 0 : dst_usage_counter_ = 0;
240 0 : for (int i = 0; i < kDSTSize; ++i) {
241 0 : ClearSegment(&dst_[i]);
242 : }
243 : }
244 :
245 : // Optimistic fast check.
246 602949 : if (before_->start_sec <= time_sec &&
247 281099 : time_sec <= before_->end_sec) {
248 : // Cache hit.
249 252242 : before_->last_used = ++dst_usage_counter_;
250 252242 : return before_->offset_ms;
251 : }
252 :
253 34804 : ProbeDST(time_sec);
254 :
255 : DCHECK(InvalidSegment(before_) || before_->start_sec <= time_sec);
256 : DCHECK(InvalidSegment(after_) || time_sec < after_->start_sec);
257 :
258 69608 : if (InvalidSegment(before_)) {
259 : // Cache miss.
260 3618 : before_->start_sec = time_sec;
261 3618 : before_->end_sec = time_sec;
262 3618 : before_->offset_ms = GetDaylightSavingsOffsetFromOS(time_sec);
263 3618 : before_->last_used = ++dst_usage_counter_;
264 3618 : return before_->offset_ms;
265 : }
266 :
267 31186 : if (time_sec <= before_->end_sec) {
268 : // Cache hit.
269 2633 : before_->last_used = ++dst_usage_counter_;
270 2633 : return before_->offset_ms;
271 : }
272 :
273 28553 : if (time_sec > before_->end_sec + kDefaultDSTDeltaInSec) {
274 : // If the before_ segment ends too early, then just
275 : // query for the offset of the time_sec
276 1769 : int offset_ms = GetDaylightSavingsOffsetFromOS(time_sec);
277 1769 : ExtendTheAfterSegment(time_sec, offset_ms);
278 : // This swap helps the optimistic fast check in subsequent invocations.
279 1769 : DST* temp = before_;
280 1769 : before_ = after_;
281 1769 : after_ = temp;
282 1769 : return offset_ms;
283 : }
284 :
285 : // Now the time_sec is between
286 : // before_->end_sec and before_->end_sec + default DST delta.
287 : // Update the usage counter of before_ since it is going to be used.
288 26784 : before_->last_used = ++dst_usage_counter_;
289 :
290 : // Check if after_ segment is invalid or starts too late.
291 : // Note that start_sec of invalid segments is kMaxEpochTimeInSec.
292 26784 : if (before_->end_sec + kDefaultDSTDeltaInSec <= after_->start_sec) {
293 23120 : int new_after_start_sec = before_->end_sec + kDefaultDSTDeltaInSec;
294 23120 : int new_offset_ms = GetDaylightSavingsOffsetFromOS(new_after_start_sec);
295 23120 : ExtendTheAfterSegment(new_after_start_sec, new_offset_ms);
296 : } else {
297 : DCHECK(!InvalidSegment(after_));
298 : // Update the usage counter of after_ since it is going to be used.
299 3664 : after_->last_used = ++dst_usage_counter_;
300 : }
301 :
302 : // Now the time_sec is between before_->end_sec and after_->start_sec.
303 : // Only one daylight savings offset change can occur in this interval.
304 :
305 26784 : if (before_->offset_ms == after_->offset_ms) {
306 : // Merge two segments if they have the same offset.
307 22295 : before_->end_sec = after_->end_sec;
308 : ClearSegment(after_);
309 22295 : return before_->offset_ms;
310 : }
311 :
312 : // Binary search for daylight savings offset change point,
313 : // but give up if we don't find it in four iterations.
314 4425 : for (int i = 4; i >= 0; --i) {
315 8914 : int delta = after_->start_sec - before_->end_sec;
316 8914 : int middle_sec = (i == 0) ? time_sec : before_->end_sec + delta / 2;
317 8914 : int offset_ms = GetDaylightSavingsOffsetFromOS(middle_sec);
318 8914 : if (before_->offset_ms == offset_ms) {
319 4331 : before_->end_sec = middle_sec;
320 4331 : if (time_sec <= before_->end_sec) {
321 : return offset_ms;
322 : }
323 : } else {
324 : DCHECK(after_->offset_ms == offset_ms);
325 4583 : after_->start_sec = middle_sec;
326 4583 : if (time_sec >= after_->start_sec) {
327 : // This swap helps the optimistic fast check in subsequent invocations.
328 : DST* temp = before_;
329 1497 : before_ = after_;
330 1497 : after_ = temp;
331 1497 : return offset_ms;
332 : }
333 : }
334 : }
335 0 : UNREACHABLE();
336 : return 0;
337 : }
338 :
339 :
340 34804 : void DateCache::ProbeDST(int time_sec) {
341 : DST* before = NULL;
342 : DST* after = NULL;
343 : DCHECK(before_ != after_);
344 :
345 1148532 : for (int i = 0; i < kDSTSize; ++i) {
346 1113728 : if (dst_[i].start_sec <= time_sec) {
347 686723 : if (before == NULL || before->start_sec < dst_[i].start_sec) {
348 243860 : before = &dst_[i];
349 : }
350 427005 : } else if (time_sec < dst_[i].end_sec) {
351 287476 : if (after == NULL || after->end_sec > dst_[i].end_sec) {
352 85254 : after = &dst_[i];
353 : }
354 : }
355 : }
356 :
357 : // If before or after segments were not found,
358 : // then set them to any invalid segment.
359 34804 : if (before == NULL) {
360 3618 : before = InvalidSegment(before_) ? before_ : LeastRecentlyUsedDST(after);
361 : }
362 34804 : if (after == NULL) {
363 31138 : after = InvalidSegment(after_) && before != after_
364 16577 : ? after_ : LeastRecentlyUsedDST(before);
365 : }
366 :
367 : DCHECK(before != NULL);
368 : DCHECK(after != NULL);
369 : DCHECK(before != after);
370 : DCHECK(InvalidSegment(before) || before->start_sec <= time_sec);
371 : DCHECK(InvalidSegment(after) || time_sec < after->start_sec);
372 : DCHECK(InvalidSegment(before) || InvalidSegment(after) ||
373 : before->end_sec < after->start_sec);
374 :
375 34804 : before_ = before;
376 34804 : after_ = after;
377 34804 : }
378 :
379 :
380 0 : DateCache::DST* DateCache::LeastRecentlyUsedDST(DST* skip) {
381 : DST* result = NULL;
382 427936 : for (int i = 0; i < kDSTSize; ++i) {
383 427936 : if (&dst_[i] == skip) continue;
384 414563 : if (result == NULL || result->last_used > dst_[i].last_used) {
385 : result = &dst_[i];
386 : }
387 : }
388 : ClearSegment(result);
389 0 : return result;
390 : }
391 :
392 : } // namespace internal
393 : } // namespace v8
|