OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 // Dart core library. | 4 // Dart core library. |
5 | 5 |
6 // VM implementation of DateTime. | 6 // VM implementation of DateTime. |
7 patch class DateTime { | 7 patch class DateTime { |
8 // Natives. | 8 // Natives. |
9 // The natives have been moved up here to work around Issue 10401. | 9 // The natives have been moved up here to work around Issue 10401. |
10 static int _getCurrentMs() native "DateNatives_currentTimeMillis"; | 10 static int _getCurrentMicros() native "DateTime_currentTimeMicros"; |
11 | 11 |
12 static String _timeZoneNameForClampedSeconds(int secondsSinceEpoch) | 12 static String _timeZoneNameForClampedSeconds(int secondsSinceEpoch) |
13 native "DateNatives_timeZoneName"; | 13 native "DateTime_timeZoneName"; |
14 | 14 |
15 static int _timeZoneOffsetInSecondsForClampedSeconds(int secondsSinceEpoch) | 15 static int _timeZoneOffsetInSecondsForClampedSeconds(int secondsSinceEpoch) |
16 native "DateNatives_timeZoneOffsetInSeconds"; | 16 native "DateTime_timeZoneOffsetInSeconds"; |
17 | 17 |
18 static int _localTimeZoneAdjustmentInSeconds() | 18 static int _localTimeZoneAdjustmentInSeconds() |
19 native "DateNatives_localTimeZoneAdjustmentInSeconds"; | 19 native "DateTime_localTimeZoneAdjustmentInSeconds"; |
20 | 20 |
21 static const _MILLISECOND_INDEX = 0; | 21 static const _MICROSECOND_INDEX = 0; |
22 static const _SECOND_INDEX = 1; | 22 static const _MILLISECOND_INDEX = 1; |
23 static const _MINUTE_INDEX = 2; | 23 static const _SECOND_INDEX = 2; |
24 static const _HOUR_INDEX = 3; | 24 static const _MINUTE_INDEX = 3; |
25 static const _DAY_INDEX = 4; | 25 static const _HOUR_INDEX = 4; |
26 static const _WEEKDAY_INDEX = 5; | 26 static const _DAY_INDEX = 5; |
27 static const _MONTH_INDEX = 6; | 27 static const _WEEKDAY_INDEX = 6; |
28 static const _YEAR_INDEX = 7; | 28 static const _MONTH_INDEX = 7; |
| 29 static const _YEAR_INDEX = 8; |
29 | 30 |
30 List __parts; | 31 List __parts; |
31 | 32 |
| 33 /* patch */ DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch, |
| 34 {bool isUtc: false}) |
| 35 : this._withValue( |
| 36 millisecondsSinceEpoch * Duration.MICROSECONDS_PER_MILLISECOND, |
| 37 isUtc: isUtc); |
| 38 |
| 39 /* patch */ DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch, |
| 40 {bool isUtc: false}) |
| 41 : this._withValue(microsecondsSinceEpoch, isUtc: isUtc); |
| 42 |
32 /* patch */ DateTime._internal(int year, | 43 /* patch */ DateTime._internal(int year, |
33 int month, | 44 int month, |
34 int day, | 45 int day, |
35 int hour, | 46 int hour, |
36 int minute, | 47 int minute, |
37 int second, | 48 int second, |
38 int millisecond, | 49 int millisecond, |
| 50 int microsecond, |
39 bool isUtc) | 51 bool isUtc) |
40 : this.isUtc = isUtc, | 52 : this.isUtc = isUtc, |
41 this.millisecondsSinceEpoch = _brokenDownDateToMillisecondsSinceEpoch( | 53 this._value = _brokenDownDateToValue( |
42 year, month, day, hour, minute, second, millisecond, isUtc) { | 54 year, month, day, hour, minute, second, millisecond, microsecond, |
43 if (millisecondsSinceEpoch == null) throw new ArgumentError(); | 55 isUtc) { |
| 56 if (_value == null) throw new ArgumentError(); |
44 if (isUtc == null) throw new ArgumentError(); | 57 if (isUtc == null) throw new ArgumentError(); |
45 } | 58 } |
46 | 59 |
47 /* patch */ DateTime._now() | 60 /* patch */ DateTime._now() |
48 : isUtc = false, | 61 : isUtc = false, |
49 millisecondsSinceEpoch = _getCurrentMs() { | 62 _value = _getCurrentMicros() { |
50 } | 63 } |
51 | 64 |
52 /* patch */ String get timeZoneName { | 65 /* patch */ String get timeZoneName { |
53 if (isUtc) return "UTC"; | 66 if (isUtc) return "UTC"; |
54 return _timeZoneName(millisecondsSinceEpoch); | 67 return _timeZoneName(microsecondsSinceEpoch); |
55 } | 68 } |
56 | 69 |
57 /* patch */ Duration get timeZoneOffset { | 70 /* patch */ Duration get timeZoneOffset { |
58 if (isUtc) return new Duration(); | 71 if (isUtc) return new Duration(); |
59 int offsetInSeconds = _timeZoneOffsetInSeconds(millisecondsSinceEpoch); | 72 int offsetInSeconds = _timeZoneOffsetInSeconds(microsecondsSinceEpoch); |
60 return new Duration(seconds: offsetInSeconds); | 73 return new Duration(seconds: offsetInSeconds); |
61 } | 74 } |
62 | 75 |
63 /** The first list contains the days until each month in non-leap years. The | 76 /** The first list contains the days until each month in non-leap years. The |
64 * second list contains the days in leap years. */ | 77 * second list contains the days in leap years. */ |
65 static const List<List<int>> _DAYS_UNTIL_MONTH = | 78 static const List<List<int>> _DAYS_UNTIL_MONTH = |
66 const [const [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], | 79 const [const [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334], |
67 const [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]]; | 80 const [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]]; |
68 | 81 |
69 static List _computeUpperPart(int localMs) { | 82 static List _computeUpperPart(int localMicros) { |
70 const int DAYS_IN_4_YEARS = 4 * 365 + 1; | 83 const int DAYS_IN_4_YEARS = 4 * 365 + 1; |
71 const int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1; | 84 const int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1; |
72 const int DAYS_IN_400_YEARS = 4 * DAYS_IN_100_YEARS + 1; | 85 const int DAYS_IN_400_YEARS = 4 * DAYS_IN_100_YEARS + 1; |
73 const int DAYS_1970_TO_2000 = 30 * 365 + 7; | 86 const int DAYS_1970_TO_2000 = 30 * 365 + 7; |
74 const int DAYS_OFFSET = 1000 * DAYS_IN_400_YEARS + 5 * DAYS_IN_400_YEARS - | 87 const int DAYS_OFFSET = 1000 * DAYS_IN_400_YEARS + 5 * DAYS_IN_400_YEARS - |
75 DAYS_1970_TO_2000; | 88 DAYS_1970_TO_2000; |
76 const int YEARS_OFFSET = 400000; | 89 const int YEARS_OFFSET = 400000; |
77 | 90 |
78 int resultYear = 0; | 91 int resultYear = 0; |
79 int resultMonth = 0; | 92 int resultMonth = 0; |
80 int resultDay = 0; | 93 int resultDay = 0; |
81 | 94 |
82 // Always round down. | 95 // Always round down. |
83 final int daysSince1970 = _flooredDivision(localMs, | 96 final int daysSince1970 = _flooredDivision(localMicros, |
84 Duration.MILLISECONDS_PER_DAY); | 97 Duration.MICROSECONDS_PER_DAY); |
85 int days = daysSince1970; | 98 int days = daysSince1970; |
86 days += DAYS_OFFSET; | 99 days += DAYS_OFFSET; |
87 resultYear = 400 * (days ~/ DAYS_IN_400_YEARS) - YEARS_OFFSET; | 100 resultYear = 400 * (days ~/ DAYS_IN_400_YEARS) - YEARS_OFFSET; |
88 days = days.remainder(DAYS_IN_400_YEARS); | 101 days = days.remainder(DAYS_IN_400_YEARS); |
89 days--; | 102 days--; |
90 int yd1 = days ~/ DAYS_IN_100_YEARS; | 103 int yd1 = days ~/ DAYS_IN_100_YEARS; |
91 days = days.remainder(DAYS_IN_100_YEARS); | 104 days = days.remainder(DAYS_IN_100_YEARS); |
92 resultYear += 100 * yd1; | 105 resultYear += 100 * yd1; |
93 days++; | 106 days++; |
94 int yd2 = days ~/ DAYS_IN_4_YEARS; | 107 int yd2 = days ~/ DAYS_IN_4_YEARS; |
95 days = days.remainder(DAYS_IN_4_YEARS); | 108 days = days.remainder(DAYS_IN_4_YEARS); |
96 resultYear += 4 * yd2; | 109 resultYear += 4 * yd2; |
97 days--; | 110 days--; |
98 int yd3 = days ~/ 365; | 111 int yd3 = days ~/ 365; |
99 days = days.remainder(365); | 112 days = days.remainder(365); |
100 resultYear += yd3; | 113 resultYear += yd3; |
101 | 114 |
102 bool isLeap = (yd1 == 0 || yd2 != 0) && yd3 == 0; | 115 bool isLeap = (yd1 == 0 || yd2 != 0) && yd3 == 0; |
103 if (isLeap) days++; | 116 if (isLeap) days++; |
104 | 117 |
105 List<int> daysUntilMonth = _DAYS_UNTIL_MONTH[isLeap ? 1 : 0]; | 118 List<int> daysUntilMonth = _DAYS_UNTIL_MONTH[isLeap ? 1 : 0]; |
106 for (resultMonth = 12; | 119 for (resultMonth = 12; |
107 daysUntilMonth[resultMonth - 1] > days; | 120 daysUntilMonth[resultMonth - 1] > days; |
108 resultMonth--) { | 121 resultMonth--) { |
109 // Do nothing. | 122 // Do nothing. |
110 } | 123 } |
111 resultDay = days - daysUntilMonth[resultMonth - 1] + 1; | 124 resultDay = days - daysUntilMonth[resultMonth - 1] + 1; |
112 | 125 |
113 int resultMillisecond = localMs % Duration.MILLISECONDS_PER_SECOND; | 126 int resultMicrosecond = localMicros % Duration.MICROSECONDS_PER_MILLISECOND; |
| 127 int resultMillisecond = |
| 128 _flooredDivision(localMicros, Duration.MICROSECONDS_PER_MILLISECOND) % |
| 129 Duration.MILLISECONDS_PER_SECOND; |
114 int resultSecond = | 130 int resultSecond = |
115 _flooredDivision(localMs, Duration.MILLISECONDS_PER_SECOND) % | 131 _flooredDivision(localMicros, Duration.MICROSECONDS_PER_SECOND) % |
116 Duration.SECONDS_PER_MINUTE; | 132 Duration.SECONDS_PER_MINUTE; |
117 | 133 |
118 int resultMinute = _flooredDivision(localMs, | 134 int resultMinute = _flooredDivision(localMicros, |
119 Duration.MILLISECONDS_PER_MINUTE); | 135 Duration.MICROSECONDS_PER_MINUTE); |
120 resultMinute %= Duration.MINUTES_PER_HOUR; | 136 resultMinute %= Duration.MINUTES_PER_HOUR; |
121 | 137 |
122 int resultHour = _flooredDivision(localMs, Duration.MILLISECONDS_PER_HOUR); | 138 int resultHour = |
| 139 _flooredDivision(localMicros, Duration.MICROSECONDS_PER_HOUR); |
123 resultHour %= Duration.HOURS_PER_DAY; | 140 resultHour %= Duration.HOURS_PER_DAY; |
124 | 141 |
125 // In accordance with ISO 8601 a week | 142 // In accordance with ISO 8601 a week |
126 // starts with Monday. Monday has the value 1 up to Sunday with 7. | 143 // starts with Monday. Monday has the value 1 up to Sunday with 7. |
127 // 1970-1-1 was a Thursday. | 144 // 1970-1-1 was a Thursday. |
128 int resultWeekday = ((daysSince1970 + DateTime.THURSDAY - DateTime.MONDAY) % | 145 int resultWeekday = ((daysSince1970 + DateTime.THURSDAY - DateTime.MONDAY) % |
129 DateTime.DAYS_PER_WEEK) + DateTime.MONDAY; | 146 DateTime.DAYS_PER_WEEK) + DateTime.MONDAY; |
130 | 147 |
131 List list = new List(_YEAR_INDEX + 1); | 148 List list = new List(_YEAR_INDEX + 1); |
| 149 list[_MICROSECOND_INDEX] = resultMicrosecond; |
132 list[_MILLISECOND_INDEX] = resultMillisecond; | 150 list[_MILLISECOND_INDEX] = resultMillisecond; |
133 list[_SECOND_INDEX] = resultSecond; | 151 list[_SECOND_INDEX] = resultSecond; |
134 list[_MINUTE_INDEX] = resultMinute; | 152 list[_MINUTE_INDEX] = resultMinute; |
135 list[_HOUR_INDEX] = resultHour; | 153 list[_HOUR_INDEX] = resultHour; |
136 list[_DAY_INDEX] = resultDay; | 154 list[_DAY_INDEX] = resultDay; |
137 list[_WEEKDAY_INDEX] = resultWeekday; | 155 list[_WEEKDAY_INDEX] = resultWeekday; |
138 list[_MONTH_INDEX] = resultMonth; | 156 list[_MONTH_INDEX] = resultMonth; |
139 list[_YEAR_INDEX] = resultYear; | 157 list[_YEAR_INDEX] = resultYear; |
140 return list; | 158 return list; |
141 } | 159 } |
142 | 160 |
143 get _parts { | 161 get _parts { |
144 if (__parts == null) { | 162 if (__parts == null) { |
145 __parts = _computeUpperPart(_localDateInUtcMs); | 163 __parts = _computeUpperPart(_localDateInUtcMicros); |
146 } | 164 } |
147 return __parts; | 165 return __parts; |
148 } | 166 } |
149 | 167 |
| 168 /* patch */ DateTime add(Duration duration) { |
| 169 return new DateTime._withValue( |
| 170 _value + duration.inMicroseconds, isUtc: isUtc); |
| 171 } |
| 172 |
| 173 /* patch */ DateTime subtract(Duration duration) { |
| 174 return new DateTime._withValue( |
| 175 _value - duration.inMicroseconds, isUtc: isUtc); |
| 176 } |
| 177 |
| 178 /* patch */ Duration difference(DateTime other) { |
| 179 return new Duration(microseconds: _value - other._value); |
| 180 } |
| 181 |
| 182 /* patch */ int get millisecondsSinceEpoch => |
| 183 _value ~/ Duration.MICROSECONDS_PER_MILLISECOND; |
| 184 |
| 185 /* patch */ int get microsecondsSinceEpoch => _value; |
| 186 |
| 187 /* patch */ int get microsecond => _parts[_MICROSECOND_INDEX]; |
| 188 |
150 /* patch */ int get millisecond => _parts[_MILLISECOND_INDEX]; | 189 /* patch */ int get millisecond => _parts[_MILLISECOND_INDEX]; |
151 | 190 |
152 /* patch */ int get second => _parts[_SECOND_INDEX]; | 191 /* patch */ int get second => _parts[_SECOND_INDEX]; |
153 | 192 |
154 /* patch */ int get minute => _parts[_MINUTE_INDEX]; | 193 /* patch */ int get minute => _parts[_MINUTE_INDEX]; |
155 | 194 |
156 /* patch */ int get hour => _parts[_HOUR_INDEX]; | 195 /* patch */ int get hour => _parts[_HOUR_INDEX]; |
157 | 196 |
158 /* patch */ int get day => _parts[_DAY_INDEX]; | 197 /* patch */ int get day => _parts[_DAY_INDEX]; |
159 | 198 |
160 /* patch */ int get weekday => _parts[_WEEKDAY_INDEX]; | 199 /* patch */ int get weekday => _parts[_WEEKDAY_INDEX]; |
161 | 200 |
162 /* patch */ int get month => _parts[_MONTH_INDEX]; | 201 /* patch */ int get month => _parts[_MONTH_INDEX]; |
163 | 202 |
164 /* patch */ int get year => _parts[_YEAR_INDEX]; | 203 /* patch */ int get year => _parts[_YEAR_INDEX]; |
165 | 204 |
166 /** | 205 /** |
167 * Returns the amount of milliseconds in UTC that represent the same values | 206 * Returns the amount of microseconds in UTC that represent the same values |
168 * as [this]. | 207 * as [this]. |
169 * | 208 * |
170 * Say [:t:] is the result of this function, then | 209 * Say `t` is the result of this function, then |
171 * * [:this.year == new DateTime.fromMillisecondsSinceEpoch(t, true).year:], | 210 * * `this.year == new DateTime.fromMicrosecondsSinceEpoch(t, true).year`, |
172 * * [:this.month == new DateTime.fromMillisecondsSinceEpoch(t, true).month:], | 211 * * `this.month == new DateTime.fromMicrosecondsSinceEpoch(t, true).month`, |
173 * * [:this.day == new DateTime.fromMillisecondsSinceEpoch(t, true).day:], | 212 * * `this.day == new DateTime.fromMicrosecondsSinceEpoch(t, true).day`, |
174 * * [:this.hour == new DateTime.fromMillisecondsSinceEpoch(t, true).hour:], | 213 * * `this.hour == new DateTime.fromMicrosecondsSinceEpoch(t, true).hour`, |
175 * * ... | 214 * * ... |
176 * | 215 * |
177 * Daylight savings is computed as if the date was computed in [1970..2037]. | 216 * Daylight savings is computed as if the date was computed in [1970..2037]. |
178 * If [this] lies outside this range then it is a year with similar | 217 * If [this] lies outside this range then it is a year with similar |
179 * properties (leap year, weekdays) is used instead. | 218 * properties (leap year, weekdays) is used instead. |
180 */ | 219 */ |
181 int get _localDateInUtcMs { | 220 int get _localDateInUtcMicros { |
182 int ms = millisecondsSinceEpoch; | 221 int micros = _value; |
183 if (isUtc) return ms; | 222 if (isUtc) return micros; |
184 int offset = | 223 int offset = |
185 _timeZoneOffsetInSeconds(ms) * Duration.MILLISECONDS_PER_SECOND; | 224 _timeZoneOffsetInSeconds(micros) * Duration.MICROSECONDS_PER_SECOND; |
186 return ms + offset; | 225 return micros + offset; |
187 } | 226 } |
188 | 227 |
189 static int _flooredDivision(int a, int b) { | 228 static int _flooredDivision(int a, int b) { |
190 return (a - (a < 0 ? b - 1 : 0)) ~/ b; | 229 return (a - (a < 0 ? b - 1 : 0)) ~/ b; |
191 } | 230 } |
192 | 231 |
193 // Returns the days since 1970 for the start of the given [year]. | 232 // Returns the days since 1970 for the start of the given [year]. |
194 // [year] may be before epoch. | 233 // [year] may be before epoch. |
195 static int _dayFromYear(int year) { | 234 static int _dayFromYear(int year) { |
196 return 365 * (year - 1970) | 235 return 365 * (year - 1970) |
197 + _flooredDivision(year - 1969, 4) | 236 + _flooredDivision(year - 1969, 4) |
198 - _flooredDivision(year - 1901, 100) | 237 - _flooredDivision(year - 1901, 100) |
199 + _flooredDivision(year - 1601, 400); | 238 + _flooredDivision(year - 1601, 400); |
200 } | 239 } |
201 | 240 |
202 static bool _isLeapYear(y) { | 241 static bool _isLeapYear(y) { |
203 // (y % 16 == 0) matches multiples of 400, and is faster than % 400. | 242 // (y % 16 == 0) matches multiples of 400, and is faster than % 400. |
204 return (y % 4 == 0) && ((y % 16 == 0) || (y % 100 != 0)); | 243 return (y % 4 == 0) && ((y % 16 == 0) || (y % 100 != 0)); |
205 } | 244 } |
206 | 245 |
207 /* patch */ static int _brokenDownDateToMillisecondsSinceEpoch( | 246 /// Converts the given broken down date to microseconds. |
| 247 /* patch */ static int _brokenDownDateToValue( |
208 int year, int month, int day, | 248 int year, int month, int day, |
209 int hour, int minute, int second, int millisecond, | 249 int hour, int minute, int second, int millisecond, int microsecond, |
210 bool isUtc) { | 250 bool isUtc) { |
211 // Simplify calculations by working with zero-based month. | 251 // Simplify calculations by working with zero-based month. |
212 --month; | 252 --month; |
213 // Deal with under and overflow. | 253 // Deal with under and overflow. |
214 if (month >= 12) { | 254 if (month >= 12) { |
215 year += month ~/ 12; | 255 year += month ~/ 12; |
216 month = month % 12; | 256 month = month % 12; |
217 } else if (month < 0) { | 257 } else if (month < 0) { |
218 int realMonth = month % 12; | 258 int realMonth = month % 12; |
219 year += (month - realMonth) ~/ 12; | 259 year += (month - realMonth) ~/ 12; |
220 month = realMonth; | 260 month = realMonth; |
221 } | 261 } |
222 | 262 |
223 // First compute the seconds in UTC, independent of the [isUtc] flag. If | 263 // First compute the seconds in UTC, independent of the [isUtc] flag. If |
224 // necessary we will add the time-zone offset later on. | 264 // necessary we will add the time-zone offset later on. |
225 int days = day - 1; | 265 int days = day - 1; |
226 days += _DAYS_UNTIL_MONTH[_isLeapYear(year) ? 1 : 0][month]; | 266 days += _DAYS_UNTIL_MONTH[_isLeapYear(year) ? 1 : 0][month]; |
227 days += _dayFromYear(year); | 267 days += _dayFromYear(year); |
228 int millisecondsSinceEpoch = | 268 int microsecondsSinceEpoch = |
229 days * Duration.MILLISECONDS_PER_DAY + | 269 days * Duration.MICROSECONDS_PER_DAY + |
230 hour * Duration.MILLISECONDS_PER_HOUR + | 270 hour * Duration.MICROSECONDS_PER_HOUR + |
231 minute * Duration.MILLISECONDS_PER_MINUTE + | 271 minute * Duration.MICROSECONDS_PER_MINUTE + |
232 second * Duration.MILLISECONDS_PER_SECOND + | 272 second * Duration.MICROSECONDS_PER_SECOND + |
233 millisecond; | 273 millisecond * Duration.MICROSECONDS_PER_MILLISECOND + |
| 274 microsecond; |
234 | 275 |
235 // Since [_timeZoneOffsetInSeconds] will crash if the input is far out of | 276 // Since [_timeZoneOffsetInSeconds] will crash if the input is far out of |
236 // the valid range we do a preliminary test that weeds out values that can | 277 // the valid range we do a preliminary test that weeds out values that can |
237 // not become valid even with timezone adjustments. | 278 // not become valid even with timezone adjustments. |
238 // The timezone adjustment is always less than a day, so adding a security | 279 // The timezone adjustment is always less than a day, so adding a security |
239 // margin of one day should be enough. | 280 // margin of one day should be enough. |
240 if (millisecondsSinceEpoch.abs() > | 281 if (microsecondsSinceEpoch.abs() > |
241 (_MAX_MILLISECONDS_SINCE_EPOCH + Duration.MILLISECONDS_PER_DAY)) { | 282 _MAX_MILLISECONDS_SINCE_EPOCH * 1000 + Duration.MICROSECONDS_PER_DAY) { |
242 return null; | 283 return null; |
243 } | 284 } |
244 | 285 |
245 if (!isUtc) { | 286 if (!isUtc) { |
246 // Note that we need to remove the local timezone adjustement before | 287 // Note that we need to remove the local timezone adjustement before |
247 // asking for the correct zone offset. | 288 // asking for the correct zone offset. |
248 int adjustment = _localTimeZoneAdjustmentInSeconds() * | 289 int adjustment = _localTimeZoneAdjustmentInSeconds() * |
249 Duration.MILLISECONDS_PER_SECOND; | 290 Duration.MICROSECONDS_PER_SECOND; |
| 291 |
250 int zoneOffset = | 292 int zoneOffset = |
251 _timeZoneOffsetInSeconds(millisecondsSinceEpoch - adjustment); | 293 _timeZoneOffsetInSeconds(microsecondsSinceEpoch - adjustment); |
252 millisecondsSinceEpoch -= zoneOffset * Duration.MILLISECONDS_PER_SECOND; | 294 microsecondsSinceEpoch -= zoneOffset * Duration.MICROSECONDS_PER_SECOND; |
253 } | 295 } |
254 if (millisecondsSinceEpoch.abs() > _MAX_MILLISECONDS_SINCE_EPOCH) { | 296 if (microsecondsSinceEpoch.abs() > |
| 297 _MAX_MILLISECONDS_SINCE_EPOCH * Duration.MICROSECONDS_PER_MILLISECOND) { |
255 return null; | 298 return null; |
256 } | 299 } |
257 return millisecondsSinceEpoch; | 300 return microsecondsSinceEpoch; |
258 } | 301 } |
259 | 302 |
260 static int _weekDay(y) { | 303 static int _weekDay(y) { |
261 // 1/1/1970 was a Thursday. | 304 // 1/1/1970 was a Thursday. |
262 return (_dayFromYear(y) + 4) % 7; | 305 return (_dayFromYear(y) + 4) % 7; |
263 } | 306 } |
264 | 307 |
265 /** | 308 /** |
266 * Returns a year in the range 2008-2035 matching | 309 * Returns a year in the range 2008-2035 matching |
267 * * leap year, and | 310 * * leap year, and |
(...skipping 29 matching lines...) Expand all Loading... |
297 static int _yearsFromSecondsSinceEpoch(int secondsSinceEpoch) { | 340 static int _yearsFromSecondsSinceEpoch(int secondsSinceEpoch) { |
298 const int DAYS_IN_4_YEARS = 4 * 365 + 1; | 341 const int DAYS_IN_4_YEARS = 4 * 365 + 1; |
299 const int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1; | 342 const int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1; |
300 const int DAYS_YEAR_2098 = DAYS_IN_100_YEARS + 6 * DAYS_IN_4_YEARS; | 343 const int DAYS_YEAR_2098 = DAYS_IN_100_YEARS + 6 * DAYS_IN_4_YEARS; |
301 | 344 |
302 int days = secondsSinceEpoch ~/ Duration.SECONDS_PER_DAY; | 345 int days = secondsSinceEpoch ~/ Duration.SECONDS_PER_DAY; |
303 if (days > 0 && days < DAYS_YEAR_2098) { | 346 if (days > 0 && days < DAYS_YEAR_2098) { |
304 // According to V8 this fast case works for dates from 1970 to 2099. | 347 // According to V8 this fast case works for dates from 1970 to 2099. |
305 return 1970 + (4 * days + 2) ~/ DAYS_IN_4_YEARS; | 348 return 1970 + (4 * days + 2) ~/ DAYS_IN_4_YEARS; |
306 } | 349 } |
307 int ms = secondsSinceEpoch * Duration.MILLISECONDS_PER_SECOND; | 350 int micros = secondsSinceEpoch * Duration.MICROSECONDS_PER_SECOND; |
308 return _computeUpperPart(ms)[_YEAR_INDEX]; | 351 return _computeUpperPart(micros)[_YEAR_INDEX]; |
309 } | 352 } |
310 | 353 |
311 /** | 354 /** |
312 * Returns a date in seconds that is equivalent to the current date. An | 355 * Returns a date in seconds that is equivalent to the current date. An |
313 * equivalent date has the same fields ([:month:], [:day:], etc.) as the | 356 * equivalent date has the same fields (`month`, `day`, etc.) as the |
314 * [this], but the [:year:] is in the range [1970..2037]. | 357 * [this], but the `year` is in the range [1970..2037]. |
315 * | 358 * |
316 * * The time since the beginning of the year is the same. | 359 * * The time since the beginning of the year is the same. |
317 * * If [this] is in a leap year then the returned seconds are in a leap | 360 * * If [this] is in a leap year then the returned seconds are in a leap |
318 * year, too. | 361 * year, too. |
319 * * The week day of [this] is the same as the one for the returned date. | 362 * * The week day of [this] is the same as the one for the returned date. |
320 */ | 363 */ |
321 static int _equivalentSeconds(int millisecondsSinceEpoch) { | 364 static int _equivalentSeconds(int microsecondsSinceEpoch) { |
322 const int CUT_OFF_SECONDS = 2100000000; | 365 const int CUT_OFF_SECONDS = 2100000000; |
323 | 366 |
324 int secondsSinceEpoch = _flooredDivision(millisecondsSinceEpoch, | 367 int secondsSinceEpoch = _flooredDivision(microsecondsSinceEpoch, |
325 Duration.MILLISECONDS_PER_SECOND); | 368 Duration.MICROSECONDS_PER_SECOND); |
326 | 369 |
327 if (secondsSinceEpoch < 0 || secondsSinceEpoch >= CUT_OFF_SECONDS) { | 370 if (secondsSinceEpoch < 0 || secondsSinceEpoch >= CUT_OFF_SECONDS) { |
328 int year = _yearsFromSecondsSinceEpoch(secondsSinceEpoch); | 371 int year = _yearsFromSecondsSinceEpoch(secondsSinceEpoch); |
329 int days = _dayFromYear(year); | 372 int days = _dayFromYear(year); |
330 int equivalentYear = _equivalentYear(year); | 373 int equivalentYear = _equivalentYear(year); |
331 int equivalentDays = _dayFromYear(equivalentYear); | 374 int equivalentDays = _dayFromYear(equivalentYear); |
332 int diffDays = equivalentDays - days; | 375 int diffDays = equivalentDays - days; |
333 secondsSinceEpoch += diffDays * Duration.SECONDS_PER_DAY; | 376 secondsSinceEpoch += diffDays * Duration.SECONDS_PER_DAY; |
334 } | 377 } |
335 return secondsSinceEpoch; | 378 return secondsSinceEpoch; |
336 } | 379 } |
337 | 380 |
338 static int _timeZoneOffsetInSeconds(int millisecondsSinceEpoch) { | 381 static int _timeZoneOffsetInSeconds(int microsecondsSinceEpoch) { |
339 int equivalentSeconds = _equivalentSeconds(millisecondsSinceEpoch); | 382 int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch); |
340 return _timeZoneOffsetInSecondsForClampedSeconds(equivalentSeconds); | 383 return _timeZoneOffsetInSecondsForClampedSeconds(equivalentSeconds); |
341 } | 384 } |
342 | 385 |
343 static String _timeZoneName(int millisecondsSinceEpoch) { | 386 static String _timeZoneName(int microsecondsSinceEpoch) { |
344 int equivalentSeconds = _equivalentSeconds(millisecondsSinceEpoch); | 387 int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch); |
345 return _timeZoneNameForClampedSeconds(equivalentSeconds); | 388 return _timeZoneNameForClampedSeconds(equivalentSeconds); |
346 } | 389 } |
347 } | 390 } |
OLD | NEW |