OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
114 // the actual year if it is in the range 1970..2037 | 114 // the actual year if it is in the range 1970..2037 |
115 if (t >= 0 && t <= 2.1e12) return t; | 115 if (t >= 0 && t <= 2.1e12) return t; |
116 | 116 |
117 var day = MakeDay(EquivalentYear(YEAR_FROM_TIME(t)), | 117 var day = MakeDay(EquivalentYear(YEAR_FROM_TIME(t)), |
118 MONTH_FROM_TIME(t), | 118 MONTH_FROM_TIME(t), |
119 DATE_FROM_TIME(t)); | 119 DATE_FROM_TIME(t)); |
120 return MakeDate(day, TimeWithinDay(t)); | 120 return MakeDate(day, TimeWithinDay(t)); |
121 } | 121 } |
122 | 122 |
123 | 123 |
124 // Because computing the DST offset is a pretty expensive operation | 124 // local_time_offset is initialized when the DST_offset_cache is missed. |
125 // we keep a cache of last computed offset along with a time interval | 125 // It must not be used until after a call to DaylightSavingsOffset(). |
| 126 // In this way, only one check, for a DST cache miss, is needed. |
| 127 var local_time_offset; |
| 128 |
| 129 |
| 130 // Because computing the DST offset is an expensive operation, |
| 131 // we keep a cache of the last computed DST offset along with a time interval |
126 // where we know the cache is valid. | 132 // where we know the cache is valid. |
| 133 // When the cache is valid, local_time_offset is also valid. |
127 var DST_offset_cache = { | 134 var DST_offset_cache = { |
128 // Cached DST offset. | 135 // Cached DST offset. |
129 offset: 0, | 136 offset: 0, |
130 // Time interval where the cached offset is valid. | 137 // Time interval where the cached offset is valid. |
131 start: 0, end: -1, | 138 start: 0, end: -1, |
132 // Size of next interval expansion. | 139 // Size of next interval expansion. |
133 increment: 0 | 140 increment: 0 |
134 }; | 141 }; |
135 | 142 |
136 | 143 |
137 // NOTE: The implementation relies on the fact that no time zones have | 144 // NOTE: The implementation relies on the fact that no time zones have |
138 // more than one daylight savings offset change per month. | 145 // more than one daylight savings offset change per month. |
139 // If this function is called with NaN it returns NaN. | 146 // If this function is called with NaN it returns NaN. |
140 function DaylightSavingsOffset(t) { | 147 function DaylightSavingsOffset(t) { |
141 // Load the cache object from the builtins object. | 148 // Load the cache object from the builtins object. |
142 var cache = DST_offset_cache; | 149 var cache = DST_offset_cache; |
143 | 150 |
144 // Cache the start and the end in local variables for fast access. | 151 // Cache the start and the end in local variables for fast access. |
145 var start = cache.start; | 152 var start = cache.start; |
146 var end = cache.end; | 153 var end = cache.end; |
147 | 154 |
148 if (start <= t) { | 155 if (start <= t) { |
149 // If the time fits in the cached interval, return the cached offset. | 156 // If the time fits in the cached interval, return the cached offset. |
150 if (t <= end) return cache.offset; | 157 if (t <= end) return cache.offset; |
151 | 158 |
| 159 // If the cache misses, the local_time_offset may not be initialized. |
| 160 if (IS_UNDEFINED(local_time_offset)) { |
| 161 local_time_offset = %DateLocalTimeOffset(); |
| 162 } |
| 163 |
152 // Compute a possible new interval end. | 164 // Compute a possible new interval end. |
153 var new_end = end + cache.increment; | 165 var new_end = end + cache.increment; |
154 | 166 |
155 if (t <= new_end) { | 167 if (t <= new_end) { |
156 var end_offset = %DateDaylightSavingsOffset(EquivalentTime(new_end)); | 168 var end_offset = %DateDaylightSavingsOffset(EquivalentTime(new_end)); |
157 if (cache.offset == end_offset) { | 169 if (cache.offset == end_offset) { |
158 // If the offset at the end of the new interval still matches | 170 // If the offset at the end of the new interval still matches |
159 // the offset in the cache, we grow the cached time interval | 171 // the offset in the cache, we grow the cached time interval |
160 // and return the offset. | 172 // and return the offset. |
161 cache.end = new_end; | 173 cache.end = new_end; |
(...skipping 16 matching lines...) Expand all Loading... |
178 cache.increment /= 3; | 190 cache.increment /= 3; |
179 cache.end = t; | 191 cache.end = t; |
180 } | 192 } |
181 // Update the offset in the cache and return it. | 193 // Update the offset in the cache and return it. |
182 cache.offset = offset; | 194 cache.offset = offset; |
183 return offset; | 195 return offset; |
184 } | 196 } |
185 } | 197 } |
186 } | 198 } |
187 | 199 |
| 200 // If the cache misses, the local_time_offset may not be initialized. |
| 201 if (IS_UNDEFINED(local_time_offset)) { |
| 202 local_time_offset = %DateLocalTimeOffset(); |
| 203 } |
188 // Compute the DST offset for the time and shrink the cache interval | 204 // Compute the DST offset for the time and shrink the cache interval |
189 // to only contain the time. This allows fast repeated DST offset | 205 // to only contain the time. This allows fast repeated DST offset |
190 // computations for the same time. | 206 // computations for the same time. |
191 var offset = %DateDaylightSavingsOffset(EquivalentTime(t)); | 207 var offset = %DateDaylightSavingsOffset(EquivalentTime(t)); |
192 cache.offset = offset; | 208 cache.offset = offset; |
193 cache.start = cache.end = t; | 209 cache.start = cache.end = t; |
194 cache.increment = msPerMonth; | 210 cache.increment = msPerMonth; |
195 return offset; | 211 return offset; |
196 } | 212 } |
197 | 213 |
(...skipping 10 matching lines...) Expand all Loading... |
208 timezone_cache_time = t; | 224 timezone_cache_time = t; |
209 timezone_cache_timezone = timezone; | 225 timezone_cache_timezone = timezone; |
210 return timezone; | 226 return timezone; |
211 } | 227 } |
212 | 228 |
213 | 229 |
214 function WeekDay(time) { | 230 function WeekDay(time) { |
215 return Modulo(DAY(time) + 4, 7); | 231 return Modulo(DAY(time) + 4, 7); |
216 } | 232 } |
217 | 233 |
218 var local_time_offset = %DateLocalTimeOffset(); | |
219 | 234 |
220 function LocalTime(time) { | 235 function LocalTime(time) { |
221 if (NUMBER_IS_NAN(time)) return time; | 236 if (NUMBER_IS_NAN(time)) return time; |
222 return time + local_time_offset + DaylightSavingsOffset(time); | 237 // DaylightSavingsOffset called before local_time_offset used. |
| 238 return time + DaylightSavingsOffset(time) + local_time_offset; |
223 } | 239 } |
224 | 240 |
225 function LocalTimeNoCheck(time) { | 241 function LocalTimeNoCheck(time) { |
226 // Inline the DST offset cache checks for speed. | 242 // Inline the DST offset cache checks for speed. |
| 243 // The cache is hit, or DaylightSavingsOffset is called, |
| 244 // before local_time_offset is used. |
227 var cache = DST_offset_cache; | 245 var cache = DST_offset_cache; |
228 if (cache.start <= time && time <= cache.end) { | 246 if (cache.start <= time && time <= cache.end) { |
229 var dst_offset = cache.offset; | 247 var dst_offset = cache.offset; |
230 } else { | 248 } else { |
231 var dst_offset = DaylightSavingsOffset(time); | 249 var dst_offset = DaylightSavingsOffset(time); |
232 } | 250 } |
233 return time + local_time_offset + dst_offset; | 251 return time + local_time_offset + dst_offset; |
234 } | 252 } |
235 | 253 |
236 | 254 |
237 function UTC(time) { | 255 function UTC(time) { |
238 if (NUMBER_IS_NAN(time)) return time; | 256 if (NUMBER_IS_NAN(time)) return time; |
| 257 // local_time_offset is needed before the call to DaylightSavingsOffset, |
| 258 // so it may be uninitialized. |
| 259 if (IS_UNDEFINED(local_time_offset)) { |
| 260 local_time_offset = %DateLocalTimeOffset(); |
| 261 } |
239 var tmp = time - local_time_offset; | 262 var tmp = time - local_time_offset; |
240 return tmp - DaylightSavingsOffset(tmp); | 263 return tmp - DaylightSavingsOffset(tmp); |
241 } | 264 } |
242 | 265 |
243 | 266 |
244 // ECMA 262 - 15.9.1.11 | 267 // ECMA 262 - 15.9.1.11 |
245 function MakeTime(hour, min, sec, ms) { | 268 function MakeTime(hour, min, sec, ms) { |
246 if (!$isFinite(hour)) return $NaN; | 269 if (!$isFinite(hour)) return $NaN; |
247 if (!$isFinite(min)) return $NaN; | 270 if (!$isFinite(min)) return $NaN; |
248 if (!$isFinite(sec)) return $NaN; | 271 if (!$isFinite(sec)) return $NaN; |
(...skipping 308 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
557 | 580 |
558 | 581 |
559 function TimeString(time) { | 582 function TimeString(time) { |
560 return TwoDigitString(HOUR_FROM_TIME(time)) + ':' | 583 return TwoDigitString(HOUR_FROM_TIME(time)) + ':' |
561 + TwoDigitString(MIN_FROM_TIME(time)) + ':' | 584 + TwoDigitString(MIN_FROM_TIME(time)) + ':' |
562 + TwoDigitString(SEC_FROM_TIME(time)); | 585 + TwoDigitString(SEC_FROM_TIME(time)); |
563 } | 586 } |
564 | 587 |
565 | 588 |
566 function LocalTimezoneString(time) { | 589 function LocalTimezoneString(time) { |
| 590 var old_timezone = timezone_cache_timezone; |
| 591 var timezone = LocalTimezone(time); |
| 592 if (old_timezone && timezone != old_timezone) { |
| 593 // If the timezone string has changed from the one that we cached, |
| 594 // the local time offset may now be wrong. So we need to update it |
| 595 // and try again. |
| 596 local_time_offset = %DateLocalTimeOffset(); |
| 597 // We also need to invalidate the DST cache as the new timezone may have |
| 598 // different DST times. |
| 599 var dst_cache = DST_offset_cache; |
| 600 dst_cache.start = 0; |
| 601 dst_cache.end = -1; |
| 602 } |
| 603 |
567 var timezoneOffset = | 604 var timezoneOffset = |
568 (local_time_offset + DaylightSavingsOffset(time)) / msPerMinute; | 605 (DaylightSavingsOffset(time) + local_time_offset) / msPerMinute; |
569 var sign = (timezoneOffset >= 0) ? 1 : -1; | 606 var sign = (timezoneOffset >= 0) ? 1 : -1; |
570 var hours = FLOOR((sign * timezoneOffset)/60); | 607 var hours = FLOOR((sign * timezoneOffset)/60); |
571 var min = FLOOR((sign * timezoneOffset)%60); | 608 var min = FLOOR((sign * timezoneOffset)%60); |
572 var gmt = ' GMT' + ((sign == 1) ? '+' : '-') + | 609 var gmt = ' GMT' + ((sign == 1) ? '+' : '-') + |
573 TwoDigitString(hours) + TwoDigitString(min); | 610 TwoDigitString(hours) + TwoDigitString(min); |
574 return gmt + ' (' + LocalTimezone(time) + ')'; | 611 return gmt + ' (' + timezone + ')'; |
575 } | 612 } |
576 | 613 |
577 | 614 |
578 function DatePrintString(time) { | 615 function DatePrintString(time) { |
579 return DateString(time) + ' ' + TimeString(time); | 616 return DateString(time) + ' ' + TimeString(time); |
580 } | 617 } |
581 | 618 |
582 // ------------------------------------------------------------------- | 619 // ------------------------------------------------------------------- |
583 | 620 |
584 // Reused output buffer. Used when parsing date strings. | 621 // Reused output buffer. Used when parsing date strings. |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
623 // elapsed since 1 January 1970 00:00:00 UTC. | 660 // elapsed since 1 January 1970 00:00:00 UTC. |
624 function DateNow() { | 661 function DateNow() { |
625 return %DateCurrentTime(); | 662 return %DateCurrentTime(); |
626 } | 663 } |
627 | 664 |
628 | 665 |
629 // ECMA 262 - 15.9.5.2 | 666 // ECMA 262 - 15.9.5.2 |
630 function DateToString() { | 667 function DateToString() { |
631 var t = DATE_VALUE(this); | 668 var t = DATE_VALUE(this); |
632 if (NUMBER_IS_NAN(t)) return kInvalidDate; | 669 if (NUMBER_IS_NAN(t)) return kInvalidDate; |
633 return DatePrintString(LocalTimeNoCheck(t)) + LocalTimezoneString(t); | 670 var time_zone_string = LocalTimezoneString(t); // May update local offset. |
| 671 return DatePrintString(LocalTimeNoCheck(t)) + time_zone_string; |
634 } | 672 } |
635 | 673 |
636 | 674 |
637 // ECMA 262 - 15.9.5.3 | 675 // ECMA 262 - 15.9.5.3 |
638 function DateToDateString() { | 676 function DateToDateString() { |
639 var t = DATE_VALUE(this); | 677 var t = DATE_VALUE(this); |
640 if (NUMBER_IS_NAN(t)) return kInvalidDate; | 678 if (NUMBER_IS_NAN(t)) return kInvalidDate; |
641 return DateString(LocalTimeNoCheck(t)); | 679 return DateString(LocalTimeNoCheck(t)); |
642 } | 680 } |
643 | 681 |
644 | 682 |
645 // ECMA 262 - 15.9.5.4 | 683 // ECMA 262 - 15.9.5.4 |
646 function DateToTimeString() { | 684 function DateToTimeString() { |
647 var t = DATE_VALUE(this); | 685 var t = DATE_VALUE(this); |
648 if (NUMBER_IS_NAN(t)) return kInvalidDate; | 686 if (NUMBER_IS_NAN(t)) return kInvalidDate; |
649 var lt = LocalTimeNoCheck(t); | 687 var time_zone_string = LocalTimezoneString(t); // May update local offset. |
650 return TimeString(lt) + LocalTimezoneString(lt); | 688 return TimeString(LocalTimeNoCheck(t)) + time_zone_string; |
651 } | 689 } |
652 | 690 |
653 | 691 |
654 // ECMA 262 - 15.9.5.5 | 692 // ECMA 262 - 15.9.5.5 |
655 function DateToLocaleString() { | 693 function DateToLocaleString() { |
656 return DateToString.call(this); | 694 return DateToString.call(this); |
657 } | 695 } |
658 | 696 |
659 | 697 |
660 // ECMA 262 - 15.9.5.6 | 698 // ECMA 262 - 15.9.5.6 |
(...skipping 419 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1080 "toGMTString", DateToGMTString, | 1118 "toGMTString", DateToGMTString, |
1081 "toUTCString", DateToUTCString, | 1119 "toUTCString", DateToUTCString, |
1082 "getYear", DateGetYear, | 1120 "getYear", DateGetYear, |
1083 "setYear", DateSetYear, | 1121 "setYear", DateSetYear, |
1084 "toISOString", DateToISOString, | 1122 "toISOString", DateToISOString, |
1085 "toJSON", DateToJSON | 1123 "toJSON", DateToJSON |
1086 )); | 1124 )); |
1087 } | 1125 } |
1088 | 1126 |
1089 SetupDate(); | 1127 SetupDate(); |
OLD | NEW |