| 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 | 4 |
| 5 // Dart core library. | 5 // Dart core library. |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Date is the public interface to a point in time. | 8 * Date is the public interface to a point in time. |
| 9 * | 9 * |
| 10 * It can represent time values that are at a distance of at most | 10 * It can represent time values that are at a distance of at most |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 45 * [month] and [day] are one-based. For example | 45 * [month] and [day] are one-based. For example |
| 46 * [:new Date(1938, 1, 10):] represents the 10th of January 1938. | 46 * [:new Date(1938, 1, 10):] represents the 10th of January 1938. |
| 47 */ | 47 */ |
| 48 factory Date(int year, | 48 factory Date(int year, |
| 49 [int month = 1, | 49 [int month = 1, |
| 50 int day = 1, | 50 int day = 1, |
| 51 int hour = 0, | 51 int hour = 0, |
| 52 int minute = 0, | 52 int minute = 0, |
| 53 int second = 0, | 53 int second = 0, |
| 54 int millisecond = 0]) { | 54 int millisecond = 0]) { |
| 55 return new DateImplementation(year, month, day, | 55 return new _DateImpl( |
| 56 hour, minute, second, | 56 year, month, day, hour, minute, second, millisecond, false); |
| 57 millisecond, false); | |
| 58 } | 57 } |
| 59 | 58 |
| 60 /** | 59 /** |
| 61 * Constructs a [Date] instance based on the individual parts. The date is | 60 * Constructs a [Date] instance based on the individual parts. The date is |
| 62 * in the UTC time zone. | 61 * in the UTC time zone. |
| 63 * | 62 * |
| 64 * [month] and [day] are one-based. For example | 63 * [month] and [day] are one-based. For example |
| 65 * [:new Date.utc(1938, 1, 10):] represents the 10th of January 1938 in | 64 * [:new Date.utc(1938, 1, 10):] represents the 10th of January 1938 in |
| 66 * Coordinated Universal Time. | 65 * Coordinated Universal Time. |
| 67 */ | 66 */ |
| 68 factory Date.utc(int year, | 67 factory Date.utc(int year, |
| 69 [int month = 1, | 68 [int month = 1, |
| 70 int day = 1, | 69 int day = 1, |
| 71 int hour = 0, | 70 int hour = 0, |
| 72 int minute = 0, | 71 int minute = 0, |
| 73 int second = 0, | 72 int second = 0, |
| 74 int millisecond = 0]) { | 73 int millisecond = 0]) { |
| 75 return new DateImplementation(year, month, day, | 74 return new _DateImpl( |
| 76 hour, minute, second, | 75 year, month, day, hour, minute, second, millisecond, true); |
| 77 millisecond, true); | |
| 78 } | 76 } |
| 79 | 77 |
| 80 /** | 78 /** |
| 81 * Constructs a new [Date] instance with current date time value in the | 79 * Constructs a new [Date] instance with current date time value in the |
| 82 * local time zone. | 80 * local time zone. |
| 83 */ | 81 */ |
| 84 factory Date.now() => new DateImplementation.now(); | 82 factory Date.now() => new _DateImpl.now(); |
| 85 | 83 |
| 86 /** | 84 /** |
| 87 * Constructs a new [Date] instance based on [formattedString]. | 85 * Constructs a new [Date] instance based on [formattedString]. |
| 88 */ | 86 */ |
| 89 factory Date.fromString(String formattedString) | 87 factory Date.fromString(String formattedString) |
| 90 => new DateImplementation.fromString(formattedString); | 88 => new _DateImpl.fromString(formattedString); |
| 91 | 89 |
| 92 /** | 90 /** |
| 93 * Constructs a new [Date] instance with the given [millisecondsSinceEpoch]. | 91 * Constructs a new [Date] instance with the given [millisecondsSinceEpoch]. |
| 94 * If [isUtc] is false then the date is in the local time zone. | 92 * If [isUtc] is false then the date is in the local time zone. |
| 95 * | 93 * |
| 96 * The constructed [Date] represents | 94 * The constructed [Date] represents |
| 97 * 1970-01-01T00:00:00Z + [millisecondsSinceEpoch]ms in the given | 95 * 1970-01-01T00:00:00Z + [millisecondsSinceEpoch]ms in the given |
| 98 * time zone (local or UTC). | 96 * time zone (local or UTC). |
| 99 */ | 97 */ |
| 100 // TODO(floitsch): the spec allows default values in interfaces, but our | 98 // TODO(floitsch): the spec allows default values in interfaces, but our |
| 101 // tools don't yet. Eventually we want to have default values here. | 99 // tools don't yet. Eventually we want to have default values here. |
| 102 // TODO(lrn): Have two constructors instead of taking an optional bool. | 100 // TODO(lrn): Have two constructors instead of taking an optional bool. |
| 103 factory Date.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch, | 101 factory Date.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch, |
| 104 {bool isUtc: false}) { | 102 {bool isUtc: false}) { |
| 105 return new DateImplementation.fromMillisecondsSinceEpoch( | 103 return new _DateImpl.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, |
| 106 millisecondsSinceEpoch, isUtc); | 104 isUtc); |
| 107 } | 105 } |
| 108 | 106 |
| 109 /** | 107 /** |
| 110 * Returns true if [this] occurs at the same time as [other]. The | 108 * Returns true if [this] occurs at the same time as [other]. The |
| 111 * comparison is independent of whether the time is utc or in the local | 109 * comparison is independent of whether the time is utc or in the local |
| 112 * time zone. | 110 * time zone. |
| 113 */ | 111 */ |
| 114 bool operator ==(Date other); | 112 bool operator ==(Date other); |
| 115 /** | 113 /** |
| 116 * Returns true if [this] occurs before [other]. The comparison is independent | 114 * Returns true if [this] occurs before [other]. The comparison is independent |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 /** | 235 /** |
| 238 * Returns a new [Date] with the [duration] subtracted from this instance. | 236 * Returns a new [Date] with the [duration] subtracted from this instance. |
| 239 */ | 237 */ |
| 240 Date subtract(Duration duration); | 238 Date subtract(Duration duration); |
| 241 | 239 |
| 242 /** | 240 /** |
| 243 * Returns a [Duration] with the difference of [:this:] and [other]. | 241 * Returns a [Duration] with the difference of [:this:] and [other]. |
| 244 */ | 242 */ |
| 245 Duration difference(Date other); | 243 Duration difference(Date other); |
| 246 } | 244 } |
| 245 |
| 246 class _DateImpl implements Date { |
| 247 final int millisecondsSinceEpoch; |
| 248 final bool isUtc; |
| 249 |
| 250 factory _DateImpl.fromString(String formattedString) { |
| 251 // Read in (a subset of) ISO 8601. |
| 252 // Examples: |
| 253 // - "2012-02-27 13:27:00" |
| 254 // - "2012-02-27 13:27:00.423z" |
| 255 // - "20120227 13:27:00" |
| 256 // - "20120227T132700" |
| 257 // - "20120227" |
| 258 // - "2012-02-27T14Z" |
| 259 // - "-123450101 00:00:00 Z" // In the year -12345. |
| 260 final RegExp re = const RegExp( |
| 261 r'^([+-]?\d?\d\d\d\d)-?(\d\d)-?(\d\d)' // The day part. |
| 262 r'(?:[ T](\d\d)(?::?(\d\d)(?::?(\d\d)(.\d{1,6})?)?)? ?([zZ])?)?$'); |
| 263 Match match = re.firstMatch(formattedString); |
| 264 if (match !== null) { |
| 265 int parseIntOrZero(String matched) { |
| 266 // TODO(floitsch): we should not need to test against the empty string. |
| 267 if (matched === null || matched == "") return 0; |
| 268 return int.parse(matched); |
| 269 } |
| 270 |
| 271 double parseDoubleOrZero(String matched) { |
| 272 // TODO(floitsch): we should not need to test against the empty string. |
| 273 if (matched === null || matched == "") return 0.0; |
| 274 return double.parse(matched); |
| 275 } |
| 276 |
| 277 int years = int.parse(match[1]); |
| 278 int month = int.parse(match[2]); |
| 279 int day = int.parse(match[3]); |
| 280 int hour = parseIntOrZero(match[4]); |
| 281 int minute = parseIntOrZero(match[5]); |
| 282 int second = parseIntOrZero(match[6]); |
| 283 bool addOneMillisecond = false; |
| 284 int millisecond = (parseDoubleOrZero(match[7]) * 1000).round().toInt(); |
| 285 if (millisecond == 1000) { |
| 286 addOneMillisecond = true; |
| 287 millisecond = 999; |
| 288 } |
| 289 // TODO(floitsch): we should not need to test against the empty string. |
| 290 bool isUtc = (match[8] !== null) && (match[8] != ""); |
| 291 int millisecondsSinceEpoch = _brokenDownDateToMillisecondsSinceEpoch( |
| 292 years, month, day, hour, minute, second, millisecond, isUtc); |
| 293 if (millisecondsSinceEpoch === null) { |
| 294 throw new ArgumentError(formattedString); |
| 295 } |
| 296 if (addOneMillisecond) millisecondsSinceEpoch++; |
| 297 return new Date.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, |
| 298 isUtc: isUtc); |
| 299 } else { |
| 300 throw new ArgumentError(formattedString); |
| 301 } |
| 302 } |
| 303 |
| 304 static const int _MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000; |
| 305 |
| 306 _DateImpl.fromMillisecondsSinceEpoch(this.millisecondsSinceEpoch, |
| 307 this.isUtc) { |
| 308 if (millisecondsSinceEpoch.abs() > _MAX_MILLISECONDS_SINCE_EPOCH) { |
| 309 throw new ArgumentError(millisecondsSinceEpoch); |
| 310 } |
| 311 if (isUtc === null) throw new ArgumentError(isUtc); |
| 312 } |
| 313 |
| 314 bool operator ==(other) { |
| 315 if (!(other is Date)) return false; |
| 316 return (millisecondsSinceEpoch == other.millisecondsSinceEpoch); |
| 317 } |
| 318 |
| 319 bool operator <(Date other) |
| 320 => millisecondsSinceEpoch < other.millisecondsSinceEpoch; |
| 321 |
| 322 bool operator <=(Date other) |
| 323 => millisecondsSinceEpoch <= other.millisecondsSinceEpoch; |
| 324 |
| 325 bool operator >(Date other) |
| 326 => millisecondsSinceEpoch > other.millisecondsSinceEpoch; |
| 327 |
| 328 bool operator >=(Date other) |
| 329 => millisecondsSinceEpoch >= other.millisecondsSinceEpoch; |
| 330 |
| 331 int compareTo(Date other) |
| 332 => millisecondsSinceEpoch.compareTo(other.millisecondsSinceEpoch); |
| 333 |
| 334 int get hashCode => millisecondsSinceEpoch; |
| 335 |
| 336 Date toLocal() { |
| 337 if (isUtc) { |
| 338 return new Date.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, |
| 339 isUtc: false); |
| 340 } |
| 341 return this; |
| 342 } |
| 343 |
| 344 Date toUtc() { |
| 345 if (isUtc) return this; |
| 346 return new Date.fromMillisecondsSinceEpoch(millisecondsSinceEpoch, |
| 347 isUtc: true); |
| 348 } |
| 349 |
| 350 String toString() { |
| 351 String fourDigits(int n) { |
| 352 int absN = n.abs(); |
| 353 String sign = n < 0 ? "-" : ""; |
| 354 if (absN >= 1000) return "$n"; |
| 355 if (absN >= 100) return "${sign}0$absN"; |
| 356 if (absN >= 10) return "${sign}00$absN"; |
| 357 return "${sign}000$absN"; |
| 358 } |
| 359 |
| 360 String threeDigits(int n) { |
| 361 if (n >= 100) return "${n}"; |
| 362 if (n >= 10) return "0${n}"; |
| 363 return "00${n}"; |
| 364 } |
| 365 |
| 366 String twoDigits(int n) { |
| 367 if (n >= 10) return "${n}"; |
| 368 return "0${n}"; |
| 369 } |
| 370 |
| 371 String y = fourDigits(year); |
| 372 String m = twoDigits(month); |
| 373 String d = twoDigits(day); |
| 374 String h = twoDigits(hour); |
| 375 String min = twoDigits(minute); |
| 376 String sec = twoDigits(second); |
| 377 String ms = threeDigits(millisecond); |
| 378 if (isUtc) { |
| 379 return "$y-$m-$d $h:$min:$sec.${ms}Z"; |
| 380 } else { |
| 381 return "$y-$m-$d $h:$min:$sec.$ms"; |
| 382 } |
| 383 } |
| 384 |
| 385 /** Returns a new [Date] with the [duration] added to [this]. */ |
| 386 Date add(Duration duration) { |
| 387 int ms = millisecondsSinceEpoch; |
| 388 return new Date.fromMillisecondsSinceEpoch( |
| 389 ms + duration.inMilliseconds, isUtc: isUtc); |
| 390 } |
| 391 |
| 392 /** Returns a new [Date] with the [duration] subtracted from [this]. */ |
| 393 Date subtract(Duration duration) { |
| 394 int ms = millisecondsSinceEpoch; |
| 395 return new Date.fromMillisecondsSinceEpoch( |
| 396 ms - duration.inMilliseconds, isUtc: isUtc); |
| 397 } |
| 398 |
| 399 /** Returns a [Duration] with the difference of [this] and [other]. */ |
| 400 Duration difference(Date other) { |
| 401 int ms = millisecondsSinceEpoch; |
| 402 int otherMs = other.millisecondsSinceEpoch; |
| 403 return new Duration(milliseconds: ms - otherMs); |
| 404 } |
| 405 |
| 406 external _DateImpl(int year, |
| 407 int month, |
| 408 int day, |
| 409 int hour, |
| 410 int minute, |
| 411 int second, |
| 412 int millisecond, |
| 413 bool isUtc); |
| 414 external _DateImpl.now(); |
| 415 external static int _brokenDownDateToMillisecondsSinceEpoch( |
| 416 int year, int month, int day, int hour, int minute, int second, |
| 417 int millisecond, bool isUtc); |
| 418 external String get timeZoneName; |
| 419 external Duration get timeZoneOffset; |
| 420 external int get year; |
| 421 external int get month; |
| 422 external int get day; |
| 423 external int get hour; |
| 424 external int get minute; |
| 425 external int get second; |
| 426 external int get millisecond; |
| 427 external int get weekday; |
| 428 } |
| OLD | NEW |