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 _getCurrentMicros() native "DateTime_currentTimeMicros"; | 10 static int _getCurrentMicros() native "DateTime_currentTimeMicros"; |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 // 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 |
278 // not become valid even with timezone adjustments. | 278 // not become valid even with timezone adjustments. |
279 // 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 |
280 // margin of one day should be enough. | 280 // margin of one day should be enough. |
281 if (microsecondsSinceEpoch.abs() > | 281 if (microsecondsSinceEpoch.abs() > |
282 _MAX_MILLISECONDS_SINCE_EPOCH * 1000 + Duration.MICROSECONDS_PER_DAY) { | 282 _MAX_MILLISECONDS_SINCE_EPOCH * 1000 + Duration.MICROSECONDS_PER_DAY) { |
283 return null; | 283 return null; |
284 } | 284 } |
285 | 285 |
286 if (!isUtc) { | 286 if (!isUtc) { |
287 // Note that we need to remove the local timezone adjustement before | 287 // Note that we need to remove the local timezone adjustment before |
288 // asking for the correct zone offset. | 288 // asking for the correct zone offset. |
289 int adjustment = _localTimeZoneAdjustmentInSeconds() * | 289 int adjustment = _localTimeZoneAdjustmentInSeconds() * |
290 Duration.MICROSECONDS_PER_SECOND; | 290 Duration.MICROSECONDS_PER_SECOND; |
| 291 // The adjustment is independent of the actual date and of the daylight |
| 292 // saving time. It is positive east of the Prime Meridian and negative |
| 293 // west of it, e.g. -28800000 for America/Los_Angeles timezone. |
291 | 294 |
292 int zoneOffset = | 295 int zoneOffset = |
293 _timeZoneOffsetInSeconds(microsecondsSinceEpoch - adjustment); | 296 _timeZoneOffsetInSeconds(microsecondsSinceEpoch - adjustment); |
| 297 // The zoneOffset depends on the actual date and reflects any daylight |
| 298 // saving time and/or historical deviation relative to UTC time. |
| 299 // It is positive east of the Prime Meridian and negative |
| 300 // west of it, e.g. -25200000 for America/Los_Angeles timezone during DST. |
294 microsecondsSinceEpoch -= zoneOffset * Duration.MICROSECONDS_PER_SECOND; | 301 microsecondsSinceEpoch -= zoneOffset * Duration.MICROSECONDS_PER_SECOND; |
295 } | 302 } |
296 if (microsecondsSinceEpoch.abs() > | 303 if (microsecondsSinceEpoch.abs() > |
297 _MAX_MILLISECONDS_SINCE_EPOCH * Duration.MICROSECONDS_PER_MILLISECOND) { | 304 _MAX_MILLISECONDS_SINCE_EPOCH * Duration.MICROSECONDS_PER_MILLISECOND) { |
298 return null; | 305 return null; |
299 } | 306 } |
300 return microsecondsSinceEpoch; | 307 return microsecondsSinceEpoch; |
301 } | 308 } |
302 | 309 |
303 static int _weekDay(y) { | 310 static int _weekDay(y) { |
304 // 1/1/1970 was a Thursday. | 311 // 1/1/1970 was a Thursday. |
305 return (_dayFromYear(y) + 4) % 7; | 312 return (_dayFromYear(y) + 4) % 7; |
306 } | 313 } |
307 | 314 |
308 /** | 315 /** |
309 * Returns a year in the range 2008-2035 matching | 316 * Returns a year in the range 2008-2035 matching |
310 * * leap year, and | 317 * * leap year, and |
311 * * week day of first day. | 318 * * week day of first day. |
312 * | 319 * |
313 * Leap seconds are ignored. | 320 * Leap seconds are ignored. |
314 * Adapted from V8's date implementation. See ECMA 262 - 15.9.1.9. | 321 * Adapted from V8's date implementation. See ECMA 262 - 15.9.1.9. |
315 */ | 322 */ |
316 static int _equivalentYear(int year) { | 323 static int _equivalentYear(int year) { |
317 // Returns the week day (in range 0 - 6). | 324 // Returns year y so that _weekDay(y) == _weekDay(year). |
| 325 // _weekDay returns the week day (in range 0 - 6). |
318 // 1/1/1956 was a Sunday (i.e. weekday 0). 1956 was a leap-year. | 326 // 1/1/1956 was a Sunday (i.e. weekday 0). 1956 was a leap-year. |
319 // 1/1/1967 was a Sunday (i.e. weekday 0). | 327 // 1/1/1967 was a Sunday (i.e. weekday 0). |
320 // Without leap years a subsequent year has a week day + 1 (for example | 328 // Without leap years a subsequent year has a week day + 1 (for example |
321 // 1/1/1968 was a Monday). With leap-years it jumps over one week day | 329 // 1/1/1968 was a Monday). With leap-years it jumps over one week day |
322 // (e.g. 1/1/1957 was a Tuesday). | 330 // (e.g. 1/1/1957 was a Tuesday). |
323 // After 12 years the weekdays have advanced by 12 days + 3 leap days = | 331 // After 12 years the weekdays have advanced by 12 days + 3 leap days = |
324 // 15 days. 15 % 7 = 1. So after 12 years the week day has always | 332 // 15 days. 15 % 7 = 1. So after 12 years the week day has always |
325 // (now independently of leap-years) advanced by one. | 333 // (now independently of leap-years) advanced by one. |
326 // weekDay * 12 gives thus a year starting with the wanted weekDay. | 334 // weekDay * 12 gives thus a year starting with the wanted weekDay. |
327 int recentYear = (_isLeapYear(year) ? 1956 : 1967) + (_weekDay(year) * 12); | 335 int recentYear = (_isLeapYear(year) ? 1956 : 1967) + (_weekDay(year) * 12); |
(...skipping 17 matching lines...) Expand all Loading... |
345 int days = secondsSinceEpoch ~/ Duration.SECONDS_PER_DAY; | 353 int days = secondsSinceEpoch ~/ Duration.SECONDS_PER_DAY; |
346 if (days > 0 && days < DAYS_YEAR_2098) { | 354 if (days > 0 && days < DAYS_YEAR_2098) { |
347 // According to V8 this fast case works for dates from 1970 to 2099. | 355 // According to V8 this fast case works for dates from 1970 to 2099. |
348 return 1970 + (4 * days + 2) ~/ DAYS_IN_4_YEARS; | 356 return 1970 + (4 * days + 2) ~/ DAYS_IN_4_YEARS; |
349 } | 357 } |
350 int micros = secondsSinceEpoch * Duration.MICROSECONDS_PER_SECOND; | 358 int micros = secondsSinceEpoch * Duration.MICROSECONDS_PER_SECOND; |
351 return _computeUpperPart(micros)[_YEAR_INDEX]; | 359 return _computeUpperPart(micros)[_YEAR_INDEX]; |
352 } | 360 } |
353 | 361 |
354 /** | 362 /** |
355 * Returns a date in seconds that is equivalent to the current date. An | 363 * Returns a date in seconds that is equivalent to the given |
356 * equivalent date has the same fields (`month`, `day`, etc.) as the | 364 * date in microseconds [microsecondsSinceEpoch]. An equivalent |
357 * [this], but the `year` is in the range [1970..2037]. | 365 * date has the same fields (`month`, `day`, etc.) as the given |
| 366 * date, but the `year` is in the range [1901..2038]. |
358 * | 367 * |
359 * * The time since the beginning of the year is the same. | 368 * * The time since the beginning of the year is the same. |
360 * * If [this] is in a leap year then the returned seconds are in a leap | 369 * * If the given date is in a leap year then the returned |
361 * year, too. | 370 * seconds are in a leap year, too. |
362 * * The week day of [this] is the same as the one for the returned date. | 371 * * The week day of given date is the same as the one for the |
| 372 * returned date. |
363 */ | 373 */ |
364 static int _equivalentSeconds(int microsecondsSinceEpoch) { | 374 static int _equivalentSeconds(int microsecondsSinceEpoch) { |
365 const int CUT_OFF_SECONDS = 2100000000; | 375 const int CUT_OFF_SECONDS = 0x7FFFFFFF; |
366 | 376 |
367 int secondsSinceEpoch = _flooredDivision(microsecondsSinceEpoch, | 377 int secondsSinceEpoch = _flooredDivision(microsecondsSinceEpoch, |
368 Duration.MICROSECONDS_PER_SECOND); | 378 Duration.MICROSECONDS_PER_SECOND); |
369 | 379 |
370 if (secondsSinceEpoch < 0 || secondsSinceEpoch >= CUT_OFF_SECONDS) { | 380 if (secondsSinceEpoch.abs() > CUT_OFF_SECONDS) { |
371 int year = _yearsFromSecondsSinceEpoch(secondsSinceEpoch); | 381 int year = _yearsFromSecondsSinceEpoch(secondsSinceEpoch); |
372 int days = _dayFromYear(year); | 382 int days = _dayFromYear(year); |
373 int equivalentYear = _equivalentYear(year); | 383 int equivalentYear = _equivalentYear(year); |
374 int equivalentDays = _dayFromYear(equivalentYear); | 384 int equivalentDays = _dayFromYear(equivalentYear); |
375 int diffDays = equivalentDays - days; | 385 int diffDays = equivalentDays - days; |
376 secondsSinceEpoch += diffDays * Duration.SECONDS_PER_DAY; | 386 secondsSinceEpoch += diffDays * Duration.SECONDS_PER_DAY; |
377 } | 387 } |
378 return secondsSinceEpoch; | 388 return secondsSinceEpoch; |
379 } | 389 } |
380 | 390 |
381 static int _timeZoneOffsetInSeconds(int microsecondsSinceEpoch) { | 391 static int _timeZoneOffsetInSeconds(int microsecondsSinceEpoch) { |
382 int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch); | 392 int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch); |
383 return _timeZoneOffsetInSecondsForClampedSeconds(equivalentSeconds); | 393 return _timeZoneOffsetInSecondsForClampedSeconds(equivalentSeconds); |
384 } | 394 } |
385 | 395 |
386 static String _timeZoneName(int microsecondsSinceEpoch) { | 396 static String _timeZoneName(int microsecondsSinceEpoch) { |
387 int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch); | 397 int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch); |
388 return _timeZoneNameForClampedSeconds(equivalentSeconds); | 398 return _timeZoneNameForClampedSeconds(equivalentSeconds); |
389 } | 399 } |
390 } | 400 } |
OLD | NEW |