-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
duration.dart
388 lines (339 loc) · 14.6 KB
/
duration.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
// Copyright (c) 2011, 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.
part of dart.core;
/// A span of time, such as 27 days, 4 hours, 12 minutes, and 3 seconds.
///
/// A `Duration` represents a difference from one point in time to another. The
/// duration may be "negative" if the difference is from a later time to an
/// earlier.
///
/// Durations are context independent. For example, a duration of 2 days is
/// always 48 hours, even when it is added to a `DateTime` just when the
/// time zone is about to make a daylight-savings switch. (See [DateTime.add]).
///
/// Despite the same name, a `Duration` object does not implement "Durations"
/// as specified by ISO 8601. In particular, a duration object does not keep
/// track of the individually provided members (such as "days" or "hours"), but
/// only uses these arguments to compute the length of the corresponding time
/// interval.
///
/// To create a new `Duration` object, use this class's single constructor
/// giving the appropriate arguments:
/// ```dart
/// const fastestMarathon = Duration(hours: 2, minutes: 3, seconds: 2);
/// ```
/// The [Duration] represents a single number of microseconds,
/// which is the sum of all the individual arguments to the constructor.
///
/// Properties can access that single number in different ways.
/// For example the [inMinutes] gives the number of whole minutes
/// in the total duration, which includes the minutes that were provided
/// as "hours" to the constructor, and can be larger than 59.
///
/// ```dart
/// const fastestMarathon = Duration(hours: 2, minutes: 3, seconds: 2);
/// print(fastestMarathon.inDays); // 0
/// print(fastestMarathon.inHours); // 2
/// print(fastestMarathon.inMinutes); // 123
/// print(fastestMarathon.inSeconds); // 7382
/// print(fastestMarathon.inMilliseconds); // 7382000
/// ```
/// The duration can be negative, in which case
/// all the properties derived from the duration are also non-positive.
/// ```dart
/// const overDayAgo = Duration(days: -1, hours: -10);
/// print(overDayAgo.inDays); // -1
/// print(overDayAgo.inHours); // -34
/// print(overDayAgo.inMinutes); // -2040
/// ```
/// Use one of the properties, such as [inDays],
/// to retrieve the integer value of the `Duration` in the specified time unit.
/// Note that the returned value is rounded down.
/// For example,
/// ```dart
/// const aLongWeekend = Duration(hours: 88);
/// print(aLongWeekend.inDays); // 3
/// ```
/// This class provides a collection of arithmetic
/// and comparison operators,
/// plus a set of constants useful for converting time units.
/// ```dart
/// const firstHalf = Duration(minutes: 45); // 00:45:00.000000
/// const secondHalf = Duration(minutes: 45); // 00:45:00.000000
/// const overTime = Duration(minutes: 30); // 00:30:00.000000
/// final maxGameTime = firstHalf + secondHalf + overTime;
/// print(maxGameTime.inMinutes); // 120
///
/// // The duration of the firstHalf and secondHalf is the same, returns 0.
/// var result = firstHalf.compareTo(secondHalf);
/// print(result); // 0
///
/// // Duration of overTime is shorter than firstHalf, returns < 0.
/// result = overTime.compareTo(firstHalf);
/// print(result); // < 0
///
/// // Duration of secondHalf is longer than overTime, returns > 0.
/// result = secondHalf.compareTo(overTime);
/// print(result); // > 0
/// ```
///
/// **See also:**
/// * [DateTime] to represent a point in time.
/// * [Stopwatch] to measure time-spans.
class Duration implements Comparable<Duration> {
/// The number of microseconds per millisecond.
static const int microsecondsPerMillisecond = 1000;
/// The number of milliseconds per second.
static const int millisecondsPerSecond = 1000;
/// The number of seconds per minute.
///
/// Notice that some minutes of official clock time might
/// differ in length because of leap seconds.
/// The [Duration] and [DateTime] classes ignore leap seconds
/// and consider all minutes to have 60 seconds.
static const int secondsPerMinute = 60;
/// The number of minutes per hour.
static const int minutesPerHour = 60;
/// The number of hours per day.
///
/// Notice that some days may differ in length because
/// of time zone changes due to daylight saving.
/// The [Duration] class is time zone agnostic and
/// considers all days to have 24 hours.
static const int hoursPerDay = 24;
/// The number of microseconds per second.
static const int microsecondsPerSecond =
microsecondsPerMillisecond * millisecondsPerSecond;
/// The number of microseconds per minute.
static const int microsecondsPerMinute =
microsecondsPerSecond * secondsPerMinute;
/// The number of microseconds per hour.
static const int microsecondsPerHour = microsecondsPerMinute * minutesPerHour;
/// The number of microseconds per day.
static const int microsecondsPerDay = microsecondsPerHour * hoursPerDay;
/// The number of milliseconds per minute.
static const int millisecondsPerMinute =
millisecondsPerSecond * secondsPerMinute;
/// The number of milliseconds per hour.
static const int millisecondsPerHour = millisecondsPerMinute * minutesPerHour;
/// The number of milliseconds per day.
static const int millisecondsPerDay = millisecondsPerHour * hoursPerDay;
/// The number of seconds per hour.
static const int secondsPerHour = secondsPerMinute * minutesPerHour;
/// The number of seconds per day.
static const int secondsPerDay = secondsPerHour * hoursPerDay;
/// The number of minutes per day.
static const int minutesPerDay = minutesPerHour * hoursPerDay;
/// An empty duration, representing zero time.
static const Duration zero = Duration(seconds: 0);
/// The total microseconds of this [Duration] object.
final int _duration;
/// Creates a new [Duration] object whose value
/// is the sum of all individual parts.
///
/// Individual parts can be larger than the number of those
/// parts in the next larger unit.
/// For example, [hours] can be greater than 23.
/// If this happens, the value overflows into the next larger
/// unit, so 26 [hours] is the same as 2 [hours] and
/// one more [days].
/// Likewise, values can be negative, in which case they
/// underflow and subtract from the next larger unit.
///
/// If the total number of microseconds cannot be represented
/// as an integer value, the number of microseconds might overflow
/// and be truncated to a smaller number of bits,
/// or it might lose precision.
///
/// All arguments are 0 by default.
/// ```dart
/// const duration = Duration(days: 1, hours: 8, minutes: 56, seconds: 59,
/// milliseconds: 30, microseconds: 10);
/// print(duration); // 32:56:59.030010
/// ```
const Duration(
{int days = 0,
int hours = 0,
int minutes = 0,
int seconds = 0,
int milliseconds = 0,
int microseconds = 0})
: this._microseconds(microseconds +
microsecondsPerMillisecond * milliseconds +
microsecondsPerSecond * seconds +
microsecondsPerMinute * minutes +
microsecondsPerHour * hours +
microsecondsPerDay * days);
// Fast path internal direct constructor to avoids the optional arguments
// and [_microseconds] recomputation.
// The `+ 0` prevents -0.0 on the web, if the incoming duration happens to be -0.0.
const Duration._microseconds(int duration) : _duration = duration + 0;
/// Adds this Duration and [other] and
/// returns the sum as a new Duration object.
Duration operator +(Duration other) {
return Duration._microseconds(_duration + other._duration);
}
/// Subtracts [other] from this Duration and
/// returns the difference as a new Duration object.
Duration operator -(Duration other) {
return Duration._microseconds(_duration - other._duration);
}
/// Multiplies this Duration by the given [factor] and returns the result
/// as a new Duration object.
///
/// Note that when [factor] is a double, and the duration is greater than
/// 53 bits, precision is lost because of double-precision arithmetic.
Duration operator *(num factor) {
return Duration._microseconds((_duration * factor).round());
}
/// Divides this Duration by the given [quotient] and returns the truncated
/// result as a new Duration object.
///
/// The [quotient] must not be `0`.
Duration operator ~/(int quotient) {
// By doing the check here instead of relying on "~/" below we get the
// exception even with dart2js.
if (quotient == 0) throw IntegerDivisionByZeroException();
return Duration._microseconds(_duration ~/ quotient);
}
/// Whether this [Duration] is shorter than [other].
bool operator <(Duration other) => this._duration < other._duration;
/// Whether this [Duration] is longer than [other].
bool operator >(Duration other) => this._duration > other._duration;
/// Whether this [Duration] is shorter than or equal to [other].
bool operator <=(Duration other) => this._duration <= other._duration;
/// Whether this [Duration] is longer than or equal to [other].
bool operator >=(Duration other) => this._duration >= other._duration;
/// The number of entire days spanned by this [Duration].
///
/// For example, a duration of four days and three hours
/// has four entire days.
/// ```dart
/// const duration = Duration(days: 4, hours: 3);
/// print(duration.inDays); // 4
/// ```
int get inDays => _duration ~/ Duration.microsecondsPerDay;
/// The number of entire hours spanned by this [Duration].
///
/// The returned value can be greater than 23.
/// For example, a duration of four days and three hours
/// has 99 entire hours.
/// ```dart
/// const duration = Duration(days: 4, hours: 3);
/// print(duration.inHours); // 99
/// ```
int get inHours => _duration ~/ Duration.microsecondsPerHour;
/// The number of whole minutes spanned by this [Duration].
///
/// The returned value can be greater than 59.
/// For example, a duration of three hours and 12 minutes
/// has 192 minutes.
/// ```dart
/// const duration = Duration(hours: 3, minutes: 12);
/// print(duration.inMinutes); // 192
/// ```
int get inMinutes => _duration ~/ Duration.microsecondsPerMinute;
/// The number of whole seconds spanned by this [Duration].
///
/// The returned value can be greater than 59.
/// For example, a duration of three minutes and 12 seconds
/// has 192 seconds.
/// ```dart
/// const duration = Duration(minutes: 3, seconds: 12);
/// print(duration.inSeconds); // 192
/// ```
int get inSeconds => _duration ~/ Duration.microsecondsPerSecond;
/// The number of whole milliseconds spanned by this [Duration].
///
/// The returned value can be greater than 999.
/// For example, a duration of three seconds and 125 milliseconds
/// has 3125 milliseconds.
/// ```dart
/// const duration = Duration(seconds: 3, milliseconds: 125);
/// print(duration.inMilliseconds); // 3125
/// ```
int get inMilliseconds => _duration ~/ Duration.microsecondsPerMillisecond;
/// The number of whole microseconds spanned by this [Duration].
///
/// The returned value can be greater than 999999.
/// For example, a duration of three seconds, 125 milliseconds and
/// 369 microseconds has 3125369 microseconds.
/// ```dart
/// const duration = Duration(seconds: 3, milliseconds: 125,
/// microseconds: 369);
/// print(duration.inMicroseconds); // 3125369
/// ```
int get inMicroseconds => _duration;
/// Whether this [Duration] has the same length as [other].
///
/// Durations have the same length if they have the same number
/// of microseconds, as reported by [inMicroseconds].
bool operator ==(Object other) =>
other is Duration && _duration == other.inMicroseconds;
int get hashCode => _duration.hashCode;
/// Compares this [Duration] to [other], returning zero if the values are equal.
///
/// Returns a negative integer if this [Duration] is shorter than
/// [other], or a positive integer if it is longer.
///
/// A negative [Duration] is always considered shorter than a positive one.
///
/// It is always the case that `duration1.compareTo(duration2) < 0` iff
/// `(someDate + duration1).compareTo(someDate + duration2) < 0`.
int compareTo(Duration other) => _duration.compareTo(other._duration);
/// Returns a string representation of this [Duration].
///
/// Returns a string with hours, minutes, seconds, and microseconds, in the
/// following format: `H:MM:SS.mmmmmm`. For example,
/// ```dart
/// var d = const Duration(days: 1, hours: 1, minutes: 33, microseconds: 500);
/// print(d.toString()); // 25:33:00.000500
///
/// d = const Duration(hours: 1, minutes: 10, microseconds: 500);
/// print(d.toString()); // 1:10:00.000500
/// ```
String toString() {
var microseconds = inMicroseconds;
var sign = "";
var negative = microseconds < 0;
var hours = microseconds ~/ microsecondsPerHour;
microseconds = microseconds.remainder(microsecondsPerHour);
// Correcting for being negative after first division, instead of before,
// to avoid negating min-int, -(2^31-1), of a native int64.
if (negative) {
hours = 0 - hours; // Not using `-hours` to avoid creating -0.0 on web.
microseconds = 0 - microseconds;
sign = "-";
}
var minutes = microseconds ~/ microsecondsPerMinute;
microseconds = microseconds.remainder(microsecondsPerMinute);
var minutesPadding = minutes < 10 ? "0" : "";
var seconds = microseconds ~/ microsecondsPerSecond;
microseconds = microseconds.remainder(microsecondsPerSecond);
var secondsPadding = seconds < 10 ? "0" : "";
// Padding up to six digits for microseconds.
var microsecondsText = microseconds.toString().padLeft(6, "0");
return "$sign$hours:"
"$minutesPadding$minutes:"
"$secondsPadding$seconds."
"$microsecondsText";
}
/// Whether this [Duration] is negative.
///
/// A negative [Duration] represents the difference from a later time to an
/// earlier time.
bool get isNegative => _duration < 0;
/// Creates a new [Duration] representing the absolute length of this
/// [Duration].
///
/// The returned [Duration] has the same length as this one, but is always
/// positive where possible.
Duration abs() => Duration._microseconds(_duration.abs());
/// Creates a new [Duration] with the opposite direction of this [Duration].
///
/// The returned [Duration] has the same length as this one, but will have the
/// opposite sign (as reported by [isNegative]) as this one where possible.
// Using subtraction helps dart2js avoid negative zeros.
Duration operator -() => Duration._microseconds(0 - _duration);
}