| Index: runtime/lib/date_patch.dart
|
| diff --git a/runtime/lib/date_patch.dart b/runtime/lib/date_patch.dart
|
| index 6a09226ae620c2fa6fa86c9898e8a4eb8ae72241..48722e10f64af8c8d3f18f11b43c9b54c5ab3161 100644
|
| --- a/runtime/lib/date_patch.dart
|
| +++ b/runtime/lib/date_patch.dart
|
| @@ -10,15 +10,21 @@ class DateTime {
|
| // The natives have been moved up here to work around Issue 10401.
|
| static int _getCurrentMicros() native "DateTime_currentTimeMicros";
|
|
|
| - static String _timeZoneNameForClampedSeconds(int secondsSinceEpoch)
|
| + static String _timeZoneNameForSeconds(int secondsSinceEpoch)
|
| native "DateTime_timeZoneName";
|
|
|
| - static int _timeZoneOffsetInSecondsForClampedSeconds(int secondsSinceEpoch)
|
| + static int _timeZoneOffsetInSecondsForSeconds(int secondsSinceEpoch)
|
| native "DateTime_timeZoneOffsetInSeconds";
|
|
|
| static int _localTimeZoneAdjustmentInSeconds()
|
| native "DateTime_localTimeZoneAdjustmentInSeconds";
|
|
|
| + // Returns `null` if an error occurred.
|
| + static int
|
| + _brokenDownToSeconds(int year, int month, int day, int hour, int minute,
|
| + int second, bool isUtc)
|
| + native "DateTime_brokenDownToSeconds"; // Would use mktime or _mkgmtime/timegm
|
| +
|
| static const _MICROSECOND_INDEX = 0;
|
| static const _MILLISECOND_INDEX = 1;
|
| static const _SECOND_INDEX = 2;
|
| @@ -261,155 +267,23 @@ class DateTime {
|
| @patch
|
| static int _brokenDownDateToValue(int year, int month, int day, int hour,
|
| int minute, int second, int millisecond, int microsecond, bool isUtc) {
|
| - // Simplify calculations by working with zero-based month.
|
| - --month;
|
| - // Deal with under and overflow.
|
| - if (month >= 12) {
|
| - year += month ~/ 12;
|
| - month = month % 12;
|
| - } else if (month < 0) {
|
| - int realMonth = month % 12;
|
| - year += (month - realMonth) ~/ 12;
|
| - month = realMonth;
|
| - }
|
| -
|
| - // First compute the seconds in UTC, independent of the [isUtc] flag. If
|
| - // necessary we will add the time-zone offset later on.
|
| - int days = day - 1;
|
| - days += _DAYS_UNTIL_MONTH[_isLeapYear(year) ? 1 : 0][month];
|
| - days += _dayFromYear(year);
|
| - int microsecondsSinceEpoch = days * Duration.MICROSECONDS_PER_DAY +
|
| - hour * Duration.MICROSECONDS_PER_HOUR +
|
| - minute * Duration.MICROSECONDS_PER_MINUTE +
|
| - second * Duration.MICROSECONDS_PER_SECOND +
|
| - millisecond * Duration.MICROSECONDS_PER_MILLISECOND +
|
| - microsecond;
|
| -
|
| - // Since [_timeZoneOffsetInSeconds] will crash if the input is far out of
|
| - // the valid range we do a preliminary test that weeds out values that can
|
| - // not become valid even with timezone adjustments.
|
| - // The timezone adjustment is always less than a day, so adding a security
|
| - // margin of one day should be enough.
|
| - if (microsecondsSinceEpoch.abs() >
|
| - _MAX_MILLISECONDS_SINCE_EPOCH * 1000 + Duration.MICROSECONDS_PER_DAY) {
|
| - return null;
|
| - }
|
| -
|
| - if (!isUtc) {
|
| - // Note that we need to remove the local timezone adjustment before
|
| - // asking for the correct zone offset.
|
| - int adjustment = _localTimeZoneAdjustmentInSeconds() *
|
| - Duration.MICROSECONDS_PER_SECOND;
|
| - // The adjustment is independent of the actual date and of the daylight
|
| - // saving time. It is positive east of the Prime Meridian and negative
|
| - // west of it, e.g. -28800 sec for America/Los_Angeles timezone.
|
| -
|
| - int zoneOffset =
|
| - _timeZoneOffsetInSeconds(microsecondsSinceEpoch - adjustment);
|
| - // The zoneOffset depends on the actual date and reflects any daylight
|
| - // saving time and/or historical deviation relative to UTC time.
|
| - // It is positive east of the Prime Meridian and negative west of it,
|
| - // e.g. -25200 sec for America/Los_Angeles timezone during DST.
|
| - microsecondsSinceEpoch -= zoneOffset * Duration.MICROSECONDS_PER_SECOND;
|
| - // The resulting microsecondsSinceEpoch value is therefore the calculated
|
| - // UTC value decreased by a (positive if east of GMT) timezone adjustment
|
| - // and decreased by typically one hour if DST is in effect.
|
| - }
|
| - if (microsecondsSinceEpoch.abs() >
|
| - _MAX_MILLISECONDS_SINCE_EPOCH * Duration.MICROSECONDS_PER_MILLISECOND) {
|
| - return null;
|
| - }
|
| - return microsecondsSinceEpoch;
|
| - }
|
| -
|
| - static int _weekDay(y) {
|
| - // 1/1/1970 was a Thursday.
|
| - return (_dayFromYear(y) + 4) % 7;
|
| - }
|
| -
|
| - /**
|
| - * Returns a year in the range 2008-2035 matching
|
| - * * leap year, and
|
| - * * week day of first day.
|
| - *
|
| - * Leap seconds are ignored.
|
| - * Adapted from V8's date implementation. See ECMA 262 - 15.9.1.9.
|
| - */
|
| - static int _equivalentYear(int year) {
|
| - // Returns year y so that _weekDay(y) == _weekDay(year).
|
| - // _weekDay returns the week day (in range 0 - 6).
|
| - // 1/1/1956 was a Sunday (i.e. weekday 0). 1956 was a leap-year.
|
| - // 1/1/1967 was a Sunday (i.e. weekday 0).
|
| - // Without leap years a subsequent year has a week day + 1 (for example
|
| - // 1/1/1968 was a Monday). With leap-years it jumps over one week day
|
| - // (e.g. 1/1/1957 was a Tuesday).
|
| - // After 12 years the weekdays have advanced by 12 days + 3 leap days =
|
| - // 15 days. 15 % 7 = 1. So after 12 years the week day has always
|
| - // (now independently of leap-years) advanced by one.
|
| - // weekDay * 12 gives thus a year starting with the wanted weekDay.
|
| - int recentYear = (_isLeapYear(year) ? 1956 : 1967) + (_weekDay(year) * 12);
|
| - // Close to the year 2008 the calendar cycles every 4 * 7 years (4 for the
|
| - // leap years, 7 for the weekdays).
|
| - // Find the year in the range 2008..2037 that is equivalent mod 28.
|
| - return 2008 + (recentYear - 2008) % 28;
|
| - }
|
| -
|
| - /**
|
| - * Returns the UTC year for the corresponding [secondsSinceEpoch].
|
| - * It is relatively fast for values in the range 0 to year 2098.
|
| - *
|
| - * Code is adapted from V8.
|
| - */
|
| - static int _yearsFromSecondsSinceEpoch(int secondsSinceEpoch) {
|
| - const int DAYS_IN_4_YEARS = 4 * 365 + 1;
|
| - const int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1;
|
| - const int DAYS_YEAR_2098 = DAYS_IN_100_YEARS + 6 * DAYS_IN_4_YEARS;
|
| -
|
| - int days = secondsSinceEpoch ~/ Duration.SECONDS_PER_DAY;
|
| - if (days > 0 && days < DAYS_YEAR_2098) {
|
| - // According to V8 this fast case works for dates from 1970 to 2099.
|
| - return 1970 + (4 * days + 2) ~/ DAYS_IN_4_YEARS;
|
| - }
|
| - int micros = secondsSinceEpoch * Duration.MICROSECONDS_PER_SECOND;
|
| - return _computeUpperPart(micros)[_YEAR_INDEX];
|
| - }
|
| -
|
| - /**
|
| - * Returns a date in seconds that is equivalent to the given
|
| - * date in microseconds [microsecondsSinceEpoch]. An equivalent
|
| - * date has the same fields (`month`, `day`, etc.) as the given
|
| - * date, but the `year` is in the range [1901..2038].
|
| - *
|
| - * * The time since the beginning of the year is the same.
|
| - * * If the given date is in a leap year then the returned
|
| - * seconds are in a leap year, too.
|
| - * * The week day of given date is the same as the one for the
|
| - * returned date.
|
| - */
|
| - static int _equivalentSeconds(int microsecondsSinceEpoch) {
|
| - const int CUT_OFF_SECONDS = 0x7FFFFFFF;
|
| -
|
| - int secondsSinceEpoch = _flooredDivision(
|
| - microsecondsSinceEpoch, Duration.MICROSECONDS_PER_SECOND);
|
| -
|
| - if (secondsSinceEpoch.abs() > CUT_OFF_SECONDS) {
|
| - int year = _yearsFromSecondsSinceEpoch(secondsSinceEpoch);
|
| - int days = _dayFromYear(year);
|
| - int equivalentYear = _equivalentYear(year);
|
| - int equivalentDays = _dayFromYear(equivalentYear);
|
| - int diffDays = equivalentDays - days;
|
| - secondsSinceEpoch += diffDays * Duration.SECONDS_PER_DAY;
|
| - }
|
| - return secondsSinceEpoch;
|
| + var seconds =
|
| + _brokenDownToSeconds(year, month - 1, day, hour, minute, second, isUtc);
|
| + if (seconds == null) return null;
|
| + return seconds * Duration.MICROSECONDS_PER_SECOND +
|
| + milliseconds * Duration.MICROSECONDS_PER_MILLISECONDS +
|
| + microseconds;
|
| }
|
|
|
| static int _timeZoneOffsetInSeconds(int microsecondsSinceEpoch) {
|
| - int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch);
|
| - return _timeZoneOffsetInSecondsForClampedSeconds(equivalentSeconds);
|
| + int seconds = _flooredDivision(
|
| + microsecondsSinceEpoch, Duration.MICROSECONDS_PER_SECOND);
|
| + return _timeZoneOffsetInSecondsForSeconds(seconds);
|
| }
|
|
|
| static String _timeZoneName(int microsecondsSinceEpoch) {
|
| - int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch);
|
| - return _timeZoneNameForClampedSeconds(equivalentSeconds);
|
| + int seconds = _flooredDivision(
|
| + microsecondsSinceEpoch, Duration.MICROSECONDS_PER_SECOND);
|
| + return _timeZoneNameForSeconds(seconds);
|
| }
|
| }
|
|
|