Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 class TimeZoneImplementation implements TimeZone { | 6 class TimeZoneImplementation implements TimeZone { |
| 7 const TimeZoneImplementation.utc() : isUtc = true; | 7 const TimeZoneImplementation.utc() : isUtc = true; |
| 8 TimeZoneImplementation.local() : isUtc = false {} | 8 TimeZoneImplementation.local() : isUtc = false {} |
| 9 | 9 |
| 10 bool operator ==(Object other) { | 10 bool operator ==(Object other) { |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 32 | 32 |
| 33 DateImplementation.withTimeZone(int years, | 33 DateImplementation.withTimeZone(int years, |
| 34 int month, | 34 int month, |
| 35 int day, | 35 int day, |
| 36 int hours, | 36 int hours, |
| 37 int minutes, | 37 int minutes, |
| 38 int seconds, | 38 int seconds, |
| 39 int milliseconds, | 39 int milliseconds, |
| 40 TimeZoneImplementation timeZone) | 40 TimeZoneImplementation timeZone) |
| 41 : timeZone = timeZone, | 41 : timeZone = timeZone, |
| 42 value = brokenDownDateToMillisecondsSinceEpoch_( | 42 value = _brokenDownDateToMillisecondsSinceEpoch( |
| 43 years, month, day, hours, minutes, seconds, milliseconds, | 43 years, month, day, hours, minutes, seconds, milliseconds, |
|
kasperl
2012/03/02 13:34:10
Weird indentation of the parameters.
floitsch
2012/03/02 17:00:29
Done.
| |
| 44 timeZone.isUtc) {} | 44 timeZone.isUtc) { |
| 45 if (value === null) throw new IllegalArgumentException(); | |
| 46 } | |
| 45 | 47 |
| 46 DateImplementation.now() | 48 DateImplementation.now() |
| 47 : timeZone = new TimeZone.local(), | 49 : timeZone = new TimeZone.local(), |
| 48 value = getCurrentMs_() { | 50 value = getCurrentMs_() { |
| 49 } | 51 } |
| 50 | 52 |
| 51 factory DateImplementation.fromString(String formattedString) { | 53 factory DateImplementation.fromString(String formattedString) { |
| 52 int substringToNumber(String str, int from, int to) { | 54 // Read in (a subset of) ISO 8601. |
| 53 int result = 0; | 55 // Examples: |
| 54 for (int i = from; i < to; i++) { | 56 // - "2012-02-27 13:27:00" |
| 55 result = result * 10 + str.charCodeAt(i) - "0".charCodeAt(0); | 57 // - "2012-02-27 13:27:00.423z" |
| 58 // - "20120227 13:27:00" | |
| 59 // - "20120227T132700" | |
| 60 // - "20120227" | |
| 61 // - "2012-02-27T14Z" | |
| 62 // - "-123450101 00:00:00 Z" // In the year -12345. | |
| 63 final RegExp re = const RegExp( | |
|
kasperl
2012/03/02 13:34:10
Is there anyway we could be sharing more of this c
floitsch
2012/03/02 17:00:29
Waiting for Josh' refactorings and will reevaluate
| |
| 64 @'^([+-]?\d?\d\d\d\d)-?(\d\d)-?(\d\d)' + // The day part. | |
| 65 @'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(?:.(\d{1,5}))?)?)? ?([zZ])?)?$'); | |
| 66 Match match = re.firstMatch(formattedString); | |
| 67 if (match !== null) { | |
| 68 int parseIntOrZero(String matched) { | |
| 69 // TODO(floitsch): we should not need to test against the empty string. | |
| 70 if (matched === null || matched == "") return 0; | |
| 71 return Math.parseInt(matched); | |
| 56 } | 72 } |
| 57 return result; | 73 |
| 74 int years = Math.parseInt(match[1]); | |
| 75 int month = Math.parseInt(match[2]); | |
| 76 int day = Math.parseInt(match[3]); | |
| 77 int hours = parseIntOrZero(match[4]); | |
| 78 int minutes = parseIntOrZero(match[5]); | |
| 79 int seconds = parseIntOrZero(match[6]); | |
| 80 bool addOneMillisecond = false; | |
| 81 int milliseconds = parseIntOrZero(match[7]); | |
| 82 if (milliseconds != 0) { | |
| 83 if (match[7].length == 1) { | |
| 84 milliseconds *= 100; | |
| 85 } else if (match[7].length == 2) { | |
| 86 milliseconds *= 10; | |
| 87 } else if (match[7].length == 3) { | |
| 88 // Do nothing. | |
| 89 } else if (match[7].length == 4) { | |
| 90 addOneMillisecond = ((milliseconds % 10) >= 5); | |
| 91 milliseconds ~/= 10; | |
| 92 } else { | |
| 93 assert(match[7].length == 5); | |
| 94 addOneMillisecond = ((milliseconds %100) >= 50); | |
|
kasperl
2012/03/02 13:34:10
%100 -> % 100
floitsch
2012/03/02 17:00:29
seems to be a common mistake... ;)
done.
| |
| 95 milliseconds ~/= 100; | |
| 96 } | |
| 97 if (addOneMillisecond && milliseconds < 999) { | |
| 98 addOneMillisecond = false; | |
| 99 milliseconds++; | |
| 100 } | |
| 101 } | |
| 102 // TODO(floitsch): we should not need to test against the empty string. | |
| 103 bool isUtc = (match[8] !== null) && (match[8] != ""); | |
| 104 TimeZone timezone = isUtc ? const TimeZone.utc() : new TimeZone.local(); | |
| 105 int epochValue = _brokenDownDateToMillisecondsSinceEpoch( | |
| 106 years, month, day, hours, minutes, seconds, milliseconds, isUtc); | |
| 107 if (epochValue === null) { | |
| 108 throw new IllegalArgumentException(formattedString); | |
| 109 } | |
| 110 if (addOneMillisecond) epochValue++; | |
| 111 return new DateImplementation.fromEpoch(epochValue, timezone); | |
| 112 } else { | |
| 113 throw new IllegalArgumentException(formattedString); | |
| 58 } | 114 } |
| 59 | |
| 60 // TODO(floitsch): improve DateImplementation parsing. | |
| 61 // Parse ISO 8601: "2011-05-14 00:37:18.231Z". | |
| 62 int yearMonthSeparator = formattedString.indexOf("-", 0); | |
| 63 if (yearMonthSeparator < 0) throw "UNIMPLEMENTED"; | |
| 64 int monthDaySeparator = | |
| 65 formattedString.indexOf("-", yearMonthSeparator + 1); | |
| 66 if (monthDaySeparator < 0) throw "UNIMPLEMENTED"; | |
| 67 int dateTimeSeparator = formattedString.indexOf(" ", monthDaySeparator + 1); | |
| 68 if (dateTimeSeparator < 0) throw "UNIMPLEMENTED"; | |
| 69 int hoursMinutesSeparator = | |
| 70 formattedString.indexOf(":", dateTimeSeparator + 1); | |
| 71 if (hoursMinutesSeparator < 0) throw "UNIMPLEMENTED"; | |
| 72 int minutesSecondsSeparator = | |
| 73 formattedString.indexOf(":", hoursMinutesSeparator + 1); | |
| 74 if (minutesSecondsSeparator < 0) throw "UNIMPLEMENTED"; | |
| 75 int secondsMillisecondsSeparator = | |
| 76 formattedString.indexOf(".", minutesSecondsSeparator + 1); | |
| 77 bool isUtc = formattedString.endsWith("Z"); | |
| 78 int end = formattedString.length - (isUtc ? 1 : 0); | |
| 79 if (secondsMillisecondsSeparator < 0) secondsMillisecondsSeparator = end; | |
| 80 | |
| 81 int year = substringToNumber(formattedString, 0, yearMonthSeparator); | |
| 82 int month = substringToNumber(formattedString, | |
| 83 yearMonthSeparator + 1, | |
| 84 monthDaySeparator); | |
| 85 int day = substringToNumber(formattedString, | |
| 86 monthDaySeparator + 1, | |
| 87 dateTimeSeparator); | |
| 88 int hours = substringToNumber(formattedString, | |
| 89 dateTimeSeparator + 1, | |
| 90 hoursMinutesSeparator); | |
| 91 int minutes = substringToNumber(formattedString, | |
| 92 hoursMinutesSeparator + 1, | |
| 93 minutesSecondsSeparator); | |
| 94 int seconds = substringToNumber(formattedString, | |
| 95 minutesSecondsSeparator + 1, | |
| 96 secondsMillisecondsSeparator); | |
| 97 int milliseconds = substringToNumber(formattedString, | |
| 98 secondsMillisecondsSeparator + 1, | |
| 99 end); | |
| 100 TimeZone timeZone = (isUtc ? const TimeZone.utc() : new TimeZone.local()); | |
| 101 return new DateImplementation.withTimeZone( | |
| 102 year, month, day, hours, minutes, seconds, milliseconds, timeZone); | |
| 103 } | 115 } |
| 104 | 116 |
| 105 const DateImplementation.fromEpoch(int this.value, | 117 const DateImplementation.fromEpoch(int this.value, |
| 106 TimeZone this.timeZone); | 118 TimeZone this.timeZone); |
| 107 | 119 |
| 108 bool operator ==(Object other) { | 120 bool operator ==(Object other) { |
| 109 if (!(other is DateImplementation)) return false; | 121 if (!(other is DateImplementation)) return false; |
| 110 return value == other.value && timeZone == other.timeZone; | 122 return value == other.value && timeZone == other.timeZone; |
| 111 } | 123 } |
| 112 | 124 |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 191 | 203 |
| 192 bool isLocalTime() { | 204 bool isLocalTime() { |
| 193 return !timeZone.isUtc; | 205 return !timeZone.isUtc; |
| 194 } | 206 } |
| 195 | 207 |
| 196 bool isUtc() { | 208 bool isUtc() { |
| 197 return timeZone.isUtc; | 209 return timeZone.isUtc; |
| 198 } | 210 } |
| 199 | 211 |
| 200 String toString() { | 212 String toString() { |
| 213 String fourDigits(int n) { | |
| 214 int absN = n.abs(); | |
| 215 String sign = n < 0 ? "-" : ""; | |
| 216 if (absN >= 1000) return "$n"; | |
| 217 if (absN >= 100) return "${sign}0$absN"; | |
| 218 if (absN >= 10) return "${sign}00$absN"; | |
| 219 if (absN >= 1) return "${sign}000$absN"; | |
| 220 } | |
| 201 String threeDigits(int n) { | 221 String threeDigits(int n) { |
| 202 if (n >= 100) return "${n}"; | 222 if (n >= 100) return "${n}"; |
| 203 if (n > 10) return "0${n}"; | 223 if (n > 10) return "0${n}"; |
| 204 return "00${n}"; | 224 return "00${n}"; |
| 205 } | 225 } |
| 206 String twoDigits(int n) { | 226 String twoDigits(int n) { |
| 207 if (n >= 10) return "${n}"; | 227 if (n >= 10) return "${n}"; |
| 208 return "0${n}"; | 228 return "0${n}"; |
| 209 } | 229 } |
| 210 | 230 |
| 231 String y = fourDigits(year); | |
| 211 String m = twoDigits(month); | 232 String m = twoDigits(month); |
| 212 String d = twoDigits(day); | 233 String d = twoDigits(day); |
| 213 String h = twoDigits(hours); | 234 String h = twoDigits(hours); |
| 214 String min = twoDigits(minutes); | 235 String min = twoDigits(minutes); |
| 215 String sec = twoDigits(seconds); | 236 String sec = twoDigits(seconds); |
| 216 String ms = threeDigits(milliseconds); | 237 String ms = threeDigits(milliseconds); |
| 217 if (timeZone.isUtc) { | 238 if (timeZone.isUtc) { |
| 218 return "$year-$m-$d $h:$min:$sec.${ms}Z"; | 239 return "$y-$m-$d $h:$min:$sec.${ms}Z"; |
| 219 } else { | 240 } else { |
| 220 return "$year-$m-$d $h:$min:$sec.$ms"; | 241 return "$y-$m-$d $h:$min:$sec.$ms"; |
| 221 } | 242 } |
| 222 } | 243 } |
| 223 | 244 |
| 224 // Adds the [duration] to this Date instance. | 245 // Adds the [duration] to this Date instance. |
| 225 Date add(Duration duration) { | 246 Date add(Duration duration) { |
| 226 return new DateImplementation.fromEpoch(value + duration.inMilliseconds, | 247 return new DateImplementation.fromEpoch(value + duration.inMilliseconds, |
| 227 timeZone); | 248 timeZone); |
| 228 } | 249 } |
| 229 | 250 |
| 230 // Subtracts the [duration] from this Date instance. | 251 // Subtracts the [duration] from this Date instance. |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 334 // 15 days. 15 % 7 = 1. So after 12 years the week day has always | 355 // 15 days. 15 % 7 = 1. So after 12 years the week day has always |
| 335 // (now independently of leap-years) advanced by one. | 356 // (now independently of leap-years) advanced by one. |
| 336 // weekDay * 12 gives thus a year starting with the wanted weekDay. | 357 // weekDay * 12 gives thus a year starting with the wanted weekDay. |
| 337 int recentYear = (inLeapYear(year) ? 1956 : 1967) + (weekDay(year) * 12); | 358 int recentYear = (inLeapYear(year) ? 1956 : 1967) + (weekDay(year) * 12); |
| 338 // Close to the year 2008 the calendar cycles every 4 * 7 years (4 for the | 359 // Close to the year 2008 the calendar cycles every 4 * 7 years (4 for the |
| 339 // leap years, 7 for the weekdays). | 360 // leap years, 7 for the weekdays). |
| 340 // Find the year in the range 2008..2037 that is equivalent mod 28. | 361 // Find the year in the range 2008..2037 that is equivalent mod 28. |
| 341 return 2008 + (recentYear - 2008) % 28; | 362 return 2008 + (recentYear - 2008) % 28; |
| 342 } | 363 } |
| 343 | 364 |
| 344 static brokenDownDateToMillisecondsSinceEpoch_( | 365 static _brokenDownDateToMillisecondsSinceEpoch( |
| 345 int years, int month, int day, | 366 int years, int month, int day, |
| 346 int hours, int minutes, int seconds, int milliseconds, | 367 int hours, int minutes, int seconds, int milliseconds, |
| 347 bool isUtc) { | 368 bool isUtc) { |
| 348 if ((month < 1) || (month > 12)) { | 369 if ((month < 1) || (month > 12)) return null; |
| 349 throw new IllegalArgumentException(); | 370 if ((day < 1) || (day > 31)) return null; |
| 350 } | |
| 351 if ((day < 1) || (day > 31)) { | |
| 352 throw new IllegalArgumentException(); | |
| 353 } | |
| 354 // Leap seconds can lead to hours == 24. | 371 // Leap seconds can lead to hours == 24. |
| 355 if ((hours < 0) || (hours > 24)) { | 372 if ((hours < 0) || (hours > 24)) return null; |
| 356 throw new IllegalArgumentException(); | 373 if ((hours == 24) && ((minutes != 0) || (seconds != 0))) return null; |
| 357 } | 374 if ((minutes < 0) || (minutes > 59)) return null; |
| 358 if ((hours == 24) && ((minutes != 0) || (seconds != 0))) { | 375 if ((seconds < 0) || (seconds > 59)) return null; |
| 359 throw new IllegalArgumentException(); | 376 if ((milliseconds < 0) || (milliseconds > 999)) return null; |
| 360 } | 377 |
| 361 if ((minutes < 0) || (minutes > 59)) { | |
| 362 throw new IllegalArgumentException(); | |
| 363 } | |
| 364 if ((seconds < 0) || (seconds > 59)) { | |
| 365 throw new IllegalArgumentException(); | |
| 366 } | |
| 367 if ((milliseconds < 0) || (milliseconds > 999)) { | |
| 368 throw new IllegalArgumentException(); | |
| 369 } | |
| 370 int equivalentYear; | 378 int equivalentYear; |
| 371 int offsetInSeconds; | 379 int offsetInSeconds; |
| 372 // According to V8 some library calls have troubles with negative values. | 380 // According to V8 some library calls have troubles with negative values. |
| 373 // Therefore clamp to 1970 - year 2035 (which is less than the size of | 381 // Therefore clamp to 1970 - year 2035 (which is less than the size of |
| 374 // 32bit). | 382 // 32bit). |
| 375 // We exclude the year 1970 when the time is not UTC, since the epoch | 383 // We exclude the year 1970 when the time is not UTC, since the epoch |
| 376 // value could then be negative. | 384 // value could then be negative. |
| 377 if (years < (isUtc ? 1970 : 1971) || years > 2035) { | 385 if (years < (isUtc ? 1970 : 1971) || years > 2035) { |
| 378 equivalentYear = equivalentYear_(years); | 386 equivalentYear = equivalentYear_(years); |
| 379 int offsetInDays = (dayFromYear_(years) - dayFromYear_(equivalentYear)); | 387 int offsetInDays = (dayFromYear_(years) - dayFromYear_(equivalentYear)); |
| 380 // Leap seconds are ignored. | 388 // Leap seconds are ignored. |
| 381 offsetInSeconds = offsetInDays * Duration.SECONDS_PER_DAY; | 389 offsetInSeconds = offsetInDays * Duration.SECONDS_PER_DAY; |
| 382 } else { | 390 } else { |
| 383 equivalentYear = years; | 391 equivalentYear = years; |
| 384 offsetInSeconds = 0; | 392 offsetInSeconds = 0; |
| 385 } | 393 } |
| 386 int secondsSinceEpoch = brokenDownDateToSecondsSinceEpoch_( | 394 int secondsSinceEpoch = _brokenDownDateToSecondsSinceEpoch( |
| 387 equivalentYear, month, day, hours, minutes, seconds, isUtc); | 395 equivalentYear, month, day, hours, minutes, seconds, isUtc); |
| 388 int adjustedSeconds = secondsSinceEpoch + offsetInSeconds; | 396 int adjustedSeconds = secondsSinceEpoch + offsetInSeconds; |
| 389 return adjustedSeconds * Duration.MILLISECONDS_PER_SECOND + milliseconds; | 397 return adjustedSeconds * Duration.MILLISECONDS_PER_SECOND + milliseconds; |
| 390 } | 398 } |
| 391 | 399 |
| 392 // Natives | 400 // Natives |
| 393 static brokenDownDateToSecondsSinceEpoch_( | 401 static _brokenDownDateToSecondsSinceEpoch( |
| 394 int years, int month, int day, int hours, int minutes, int seconds, | 402 int years, int month, int day, int hours, int minutes, int seconds, |
| 395 bool isUtc) native "DateNatives_brokenDownToSecondsSinceEpoch"; | 403 bool isUtc) native "DateNatives_brokenDownToSecondsSinceEpoch"; |
| 396 | 404 |
| 397 static int getCurrentMs_() native "DateNatives_currentTimeMillis"; | 405 static int getCurrentMs_() native "DateNatives_currentTimeMillis"; |
| 398 | 406 |
| 399 // TODO(floitsch): it would be more efficient if we didn't call the native | 407 // TODO(floitsch): it would be more efficient if we didn't call the native |
| 400 // function for every member, but cached the broken-down date. | 408 // function for every member, but cached the broken-down date. |
| 401 static int getYear_(int secondsSinceEpoch, bool isUtc) | 409 static int getYear_(int secondsSinceEpoch, bool isUtc) |
| 402 native "DateNatives_getYear"; | 410 native "DateNatives_getYear"; |
| 403 | 411 |
| 404 static int getMonth_(int secondsSinceEpoch, bool isUtc) | 412 static int getMonth_(int secondsSinceEpoch, bool isUtc) |
| 405 native "DateNatives_getMonth"; | 413 native "DateNatives_getMonth"; |
| 406 | 414 |
| 407 static int getDay_(int secondsSinceEpoch, bool isUtc) | 415 static int getDay_(int secondsSinceEpoch, bool isUtc) |
| 408 native "DateNatives_getDay"; | 416 native "DateNatives_getDay"; |
| 409 | 417 |
| 410 static int getHours_(int secondsSinceEpoch, bool isUtc) | 418 static int getHours_(int secondsSinceEpoch, bool isUtc) |
| 411 native "DateNatives_getHours"; | 419 native "DateNatives_getHours"; |
| 412 | 420 |
| 413 static int getMinutes_(int secondsSinceEpoch, bool isUtc) | 421 static int getMinutes_(int secondsSinceEpoch, bool isUtc) |
| 414 native "DateNatives_getMinutes"; | 422 native "DateNatives_getMinutes"; |
| 415 | 423 |
| 416 static int getSeconds_(int secondsSinceEpoch, bool isUtc) | 424 static int getSeconds_(int secondsSinceEpoch, bool isUtc) |
| 417 native "DateNatives_getSeconds"; | 425 native "DateNatives_getSeconds"; |
| 418 } | 426 } |
| OLD | NEW |