Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: runtime/lib/date_patch.dart

Issue 3006853002: Use more of the std libraries to do date manipulations. (Closed)
Patch Set: Remove "clamped" part. Created 3 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 7 @patch
8 class DateTime { 8 class DateTime {
9 // Natives. 9 // Natives.
10 // The natives have been moved up here to work around Issue 10401. 10 // The natives have been moved up here to work around Issue 10401.
11 static int _getCurrentMicros() native "DateTime_currentTimeMicros"; 11 static int _getCurrentMicros() native "DateTime_currentTimeMicros";
12 12
13 static String _timeZoneNameForClampedSeconds(int secondsSinceEpoch) 13 static String _timeZoneNameForSeconds(int secondsSinceEpoch)
14 native "DateTime_timeZoneName"; 14 native "DateTime_timeZoneName";
15 15
16 static int _timeZoneOffsetInSecondsForClampedSeconds(int secondsSinceEpoch) 16 static int _timeZoneOffsetInSecondsForSeconds(int secondsSinceEpoch)
17 native "DateTime_timeZoneOffsetInSeconds"; 17 native "DateTime_timeZoneOffsetInSeconds";
18 18
19 static int _localTimeZoneAdjustmentInSeconds() 19 static int _localTimeZoneAdjustmentInSeconds()
20 native "DateTime_localTimeZoneAdjustmentInSeconds"; 20 native "DateTime_localTimeZoneAdjustmentInSeconds";
21 21
22 // Returns `null` if an error occurred.
23 static int
24 _brokenDownToSeconds(int year, int month, int day, int hour, int minute,
25 int second, bool isUtc)
26 native "DateTime_brokenDownToSeconds"; // Would use mktime or _mkgmtime/ti megm
27
22 static const _MICROSECOND_INDEX = 0; 28 static const _MICROSECOND_INDEX = 0;
23 static const _MILLISECOND_INDEX = 1; 29 static const _MILLISECOND_INDEX = 1;
24 static const _SECOND_INDEX = 2; 30 static const _SECOND_INDEX = 2;
25 static const _MINUTE_INDEX = 3; 31 static const _MINUTE_INDEX = 3;
26 static const _HOUR_INDEX = 4; 32 static const _HOUR_INDEX = 4;
27 static const _DAY_INDEX = 5; 33 static const _DAY_INDEX = 5;
28 static const _WEEKDAY_INDEX = 6; 34 static const _WEEKDAY_INDEX = 6;
29 static const _MONTH_INDEX = 7; 35 static const _MONTH_INDEX = 7;
30 static const _YEAR_INDEX = 8; 36 static const _YEAR_INDEX = 8;
31 37
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 260
255 static bool _isLeapYear(y) { 261 static bool _isLeapYear(y) {
256 // (y % 16 == 0) matches multiples of 400, and is faster than % 400. 262 // (y % 16 == 0) matches multiples of 400, and is faster than % 400.
257 return (y % 4 == 0) && ((y % 16 == 0) || (y % 100 != 0)); 263 return (y % 4 == 0) && ((y % 16 == 0) || (y % 100 != 0));
258 } 264 }
259 265
260 /// Converts the given broken down date to microseconds. 266 /// Converts the given broken down date to microseconds.
261 @patch 267 @patch
262 static int _brokenDownDateToValue(int year, int month, int day, int hour, 268 static int _brokenDownDateToValue(int year, int month, int day, int hour,
263 int minute, int second, int millisecond, int microsecond, bool isUtc) { 269 int minute, int second, int millisecond, int microsecond, bool isUtc) {
264 // Simplify calculations by working with zero-based month. 270 var seconds =
265 --month; 271 _brokenDownToSeconds(year, month - 1, day, hour, minute, second, isUtc);
266 // Deal with under and overflow. 272 if (seconds == null) return null;
267 if (month >= 12) { 273 return seconds * Duration.MICROSECONDS_PER_SECOND +
268 year += month ~/ 12; 274 milliseconds * Duration.MICROSECONDS_PER_MILLISECONDS +
269 month = month % 12; 275 microseconds;
270 } else if (month < 0) {
271 int realMonth = month % 12;
272 year += (month - realMonth) ~/ 12;
273 month = realMonth;
274 }
275
276 // First compute the seconds in UTC, independent of the [isUtc] flag. If
277 // necessary we will add the time-zone offset later on.
278 int days = day - 1;
279 days += _DAYS_UNTIL_MONTH[_isLeapYear(year) ? 1 : 0][month];
280 days += _dayFromYear(year);
281 int microsecondsSinceEpoch = days * Duration.MICROSECONDS_PER_DAY +
282 hour * Duration.MICROSECONDS_PER_HOUR +
283 minute * Duration.MICROSECONDS_PER_MINUTE +
284 second * Duration.MICROSECONDS_PER_SECOND +
285 millisecond * Duration.MICROSECONDS_PER_MILLISECOND +
286 microsecond;
287
288 // Since [_timeZoneOffsetInSeconds] will crash if the input is far out of
289 // the valid range we do a preliminary test that weeds out values that can
290 // not become valid even with timezone adjustments.
291 // The timezone adjustment is always less than a day, so adding a security
292 // margin of one day should be enough.
293 if (microsecondsSinceEpoch.abs() >
294 _MAX_MILLISECONDS_SINCE_EPOCH * 1000 + Duration.MICROSECONDS_PER_DAY) {
295 return null;
296 }
297
298 if (!isUtc) {
299 // Note that we need to remove the local timezone adjustment before
300 // asking for the correct zone offset.
301 int adjustment = _localTimeZoneAdjustmentInSeconds() *
302 Duration.MICROSECONDS_PER_SECOND;
303 // The adjustment is independent of the actual date and of the daylight
304 // saving time. It is positive east of the Prime Meridian and negative
305 // west of it, e.g. -28800 sec for America/Los_Angeles timezone.
306
307 int zoneOffset =
308 _timeZoneOffsetInSeconds(microsecondsSinceEpoch - adjustment);
309 // The zoneOffset depends on the actual date and reflects any daylight
310 // saving time and/or historical deviation relative to UTC time.
311 // It is positive east of the Prime Meridian and negative west of it,
312 // e.g. -25200 sec for America/Los_Angeles timezone during DST.
313 microsecondsSinceEpoch -= zoneOffset * Duration.MICROSECONDS_PER_SECOND;
314 // The resulting microsecondsSinceEpoch value is therefore the calculated
315 // UTC value decreased by a (positive if east of GMT) timezone adjustment
316 // and decreased by typically one hour if DST is in effect.
317 }
318 if (microsecondsSinceEpoch.abs() >
319 _MAX_MILLISECONDS_SINCE_EPOCH * Duration.MICROSECONDS_PER_MILLISECOND) {
320 return null;
321 }
322 return microsecondsSinceEpoch;
323 }
324
325 static int _weekDay(y) {
326 // 1/1/1970 was a Thursday.
327 return (_dayFromYear(y) + 4) % 7;
328 }
329
330 /**
331 * Returns a year in the range 2008-2035 matching
332 * * leap year, and
333 * * week day of first day.
334 *
335 * Leap seconds are ignored.
336 * Adapted from V8's date implementation. See ECMA 262 - 15.9.1.9.
337 */
338 static int _equivalentYear(int year) {
339 // Returns year y so that _weekDay(y) == _weekDay(year).
340 // _weekDay returns the week day (in range 0 - 6).
341 // 1/1/1956 was a Sunday (i.e. weekday 0). 1956 was a leap-year.
342 // 1/1/1967 was a Sunday (i.e. weekday 0).
343 // Without leap years a subsequent year has a week day + 1 (for example
344 // 1/1/1968 was a Monday). With leap-years it jumps over one week day
345 // (e.g. 1/1/1957 was a Tuesday).
346 // After 12 years the weekdays have advanced by 12 days + 3 leap days =
347 // 15 days. 15 % 7 = 1. So after 12 years the week day has always
348 // (now independently of leap-years) advanced by one.
349 // weekDay * 12 gives thus a year starting with the wanted weekDay.
350 int recentYear = (_isLeapYear(year) ? 1956 : 1967) + (_weekDay(year) * 12);
351 // Close to the year 2008 the calendar cycles every 4 * 7 years (4 for the
352 // leap years, 7 for the weekdays).
353 // Find the year in the range 2008..2037 that is equivalent mod 28.
354 return 2008 + (recentYear - 2008) % 28;
355 }
356
357 /**
358 * Returns the UTC year for the corresponding [secondsSinceEpoch].
359 * It is relatively fast for values in the range 0 to year 2098.
360 *
361 * Code is adapted from V8.
362 */
363 static int _yearsFromSecondsSinceEpoch(int secondsSinceEpoch) {
364 const int DAYS_IN_4_YEARS = 4 * 365 + 1;
365 const int DAYS_IN_100_YEARS = 25 * DAYS_IN_4_YEARS - 1;
366 const int DAYS_YEAR_2098 = DAYS_IN_100_YEARS + 6 * DAYS_IN_4_YEARS;
367
368 int days = secondsSinceEpoch ~/ Duration.SECONDS_PER_DAY;
369 if (days > 0 && days < DAYS_YEAR_2098) {
370 // According to V8 this fast case works for dates from 1970 to 2099.
371 return 1970 + (4 * days + 2) ~/ DAYS_IN_4_YEARS;
372 }
373 int micros = secondsSinceEpoch * Duration.MICROSECONDS_PER_SECOND;
374 return _computeUpperPart(micros)[_YEAR_INDEX];
375 }
376
377 /**
378 * Returns a date in seconds that is equivalent to the given
379 * date in microseconds [microsecondsSinceEpoch]. An equivalent
380 * date has the same fields (`month`, `day`, etc.) as the given
381 * date, but the `year` is in the range [1901..2038].
382 *
383 * * The time since the beginning of the year is the same.
384 * * If the given date is in a leap year then the returned
385 * seconds are in a leap year, too.
386 * * The week day of given date is the same as the one for the
387 * returned date.
388 */
389 static int _equivalentSeconds(int microsecondsSinceEpoch) {
390 const int CUT_OFF_SECONDS = 0x7FFFFFFF;
391
392 int secondsSinceEpoch = _flooredDivision(
393 microsecondsSinceEpoch, Duration.MICROSECONDS_PER_SECOND);
394
395 if (secondsSinceEpoch.abs() > CUT_OFF_SECONDS) {
396 int year = _yearsFromSecondsSinceEpoch(secondsSinceEpoch);
397 int days = _dayFromYear(year);
398 int equivalentYear = _equivalentYear(year);
399 int equivalentDays = _dayFromYear(equivalentYear);
400 int diffDays = equivalentDays - days;
401 secondsSinceEpoch += diffDays * Duration.SECONDS_PER_DAY;
402 }
403 return secondsSinceEpoch;
404 } 276 }
405 277
406 static int _timeZoneOffsetInSeconds(int microsecondsSinceEpoch) { 278 static int _timeZoneOffsetInSeconds(int microsecondsSinceEpoch) {
407 int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch); 279 int seconds = _flooredDivision(
408 return _timeZoneOffsetInSecondsForClampedSeconds(equivalentSeconds); 280 microsecondsSinceEpoch, Duration.MICROSECONDS_PER_SECOND);
281 return _timeZoneOffsetInSecondsForSeconds(seconds);
409 } 282 }
410 283
411 static String _timeZoneName(int microsecondsSinceEpoch) { 284 static String _timeZoneName(int microsecondsSinceEpoch) {
412 int equivalentSeconds = _equivalentSeconds(microsecondsSinceEpoch); 285 int seconds = _flooredDivision(
413 return _timeZoneNameForClampedSeconds(equivalentSeconds); 286 microsecondsSinceEpoch, Duration.MICROSECONDS_PER_SECOND);
287 return _timeZoneNameForSeconds(seconds);
414 } 288 }
415 } 289 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698