Revert "[js_runtime, js_dev_runtime] Implement `microsecond` field of `DataTime`"
This reverts commit fb057ea4e07de2af624688455925c0ca07afe04f.
Reason for revert: b/342552853
Original change's description:
> [js_runtime, js_dev_runtime] Implement `microsecond` field of `DataTime`
>
> - Move DateTime implementation for dart2js and DDC into a shared place to reduce duplication.
>
> - Add a _microsecond field to the web DateTime to track microseconds outside of the JavaScript Date.
>
> - The cute dart2js optimization whereby `DateTime.now().millisecondsSinceEpoch` is compiled to `Date.now()` still works.
>
> - Both implementations report better errors.
>
> - Fixed VM bug with in-range sentinel.
>
>
> Change-Id: I9156255bdb6ecc195500ae9bc88f91fb315b6297
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/366963
> Reviewed-by: Alexander Aprelev <aam@google.com>
> Reviewed-by: Martin Kustermann <kustermann@google.com>
> Reviewed-by: Lasse Nielsen <lrn@google.com>
> Commit-Queue: Stephen Adams <sra@google.com>
Change-Id: I58572256a7710df4589bb5e41c7afee295c2388b
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/368103
Reviewed-by: Alexander Thomas <athom@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Auto-Submit: Ivan Inozemtsev <iinozemtsev@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cdc5cfc..78ba51e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,20 +17,6 @@
[#55418]: https://github.com/dart-lang/sdk/issues/55418
[#55436]: https://github.com/dart-lang/sdk/issues/55436
-### Libraries
-
-#### `dart:core`
-
-- `DateTime` on the web platform now stores microseconds. Fixes [#44876][].
- The web imlementation is now practically compatible with the native
- implementation. Small discrepancies due to rounding of web integers may still
- occur for (1) `microsecondsSinceEpoch` outside the safe range, corresponding
- to dates with a year outside of 1685..2255, and (2) arithmetic (`add`,
- `subtract`, `difference`) where the `Duration` argument or result exceeds 570
- years.
-
-[#44876]: https://github.com/dart-lang/sdk/issues/44876
-
### Tools
#### Linter
diff --git a/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart b/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart
index f028c43..751b18c 100644
--- a/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart
+++ b/pkg/compiler/test/deferred_loading/data/lazy_types/lib.dart
@@ -11,7 +11,7 @@
int? x;
/*member: Foo.:member_unit=4{libB}*/
Foo() {
- x = DateTime.now().millisecondsSinceEpoch;
+ x = DateTime.now().millisecond;
}
/*member: Foo.method:member_unit=4{libB}*/
@pragma('dart2js:noInline')
diff --git a/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart b/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
index 65cc146..7c39178 100644
--- a/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
+++ b/sdk/lib/_internal/js_dev_runtime/patch/core_patch.dart
@@ -267,6 +267,147 @@
}
}
+// Patch for DateTime implementation.
+@patch
+class DateTime {
+ @patch
+ DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
+ {bool isUtc = false})
+ : this._withValue(millisecondsSinceEpoch, isUtc: isUtc);
+
+ @patch
+ DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
+ {bool isUtc = false})
+ : this._withValue(
+ _microsecondInRoundedMilliseconds(microsecondsSinceEpoch),
+ isUtc: isUtc);
+
+ @patch
+ DateTime._internal(int year, int month, int day, int hour, int minute,
+ int second, int millisecond, int microsecond, bool isUtc)
+ : isUtc = isUtc,
+ _value = checkInt(Primitives.valueFromDecomposedDate(
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ millisecond + _microsecondInRoundedMilliseconds(microsecond),
+ isUtc));
+
+ @patch
+ DateTime._now()
+ : isUtc = false,
+ _value = Primitives.dateNow();
+
+ @patch
+ DateTime._nowUtc()
+ : isUtc = true,
+ _value = Primitives.dateNow();
+
+ /// Rounds the given [microsecond] to the nearest milliseconds value.
+ ///
+ /// For example, invoked with argument `2600` returns `3`.
+ static int _microsecondInRoundedMilliseconds(int microsecond) {
+ return (microsecond / 1000).round();
+ }
+
+ @patch
+ static int? _brokenDownDateToValue(int year, int month, int day, int hour,
+ int minute, int second, int millisecond, int microsecond, bool isUtc) {
+ return Primitives.valueFromDecomposedDate(
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ millisecond + _microsecondInRoundedMilliseconds(microsecond),
+ isUtc);
+ }
+
+ @patch
+ String get timeZoneName {
+ if (isUtc) return "UTC";
+ return Primitives.getTimeZoneName(this);
+ }
+
+ @patch
+ Duration get timeZoneOffset {
+ if (isUtc) return Duration.zero;
+ return Duration(minutes: Primitives.getTimeZoneOffsetInMinutes(this));
+ }
+
+ @patch
+ DateTime add(Duration duration) {
+ return DateTime._withValue(_value + duration.inMilliseconds, isUtc: isUtc);
+ }
+
+ @patch
+ DateTime subtract(Duration duration) {
+ return DateTime._withValue(_value - duration.inMilliseconds, isUtc: isUtc);
+ }
+
+ @patch
+ Duration difference(DateTime other) {
+ return Duration(milliseconds: _value - other.millisecondsSinceEpoch);
+ }
+
+ @patch
+ int get millisecondsSinceEpoch => _value;
+
+ @patch
+ int get microsecondsSinceEpoch => _value * 1000;
+
+ @patch
+ int get year => Primitives.getYear(this);
+
+ @patch
+ int get month => Primitives.getMonth(this);
+
+ @patch
+ int get day => Primitives.getDay(this);
+
+ @patch
+ int get hour => Primitives.getHours(this);
+
+ @patch
+ int get minute => Primitives.getMinutes(this);
+
+ @patch
+ int get second => Primitives.getSeconds(this);
+
+ @patch
+ int get millisecond => Primitives.getMilliseconds(this);
+
+ @patch
+ int get microsecond => 0;
+
+ @patch
+ int get weekday => Primitives.getWeekday(this);
+
+ @patch
+ bool operator ==(Object other) =>
+ other is DateTime &&
+ _value == other.millisecondsSinceEpoch &&
+ isUtc == other.isUtc;
+
+ @patch
+ bool isBefore(DateTime other) => _value < other.millisecondsSinceEpoch;
+
+ @patch
+ bool isAfter(DateTime other) => _value > other.millisecondsSinceEpoch;
+
+ @patch
+ bool isAtSameMomentAs(DateTime other) =>
+ _value == other.millisecondsSinceEpoch;
+
+ @patch
+ int compareTo(DateTime other) =>
+ _value.compareTo(other.millisecondsSinceEpoch);
+}
+
// Patch for Stopwatch implementation.
@patch
class Stopwatch {
diff --git a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
index 6e7c363..2c1c1a0 100644
--- a/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
+++ b/sdk/lib/_internal/js_dev_runtime/private/js_helper.dart
@@ -392,7 +392,6 @@
@nullCheck int minutes,
@nullCheck int seconds,
@nullCheck int milliseconds,
- @nullCheck int microseconds,
@nullCheck bool isUtc) {
final int MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000;
var jsMonth = month - 1;
@@ -404,11 +403,6 @@
years += 400;
jsMonth -= 400 * 12;
}
- // JavaScript `Date` does not handle microseconds, so ensure the provided
- // microseconds is in range [0..999].
- final remainder = microseconds % 1000;
- milliseconds += (microseconds - remainder) ~/ 1000;
- microseconds = remainder;
int value;
if (isUtc) {
value = JS<int>('!', r'Date.UTC(#, #, #, #, #, #, #)', years, jsMonth,
@@ -419,13 +413,23 @@
}
if (value.isNaN ||
value < -MAX_MILLISECONDS_SINCE_EPOCH ||
- value > MAX_MILLISECONDS_SINCE_EPOCH ||
- value == MAX_MILLISECONDS_SINCE_EPOCH && microseconds != 0) {
+ value > MAX_MILLISECONDS_SINCE_EPOCH) {
return null;
}
+ if (years <= 0 || years < 100) return patchUpY2K(value, years, isUtc);
return value;
}
+ static int patchUpY2K(value, years, isUtc) {
+ var date = JS<int>('!', r'new Date(#)', value);
+ if (isUtc) {
+ JS<int>('!', r'#.setUTCFullYear(#)', date, years);
+ } else {
+ JS<int>('!', r'#.setFullYear(#)', date, years);
+ }
+ return JS<int>('!', r'#.valueOf()', date);
+ }
+
// Lazily keep a JS Date stored in the JS object.
static lazyAsJsDate(DateTime receiver) {
if (JS<bool>('!', r'#.date === (void 0)', receiver)) {
@@ -489,6 +493,13 @@
return (weekday + 6) % 7 + 1;
}
+ static num valueFromDateString(str) {
+ if (str is! String) throw argumentErrorValue(str);
+ num value = JS('!', r'Date.parse(#)', str);
+ if (value.isNaN) throw argumentErrorValue(str);
+ return value;
+ }
+
static Object? getProperty(Object? object, Object key) {
if (object == null || object is bool || object is num || object is String) {
throw argumentErrorValue(object);
diff --git a/sdk/lib/_internal/js_runtime/lib/core_patch.dart b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
index d7aa5f8..db471fb 100644
--- a/sdk/lib/_internal/js_runtime/lib/core_patch.dart
+++ b/sdk/lib/_internal/js_runtime/lib/core_patch.dart
@@ -281,6 +281,151 @@
}
}
+// Patch for DateTime implementation.
+@patch
+class DateTime {
+ @patch
+ DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
+ {bool isUtc = false})
+ // `0 + millisecondsSinceEpoch` forces the inferred result to be non-null.
+ : this._withValue(0 + millisecondsSinceEpoch, isUtc: isUtc);
+
+ @patch
+ DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
+ {bool isUtc = false})
+ : this._withValue(
+ _microsecondInRoundedMilliseconds(microsecondsSinceEpoch),
+ isUtc: isUtc);
+
+ @patch
+ DateTime._internal(int year, int month, int day, int hour, int minute,
+ int second, int millisecond, int microsecond, bool isUtc)
+ // checkBool is manually inlined here because dart2js doesn't inline it
+ // and [isUtc] is usually a constant.
+ : this.isUtc =
+ isUtc is bool ? isUtc : throw ArgumentError.value(isUtc, 'isUtc'),
+ _value = checkInt(Primitives.valueFromDecomposedDate(
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ millisecond + _microsecondInRoundedMilliseconds(microsecond),
+ isUtc));
+
+ @patch
+ DateTime._now()
+ : isUtc = false,
+ _value = Primitives.dateNow();
+
+ @patch
+ DateTime._nowUtc()
+ : isUtc = true,
+ _value = Primitives.dateNow();
+
+ /// Rounds the given [microsecond] to the nearest milliseconds value.
+ ///
+ /// For example, invoked with argument `2600` returns `3`.
+ static int _microsecondInRoundedMilliseconds(int microsecond) {
+ return (microsecond / 1000).round();
+ }
+
+ @patch
+ static int? _brokenDownDateToValue(int year, int month, int day, int hour,
+ int minute, int second, int millisecond, int microsecond, bool isUtc) {
+ return Primitives.valueFromDecomposedDate(
+ year,
+ month,
+ day,
+ hour,
+ minute,
+ second,
+ millisecond + _microsecondInRoundedMilliseconds(microsecond),
+ isUtc);
+ }
+
+ @patch
+ String get timeZoneName {
+ if (isUtc) return "UTC";
+ return Primitives.getTimeZoneName(this);
+ }
+
+ @patch
+ Duration get timeZoneOffset {
+ if (isUtc) return Duration();
+ return Duration(minutes: Primitives.getTimeZoneOffsetInMinutes(this));
+ }
+
+ @patch
+ DateTime add(Duration duration) {
+ return DateTime._withValue(_value + duration.inMilliseconds, isUtc: isUtc);
+ }
+
+ @patch
+ DateTime subtract(Duration duration) {
+ return DateTime._withValue(_value - duration.inMilliseconds, isUtc: isUtc);
+ }
+
+ @patch
+ Duration difference(DateTime other) {
+ return Duration(milliseconds: _value - other.millisecondsSinceEpoch);
+ }
+
+ @patch
+ int get millisecondsSinceEpoch => _value;
+
+ @patch
+ int get microsecondsSinceEpoch => 1000 * _value;
+
+ @patch
+ int get year => Primitives.getYear(this);
+
+ @patch
+ int get month => Primitives.getMonth(this);
+
+ @patch
+ int get day => Primitives.getDay(this);
+
+ @patch
+ int get hour => Primitives.getHours(this);
+
+ @patch
+ int get minute => Primitives.getMinutes(this);
+
+ @patch
+ int get second => Primitives.getSeconds(this);
+
+ @patch
+ int get millisecond => Primitives.getMilliseconds(this);
+
+ @patch
+ int get microsecond => 0;
+
+ @patch
+ int get weekday => Primitives.getWeekday(this);
+
+ @patch
+ bool operator ==(Object other) =>
+ other is DateTime &&
+ _value == other.millisecondsSinceEpoch &&
+ isUtc == other.isUtc;
+
+ @patch
+ bool isBefore(DateTime other) => _value < other.millisecondsSinceEpoch;
+
+ @patch
+ bool isAfter(DateTime other) => _value > other.millisecondsSinceEpoch;
+
+ @patch
+ bool isAtSameMomentAs(DateTime other) =>
+ _value == other.millisecondsSinceEpoch;
+
+ @patch
+ int compareTo(DateTime other) =>
+ _value.compareTo(other.millisecondsSinceEpoch);
+}
+
// Patch for Stopwatch implementation.
@patch
class Stopwatch {
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 2359738..1a04a33 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -682,16 +682,8 @@
as int;
}
- static int? valueFromDecomposedDate(
- int years,
- int month,
- int day,
- int hours,
- int minutes,
- int seconds,
- int milliseconds,
- int microseconds,
- bool isUtc) {
+ static int? valueFromDecomposedDate(int years, int month, int day, int hours,
+ int minutes, int seconds, int milliseconds, bool isUtc) {
final int MAX_MILLISECONDS_SINCE_EPOCH = 8640000000000000;
checkInt(years);
checkInt(month);
@@ -700,7 +692,6 @@
checkInt(minutes);
checkInt(seconds);
checkInt(milliseconds);
- checkInt(microseconds);
checkBool(isUtc);
var jsMonth = month - 1;
// The JavaScript Date constructor 'corrects' year NN to 19NN. Sidestep that
@@ -711,11 +702,6 @@
years += 400;
jsMonth -= 400 * 12;
}
- // JavaScript `Date` does not handle microseconds, so ensure the provided
- // microseconds is in range [0..999].
- final remainder = microseconds % 1000;
- milliseconds += (microseconds - remainder) ~/ 1000;
- microseconds = remainder;
num value;
if (isUtc) {
value = JS('num', r'Date.UTC(#, #, #, #, #, #, #)', years, jsMonth, day,
@@ -726,8 +712,7 @@
}
if (value.isNaN ||
value < -MAX_MILLISECONDS_SINCE_EPOCH ||
- value > MAX_MILLISECONDS_SINCE_EPOCH ||
- value == MAX_MILLISECONDS_SINCE_EPOCH && microseconds != 0) {
+ value > MAX_MILLISECONDS_SINCE_EPOCH) {
return null;
}
return JS('int', '#', value);
@@ -759,7 +744,7 @@
@pragma('dart2js:noSideEffects')
@pragma('dart2js:noThrows')
@pragma('dart2js:noInline')
- static int getYear(DateTime receiver) {
+ static getYear(DateTime receiver) {
return (receiver.isUtc)
? JS('int', r'(#.getUTCFullYear() + 0)', lazyAsJsDate(receiver))
: JS('int', r'(#.getFullYear() + 0)', lazyAsJsDate(receiver));
@@ -768,7 +753,7 @@
@pragma('dart2js:noSideEffects')
@pragma('dart2js:noThrows')
@pragma('dart2js:noInline')
- static int getMonth(DateTime receiver) {
+ static getMonth(DateTime receiver) {
return (receiver.isUtc)
? JS('JSUInt31', r'#.getUTCMonth() + 1', lazyAsJsDate(receiver))
: JS('JSUInt31', r'#.getMonth() + 1', lazyAsJsDate(receiver));
@@ -777,7 +762,7 @@
@pragma('dart2js:noSideEffects')
@pragma('dart2js:noThrows')
@pragma('dart2js:noInline')
- static int getDay(DateTime receiver) {
+ static getDay(DateTime receiver) {
return (receiver.isUtc)
? JS('JSUInt31', r'(#.getUTCDate() + 0)', lazyAsJsDate(receiver))
: JS('JSUInt31', r'(#.getDate() + 0)', lazyAsJsDate(receiver));
@@ -786,7 +771,7 @@
@pragma('dart2js:noSideEffects')
@pragma('dart2js:noThrows')
@pragma('dart2js:noInline')
- static int getHours(DateTime receiver) {
+ static getHours(DateTime receiver) {
return (receiver.isUtc)
? JS('JSUInt31', r'(#.getUTCHours() + 0)', lazyAsJsDate(receiver))
: JS('JSUInt31', r'(#.getHours() + 0)', lazyAsJsDate(receiver));
@@ -795,7 +780,7 @@
@pragma('dart2js:noSideEffects')
@pragma('dart2js:noThrows')
@pragma('dart2js:noInline')
- static int getMinutes(DateTime receiver) {
+ static getMinutes(DateTime receiver) {
return (receiver.isUtc)
? JS('JSUInt31', r'(#.getUTCMinutes() + 0)', lazyAsJsDate(receiver))
: JS('JSUInt31', r'(#.getMinutes() + 0)', lazyAsJsDate(receiver));
@@ -804,7 +789,7 @@
@pragma('dart2js:noSideEffects')
@pragma('dart2js:noThrows')
@pragma('dart2js:noInline')
- static int getSeconds(DateTime receiver) {
+ static getSeconds(DateTime receiver) {
return (receiver.isUtc)
? JS('JSUInt31', r'(#.getUTCSeconds() + 0)', lazyAsJsDate(receiver))
: JS('JSUInt31', r'(#.getSeconds() + 0)', lazyAsJsDate(receiver));
@@ -813,7 +798,7 @@
@pragma('dart2js:noSideEffects')
@pragma('dart2js:noThrows')
@pragma('dart2js:noInline')
- static int getMilliseconds(DateTime receiver) {
+ static getMilliseconds(DateTime receiver) {
return (receiver.isUtc)
? JS(
'JSUInt31', r'(#.getUTCMilliseconds() + 0)', lazyAsJsDate(receiver))
@@ -823,7 +808,7 @@
@pragma('dart2js:noSideEffects')
@pragma('dart2js:noThrows')
@pragma('dart2js:noInline')
- static int getWeekday(DateTime receiver) {
+ static getWeekday(DateTime receiver) {
int weekday = (receiver.isUtc)
? JS('int', r'#.getUTCDay() + 0', lazyAsJsDate(receiver))
: JS('int', r'#.getDay() + 0', lazyAsJsDate(receiver));
@@ -831,6 +816,13 @@
return (weekday + 6) % 7 + 1;
}
+ static num valueFromDateString(str) {
+ if (str is! String) throw argumentErrorValue(str);
+ num value = JS('num', r'Date.parse(#)', str);
+ if (value.isNaN) throw argumentErrorValue(str);
+ return value;
+ }
+
static getProperty(object, key) {
if (object == null || object is bool || object is num || object is String) {
throw argumentErrorValue(object);
diff --git a/sdk/lib/_internal/js_shared/lib/date_time_patch.dart b/sdk/lib/_internal/js_shared/lib/date_time_patch.dart
deleted file mode 100644
index ecba740..0000000
--- a/sdk/lib/_internal/js_shared/lib/date_time_patch.dart
+++ /dev/null
@@ -1,195 +0,0 @@
-// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:_foreign_helper' show JS;
-import 'dart:_internal' show patch;
-import 'dart:_js_helper' show checkInt, Primitives;
-
-// Patch for DateTime implementation.
-@patch
-class DateTime {
- /// The value component of this DateTime, equal to [millisecondsSinceEpoch].
- final int _value;
-
- /// The [microsecond] component of this DateTime, in the range [0...999].
- final int _microsecond;
-
- /// Constructor for pre-validated components.
- DateTime._(this._value, this._microsecond, {required this.isUtc});
-
- /// Constructs a new [DateTime] instance with the given value.
- ///
- /// If [isUtc] is false, then the date is in the local time zone.
- DateTime._withValueChecked(int millisecondsSinceEpoch, int microsecond,
- {required bool isUtc})
- : _value = _validate(millisecondsSinceEpoch, microsecond, isUtc),
- _microsecond = microsecond,
- this.isUtc = isUtc;
-
- @patch
- DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
- {bool isUtc = false})
- : this._withValueChecked(millisecondsSinceEpoch, 0, isUtc: isUtc);
-
- @patch
- DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
- {bool isUtc = false})
- : this._withValueChecked(
- (microsecondsSinceEpoch - microsecondsSinceEpoch % 1000) ~/ 1000,
- microsecondsSinceEpoch % 1000,
- isUtc: isUtc);
-
- @patch
- DateTime._internal(int year, int month, int day, int hour, int minute,
- int second, int millisecond, int microsecond, bool isUtc)
- // checkBool is manually inlined here because dart2js doesn't inline it
- // and [isUtc] is usually a constant.
- : this.isUtc =
- isUtc is bool ? isUtc : throw ArgumentError.value(isUtc, 'isUtc'),
- _value = Primitives.valueFromDecomposedDate(year, month, day, hour,
- minute, second, millisecond, microsecond, isUtc) ??
- _sentinel,
- _microsecond = microsecond % 1000 {
- if (_value == _sentinel) {
- throw ArgumentError('($year, $month, $day,'
- ' $hour, $minute, $second, $millisecond, $microsecond)');
- }
- }
-
- static const _sentinel = _maxMillisecondsSinceEpoch * 10;
- static const _sentinelConstraint = _sentinel < -_maxMillisecondsSinceEpoch ||
- _sentinel > _maxMillisecondsSinceEpoch;
- static const _sentinelAssertion = 1 ~/ (_sentinelConstraint ? 1 : 0);
-
- @patch
- DateTime._now()
- : isUtc = false,
- _value = Primitives.dateNow(),
- _microsecond = 0;
-
- @patch
- DateTime._nowUtc()
- : isUtc = true,
- _value = Primitives.dateNow(),
- _microsecond = 0;
-
- @patch
- DateTime _withUtc({required bool isUtc}) {
- return DateTime._(_value, _microsecond, isUtc: isUtc);
- }
-
- @patch
- static DateTime? _finishParse(int year, int month, int day, int hour,
- int minute, int second, int millisecond, int microsecond, bool isUtc) {
- final value = Primitives.valueFromDecomposedDate(year, month, day, hour,
- minute, second, millisecond, microsecond, isUtc);
- if (value == null) return null;
- return DateTime._withValueChecked(value, microsecond, isUtc: isUtc);
- }
-
- @patch
- String get timeZoneName {
- if (isUtc) return "UTC";
- return Primitives.getTimeZoneName(this);
- }
-
- @patch
- Duration get timeZoneOffset {
- if (isUtc) return Duration.zero;
- return Duration(minutes: Primitives.getTimeZoneOffsetInMinutes(this));
- }
-
- @patch
- DateTime add(Duration duration) => _addMicroseconds(duration.inMicroseconds);
-
- @patch
- DateTime subtract(Duration duration) =>
- _addMicroseconds(0 - duration.inMicroseconds);
-
- DateTime _addMicroseconds(int durationMicroseconds) {
- final durationLo = durationMicroseconds % 1000;
- final durationHi = (durationMicroseconds - durationLo) ~/ 1000;
- final sumLo = _microsecond + durationLo;
- final microsecond = sumLo % 1000;
- final carry = (sumLo - microsecond) ~/ 1000;
- final milliseconds = _value + carry + durationHi;
- return DateTime._withValueChecked(milliseconds, microsecond, isUtc: isUtc);
- }
-
- @patch
- Duration difference(DateTime other) {
- final deltaMilliseconds =
- millisecondsSinceEpoch - other.millisecondsSinceEpoch;
- final deltaMicroseconds = microsecond - other.microsecond;
- return Duration(
- milliseconds: deltaMilliseconds, microseconds: deltaMicroseconds);
- }
-
- @patch
- int get millisecondsSinceEpoch => _value;
-
- @patch
- int get microsecondsSinceEpoch => 1000 * _value + _microsecond;
-
- @patch
- int get year => Primitives.getYear(this);
-
- @patch
- int get month => Primitives.getMonth(this);
-
- @patch
- int get day => Primitives.getDay(this);
-
- @patch
- int get hour => Primitives.getHours(this);
-
- @patch
- int get minute => Primitives.getMinutes(this);
-
- @patch
- int get second => Primitives.getSeconds(this);
-
- @patch
- int get millisecond => Primitives.getMilliseconds(this);
-
- @patch
- int get microsecond => _microsecond;
-
- @patch
- int get weekday => Primitives.getWeekday(this);
-
- @patch
- bool operator ==(Object other) =>
- other is DateTime &&
- millisecondsSinceEpoch == other.millisecondsSinceEpoch &&
- microsecond == other.microsecond &&
- isUtc == other.isUtc;
-
- @patch
- int get hashCode => Object.hash(_value, _microsecond);
-
- @patch
- bool isBefore(DateTime other) =>
- millisecondsSinceEpoch < other.millisecondsSinceEpoch ||
- millisecondsSinceEpoch == other.millisecondsSinceEpoch &&
- microsecond < other.microsecond;
-
- @patch
- bool isAfter(DateTime other) =>
- millisecondsSinceEpoch > other.millisecondsSinceEpoch ||
- millisecondsSinceEpoch == other.millisecondsSinceEpoch &&
- microsecond > other.microsecond;
-
- @patch
- bool isAtSameMomentAs(DateTime other) =>
- millisecondsSinceEpoch == other.millisecondsSinceEpoch &&
- microsecond == other.microsecond;
-
- @patch
- int compareTo(DateTime other) {
- final r = millisecondsSinceEpoch.compareTo(other.millisecondsSinceEpoch);
- if (r != 0) return r;
- return microsecond.compareTo(other.microsecond);
- }
-}
diff --git a/sdk/lib/_internal/vm_shared/lib/date_patch.dart b/sdk/lib/_internal/vm_shared/lib/date_patch.dart
index 1f06867..b1fd03d 100644
--- a/sdk/lib/_internal/vm_shared/lib/date_patch.dart
+++ b/sdk/lib/_internal/vm_shared/lib/date_patch.dart
@@ -29,21 +29,8 @@
static const _MONTH_INDEX = 7;
static const _YEAR_INDEX = 8;
- /// The value of this DateTime, equal to [microsecondsSinceEpoch].
- final int _value;
-
List<int>? __parts;
- /// Constructor for pre-validated components.
- DateTime._(this._value, {required this.isUtc});
-
- /// Constructs a new [DateTime] instance with the given value.
- ///
- /// If [isUtc] is false, then the date is in the local time zone.
- DateTime._withValue(this._value, {required this.isUtc}) {
- _validate(millisecondsSinceEpoch, microsecond, isUtc);
- }
-
@patch
DateTime.fromMillisecondsSinceEpoch(int millisecondsSinceEpoch,
{bool isUtc = false})
@@ -57,10 +44,7 @@
{bool isUtc = false})
: this._withValue(microsecondsSinceEpoch, isUtc: isUtc);
- static const _sentinel = -_maxMicrosecondsSinceEpoch - 1;
- static const _sentinelConstraint = _sentinel < -_maxMicrosecondsSinceEpoch ||
- _sentinel > _maxMicrosecondsSinceEpoch;
- static const _sentinelAssertion = 1 ~/ (_sentinelConstraint ? 1 : 0);
+ static const _sentinelMs = -_maxMillisecondsSinceEpoch - 1;
@patch
DateTime._internal(int year, int month, int day, int hour, int minute,
@@ -68,11 +52,8 @@
: this.isUtc = checkNotNullable(isUtc, "isUtc"),
this._value = _brokenDownDateToValue(year, month, day, hour, minute,
second, millisecond, microsecond, isUtc) ??
- _sentinel {
- if (_value == _sentinel) {
- throw ArgumentError('($year, $month, $day,'
- ' $hour, $minute, $second, $millisecond, $microsecond)');
- }
+ _sentinelMs {
+ if (_value == _sentinelMs) throw new ArgumentError();
}
static int _validateMilliseconds(int millisecondsSinceEpoch) =>
@@ -93,11 +74,6 @@
_value = _getCurrentMicros();
@patch
- DateTime _withUtc({required bool isUtc}) {
- return DateTime._(_value, isUtc: isUtc);
- }
-
- @patch
String get timeZoneName {
if (isUtc) return "UTC";
return _timeZoneName(microsecondsSinceEpoch);
@@ -105,9 +81,9 @@
@patch
Duration get timeZoneOffset {
- if (isUtc) return Duration();
+ if (isUtc) return new Duration();
int offsetInSeconds = _timeZoneOffsetInSeconds(microsecondsSinceEpoch);
- return Duration(seconds: offsetInSeconds);
+ return new Duration(seconds: offsetInSeconds);
}
@patch
@@ -117,9 +93,6 @@
isUtc == other.isUtc;
@patch
- int get hashCode => (_value ^ (_value >> 30)) & 0x3FFFFFFF;
-
- @patch
bool isBefore(DateTime other) => _value < other.microsecondsSinceEpoch;
@patch
@@ -133,11 +106,11 @@
int compareTo(DateTime other) =>
_value.compareTo(other.microsecondsSinceEpoch);
- /// The first list contains the days until each month in non-leap years. The
- /// second list contains the days in leap years.
- static const List<List<int>> _DAYS_UNTIL_MONTH = [
- [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
- [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
+ /** The first list contains the days until each month in non-leap years. The
+ * second list contains the days in leap years. */
+ static const List<List<int>> _DAYS_UNTIL_MONTH = const [
+ const [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334],
+ const [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335]
];
static List<int> _computeUpperPart(int localMicros) {
@@ -207,7 +180,7 @@
DateTime.daysPerWeek) +
DateTime.monday;
- List<int> list = List<int>.filled(_YEAR_INDEX + 1, 0);
+ List<int> list = new List<int>.filled(_YEAR_INDEX + 1, 0);
list[_MICROSECOND_INDEX] = resultMicrosecond;
list[_MILLISECOND_INDEX] = resultMillisecond;
list[_SECOND_INDEX] = resultSecond;
@@ -226,22 +199,24 @@
@patch
DateTime add(Duration duration) {
- return DateTime._withValue(_value + duration.inMicroseconds, isUtc: isUtc);
+ return new DateTime._withValue(_value + duration.inMicroseconds,
+ isUtc: isUtc);
}
@patch
DateTime subtract(Duration duration) {
- return DateTime._withValue(_value - duration.inMicroseconds, isUtc: isUtc);
+ return new DateTime._withValue(_value - duration.inMicroseconds,
+ isUtc: isUtc);
}
@patch
Duration difference(DateTime other) {
- return Duration(microseconds: _value - other.microsecondsSinceEpoch);
+ return new Duration(microseconds: _value - other.microsecondsSinceEpoch);
}
@patch
int get millisecondsSinceEpoch =>
- _flooredDivision(_value, Duration.microsecondsPerMillisecond);
+ _value ~/ Duration.microsecondsPerMillisecond;
@patch
int get microsecondsSinceEpoch => _value;
@@ -273,19 +248,21 @@
@patch
int get year => _parts[_YEAR_INDEX];
- /// Returns the amount of microseconds in UTC that represent the same values
- /// as this [DateTime].
- ///
- /// Say `t` is the result of this function, then
- /// * `this.year == new DateTime.fromMicrosecondsSinceEpoch(t, true).year`,
- /// * `this.month == new DateTime.fromMicrosecondsSinceEpoch(t, true).month`,
- /// * `this.day == new DateTime.fromMicrosecondsSinceEpoch(t, true).day`,
- /// * `this.hour == new DateTime.fromMicrosecondsSinceEpoch(t, true).hour`,
- /// * ...
- ///
- /// Daylight savings is computed as if the date was computed in [1970..2037].
- /// If this [DateTime] lies outside this range then a year with similar
- /// properties (leap year, weekdays) is used instead.
+ /**
+ * Returns the amount of microseconds in UTC that represent the same values
+ * as this [DateTime].
+ *
+ * Say `t` is the result of this function, then
+ * * `this.year == new DateTime.fromMicrosecondsSinceEpoch(t, true).year`,
+ * * `this.month == new DateTime.fromMicrosecondsSinceEpoch(t, true).month`,
+ * * `this.day == new DateTime.fromMicrosecondsSinceEpoch(t, true).day`,
+ * * `this.hour == new DateTime.fromMicrosecondsSinceEpoch(t, true).hour`,
+ * * ...
+ *
+ * Daylight savings is computed as if the date was computed in [1970..2037].
+ * If this [DateTime] lies outside this range then it is a year with similar
+ * properties (leap year, weekdays) is used instead.
+ */
int get _localDateInUtcMicros {
int micros = _value;
if (isUtc) return micros;
@@ -313,6 +290,7 @@
}
/// Converts the given broken down date to microseconds.
+ @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.
@@ -360,26 +338,19 @@
return microsecondsSinceEpoch;
}
- @patch
- static DateTime? _finishParse(int year, int month, int day, int hour,
- int minute, int second, int millisecond, int microsecond, bool isUtc) {
- final value = _brokenDownDateToValue(year, month, day, hour, minute, second,
- millisecond, microsecond, isUtc);
- if (value == null) return null;
- return DateTime._withValue(value, isUtc: isUtc);
- }
-
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.
+ /**
+ * 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).
@@ -399,10 +370,12 @@
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.
+ /**
+ * 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;
@@ -417,16 +390,18 @@
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.
+ /**
+ * 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;
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index 6c53f7f..366995c 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -159,6 +159,13 @@
static const int december = 12;
static const int monthsPerYear = 12;
+ /// The value of this DateTime.
+ ///
+ /// The content of this field is implementation dependent. On JavaScript it is
+ /// equal to [millisecondsSinceEpoch]. On the VM it is equal to
+ /// [microsecondsSinceEpoch].
+ final int _value;
+
/// True if this [DateTime] is set to UTC time.
///
/// ```dart
@@ -341,12 +348,12 @@
minute -= sign * minuteDifference;
}
}
- DateTime? result = _finishParse(years, month, day, hour, minute, second,
- millisecond, microsecond, isUtc);
- if (result == null) {
+ int? value = _brokenDownDateToValue(years, month, day, hour, minute,
+ second, millisecond, microsecond, isUtc);
+ if (value == null) {
throw FormatException("Time out of range", formattedString);
}
- return result;
+ return DateTime._withValue(value, isUtc: isUtc);
} else {
throw FormatException("Invalid date format", formattedString);
}
@@ -366,8 +373,6 @@
}
static const int _maxMillisecondsSinceEpoch = 8640000000000000;
- static const int _maxMicrosecondsSinceEpoch =
- _maxMillisecondsSinceEpoch * Duration.microsecondsPerMillisecond;
/// Constructs a new [DateTime] instance
/// with the given [millisecondsSinceEpoch].
@@ -401,33 +406,18 @@
external DateTime.fromMicrosecondsSinceEpoch(int microsecondsSinceEpoch,
{bool isUtc = false});
- /// Throws an error if the millisecondsSinceEpoch and microsecond components
- /// are out of range.
+ /// Constructs a new [DateTime] instance with the given value.
///
- /// Returns the millisecondsSinceEpoch component.
- static int _validate(
- int millisecondsSinceEpoch, int microsecond, bool isUtc) {
- if (microsecond < 0 || microsecond > 999) {
- throw RangeError.range(microsecond, 0, 999, "microsecond");
+ /// If [isUtc] is false, then the date is in the local time zone.
+ DateTime._withValue(this._value, {required this.isUtc}) {
+ if (millisecondsSinceEpoch.abs() > _maxMillisecondsSinceEpoch ||
+ (millisecondsSinceEpoch.abs() == _maxMillisecondsSinceEpoch &&
+ microsecond != 0)) {
+ throw ArgumentError(
+ "DateTime is outside valid range: $millisecondsSinceEpoch");
}
- if (millisecondsSinceEpoch < -_maxMillisecondsSinceEpoch ||
- millisecondsSinceEpoch > _maxMillisecondsSinceEpoch) {
- throw RangeError.range(
- millisecondsSinceEpoch,
- -_maxMillisecondsSinceEpoch,
- _maxMillisecondsSinceEpoch,
- "millisecondsSinceEpoch");
- }
- if (millisecondsSinceEpoch == _maxMillisecondsSinceEpoch &&
- microsecond != 0) {
- throw ArgumentError.value(microsecond, "microsecond",
- "Time including microseconds is outside valid range");
- }
-
// For backwards compatibility with legacy mode.
checkNotNullable(isUtc, "isUtc");
-
- return millisecondsSinceEpoch;
}
/// Whether [other] is a [DateTime] at the same moment and in the
@@ -446,8 +436,6 @@
/// independently of their zones.
external bool operator ==(Object other);
- external int get hashCode;
-
/// Whether this [DateTime] occurs before [other].
///
/// The comparison is independent
@@ -528,6 +516,8 @@
/// ```
external int compareTo(DateTime other);
+ int get hashCode => (_value ^ (_value >> 30)) & 0x3FFFFFFF;
+
/// Returns this DateTime value in the local time zone.
///
/// Returns this [DateTime] if it is already in the local time zone.
@@ -539,7 +529,7 @@
/// ```
DateTime toLocal() {
if (isUtc) {
- return _withUtc(isUtc: false);
+ return DateTime._withValue(_value, isUtc: false);
}
return this;
}
@@ -555,11 +545,9 @@
/// ```
DateTime toUtc() {
if (isUtc) return this;
- return _withUtc(isUtc: true);
+ return DateTime._withValue(_value, isUtc: true);
}
- external DateTime _withUtc({required bool isUtc});
-
static String _fourDigits(int n) {
int absN = n.abs();
String sign = n < 0 ? "-" : "";
@@ -724,10 +712,18 @@
external DateTime._now();
- /// Returns the [DateTime] corresponding to the given components, or `null` if
- /// the values are out of range.
- external static DateTime? _finishParse(int year, int month, int day, int hour,
- int minute, int second, int millisecond, int microsecond, bool isUtc);
+ /// Returns the time as value (millisecond or microsecond since epoch), or
+ /// null if the values are out of range.
+ external static int? _brokenDownDateToValue(
+ int year,
+ int month,
+ int day,
+ int hour,
+ int minute,
+ int second,
+ int millisecond,
+ int microsecond,
+ bool isUtc);
/// The number of milliseconds since
/// the "Unix epoch" 1970-01-01T00:00:00Z (UTC).
@@ -748,10 +744,8 @@
/// 8,640,000,000,000,000,000us (100,000,000 days) from the Unix epoch.
/// In other words: `microsecondsSinceEpoch.abs() <= 8640000000000000000`.
///
- /// Note that this value does not always fit into 53 bits (the size of a IEEE
- /// double). On the web JavaScript platforms, there may be a rounding error
- /// for DateTime values sufficiently far from the epoch. The year range close
- /// to the epoch to avoid rounding is approximately 1685..2254.
+ /// Note that this value does not fit into 53 bits (the size of a IEEE double).
+ /// A JavaScript number is not able to hold this value.
external int get microsecondsSinceEpoch;
/// The time zone name.
diff --git a/sdk/lib/libraries.json b/sdk/lib/libraries.json
index a00925f..56265a2 100644
--- a/sdk/lib/libraries.json
+++ b/sdk/lib/libraries.json
@@ -390,10 +390,7 @@
},
"core": {
"uri": "core/core.dart",
- "patches": [
- "_internal/js_shared/lib/date_time_patch.dart",
- "_internal/js_runtime/lib/core_patch.dart"
- ]
+ "patches": "_internal/js_runtime/lib/core_patch.dart"
},
"developer": {
"uri": "developer/developer.dart",
@@ -573,10 +570,7 @@
},
"core": {
"uri": "core/core.dart",
- "patches": [
- "_internal/js_shared/lib/date_time_patch.dart",
- "_internal/js_dev_runtime/patch/core_patch.dart"
- ]
+ "patches": "_internal/js_dev_runtime/patch/core_patch.dart"
},
"developer": {
"uri": "developer/developer.dart",
diff --git a/sdk/lib/libraries.yaml b/sdk/lib/libraries.yaml
index e843722c..068e1b2 100644
--- a/sdk/lib/libraries.yaml
+++ b/sdk/lib/libraries.yaml
@@ -319,9 +319,7 @@
core:
uri: "core/core.dart"
- patches:
- - "_internal/js_shared/lib/date_time_patch.dart"
- - "_internal/js_runtime/lib/core_patch.dart"
+ patches: "_internal/js_runtime/lib/core_patch.dart"
developer:
uri: "developer/developer.dart"
@@ -497,9 +495,7 @@
core:
uri: "core/core.dart"
- patches:
- - "_internal/js_shared/lib/date_time_patch.dart"
- - "_internal/js_dev_runtime/patch/core_patch.dart"
+ patches: "_internal/js_dev_runtime/patch/core_patch.dart"
developer:
uri: "developer/developer.dart"
diff --git a/tests/corelib/date_time_extremes_test.dart b/tests/corelib/date_time_extremes_test.dart
index ad5316f..57facb1 100644
--- a/tests/corelib/date_time_extremes_test.dart
+++ b/tests/corelib/date_time_extremes_test.dart
@@ -7,13 +7,14 @@
// Dart test program for DateTime, extreme values.
bool get supportsMicroseconds =>
- DateTime.fromMicrosecondsSinceEpoch(1).microsecondsSinceEpoch == 1;
+ new DateTime.fromMicrosecondsSinceEpoch(1).microsecondsSinceEpoch == 1;
// Identical to _maxMillisecondsSinceEpoch in date_time.dart
const int _MAX_MILLISECONDS = 8640000000000000;
void testExtremes() {
- var dt = DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS, isUtc: true);
+ var dt =
+ new DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS, isUtc: true);
Expect.equals(275760, dt.year);
Expect.equals(9, dt.month);
Expect.equals(13, dt.day);
@@ -22,7 +23,7 @@
Expect.equals(0, dt.second);
Expect.equals(0, dt.millisecond);
Expect.equals(0, dt.microsecond);
- dt = DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS, isUtc: true);
+ dt = new DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS, isUtc: true);
Expect.equals(-271821, dt.year);
Expect.equals(4, dt.month);
Expect.equals(20, dt.day);
@@ -32,103 +33,71 @@
Expect.equals(0, dt.millisecond);
Expect.equals(0, dt.microsecond);
// Make sure that we can build the extreme dates in local too.
- dt = DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS);
- dt = DateTime(
+ dt = new DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS);
+ dt = new DateTime(
dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.millisecond);
Expect.equals(_MAX_MILLISECONDS, dt.millisecondsSinceEpoch);
- dt = DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS);
- dt = DateTime(
+ dt = new DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS);
+ dt = new DateTime(
dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.millisecond);
Expect.equals(-_MAX_MILLISECONDS, dt.millisecondsSinceEpoch);
+ Expect.throws(() => new DateTime.fromMillisecondsSinceEpoch(
+ _MAX_MILLISECONDS + 1,
+ isUtc: true));
+ Expect.throws(() => new DateTime.fromMillisecondsSinceEpoch(
+ -_MAX_MILLISECONDS - 1,
+ isUtc: true));
+ Expect.throws(
+ () => new DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS + 1));
+ Expect.throws(
+ () => new DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS - 1));
+ dt = new DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS);
+ Expect.throws(
+ () => new DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 1));
+ dt = new DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS, isUtc: true);
Expect.throws(() =>
- DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS + 1, isUtc: true));
+ new DateTime.utc(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 1));
+ dt = new DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS);
+ Expect.throws(
+ () => new DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, -1));
+ dt = new DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS, isUtc: true);
Expect.throws(() =>
- DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS - 1, isUtc: true));
- Expect.throws(
- () => DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS + 1));
- Expect.throws(
- () => DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS - 1));
- dt = DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS);
- Expect.throws(
- () => DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 1));
- dt = DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS, isUtc: true);
- Expect.throws(
- () => DateTime.utc(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 1));
- dt = DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS);
- Expect.throws(
- () => DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, -1));
- dt = DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS, isUtc: true);
- Expect.throws(
- () => DateTime.utc(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, -1));
+ new DateTime.utc(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, -1));
if (!supportsMicroseconds) return;
- /// The nearest value to [base] in the direction [delta]. For native `int`s,
- /// this is just `base + delta`. For web `int`s outside the safe range, the
- /// next value might differ by some power of two.
- int nearest(int base, int delta) {
- for (int factor = 1;; factor *= 2) {
- final next = base + delta * factor;
- print(factor);
- if (next != base) return next;
- }
- }
-
- dt = DateTime.fromMicrosecondsSinceEpoch(_MAX_MILLISECONDS * 1000);
- dt = DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second);
+ dt = new DateTime.fromMicrosecondsSinceEpoch(_MAX_MILLISECONDS * 1000);
+ dt = new DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute);
Expect.equals(_MAX_MILLISECONDS * 1000, dt.microsecondsSinceEpoch);
- print(-_MAX_MILLISECONDS * 1000);
- dt = DateTime.fromMicrosecondsSinceEpoch(-_MAX_MILLISECONDS * 1000);
- dt = DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second);
+ dt = new DateTime.fromMicrosecondsSinceEpoch(-_MAX_MILLISECONDS * 1000);
+ dt = new DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute);
Expect.equals(-_MAX_MILLISECONDS * 1000, dt.microsecondsSinceEpoch);
- Expect.throws(() => DateTime.fromMicrosecondsSinceEpoch(
- nearest(_MAX_MILLISECONDS * 1000, 1),
+ Expect.throws(() => new DateTime.fromMicrosecondsSinceEpoch(
+ _MAX_MILLISECONDS * 1000 + 1,
isUtc: true));
- Expect.throws(() => DateTime.fromMicrosecondsSinceEpoch(
- nearest(-_MAX_MILLISECONDS * 1000, -1),
+ Expect.throws(() => new DateTime.fromMicrosecondsSinceEpoch(
+ -_MAX_MILLISECONDS * 1000 - 1,
isUtc: true));
- Expect.throws(() => DateTime.fromMicrosecondsSinceEpoch(
- nearest(_MAX_MILLISECONDS * 1000, 1)));
- Expect.throws(() => DateTime.fromMicrosecondsSinceEpoch(
- nearest(-_MAX_MILLISECONDS * 1000, -1)));
- // These should all succeed - stepping into the valid range rather than out:
- DateTime.fromMicrosecondsSinceEpoch(nearest(-_MAX_MILLISECONDS * 1000, 1),
- isUtc: true);
- DateTime.fromMicrosecondsSinceEpoch(nearest(_MAX_MILLISECONDS * 1000, -1),
- isUtc: true);
- DateTime.fromMicrosecondsSinceEpoch(nearest(-_MAX_MILLISECONDS * 1000, 1));
- DateTime.fromMicrosecondsSinceEpoch(nearest(_MAX_MILLISECONDS * 1000, -1));
-
- dt = DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS);
- Expect.throws(
- () => DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 0, 1));
- Expect.throws(() => dt.copyWith(microsecond: 1));
- Expect.isTrue(dt.copyWith(microsecond: -1).toString().endsWith('.999999'));
-
- dt = DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS, isUtc: true);
Expect.throws(() =>
- DateTime.utc(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 0, 1));
- Expect.throws(() => dt.copyWith(microsecond: 1));
- Expect.isTrue(dt.copyWith(microsecond: -1).toString().endsWith('.999999Z'));
-
- dt = DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS);
- Expect.throws(
- () => DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 0, -1));
- Expect.throws(() => dt.copyWith(microsecond: -1));
- Expect.isTrue(dt.copyWith(microsecond: 1).toString().endsWith('.000001'));
-
- dt = DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS, isUtc: true);
+ new DateTime.fromMicrosecondsSinceEpoch(_MAX_MILLISECONDS * 1000 + 1));
Expect.throws(() =>
- DateTime.utc(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 0, -1));
- Expect.throws(() => dt.copyWith(microsecond: -1));
- Expect.isTrue(dt.copyWith(microsecond: 1).toString().endsWith('.000001Z'));
+ new DateTime.fromMicrosecondsSinceEpoch(-_MAX_MILLISECONDS * 1000 - 1));
+ dt = new DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS);
+ Expect.throws(() =>
+ new DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 0, 1));
+ dt = new DateTime.fromMillisecondsSinceEpoch(_MAX_MILLISECONDS, isUtc: true);
+ Expect.throws(() =>
+ new DateTime.utc(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 0, 1));
+ dt = new DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS);
+ Expect.throws(() =>
+ new DateTime(dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 0, -1));
+ dt = new DateTime.fromMillisecondsSinceEpoch(-_MAX_MILLISECONDS, isUtc: true);
+ Expect.throws(() => new DateTime.utc(
+ dt.year, dt.month, dt.day, dt.hour, dt.minute, 0, 0, -1));
// Regression test for https://dartbug.com/55438
dt = DateTime.utc(1969, 12, 31, 23, 59, 59, 999, 999);
Expect.equals(-1, dt.microsecondsSinceEpoch);
- // The first fix confused millisecondsSinceEpoch and microsecondsSinceEpoch.
- dt = DateTime.utc(1696, 3, 16, 23, 59, 59, 999, 999);
- Expect.equals(-_MAX_MILLISECONDS - 1, dt.microsecondsSinceEpoch);
}
void main() {