1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Temporal quantification
16 use ops::{Add, Sub, Mul, Div, Neg};
17 use option::{Option, Some, None};
19 use num::{CheckedAdd, CheckedMul};
20 use result::{Result, Ok, Err};
22 /// The number of nanoseconds in a microsecond.
23 const NANOS_PER_MICRO: i32 = 1000;
24 /// The number of nanoseconds in a millisecond.
25 const NANOS_PER_MILLI: i32 = 1000_000;
26 /// The number of nanoseconds in seconds.
27 const NANOS_PER_SEC: i32 = 1_000_000_000;
28 /// The number of microseconds per second.
29 const MICROS_PER_SEC: i64 = 1000_000;
30 /// The number of milliseconds per second.
31 const MILLIS_PER_SEC: i64 = 1000;
32 /// The number of seconds in a minute.
33 const SECS_PER_MINUTE: i64 = 60;
34 /// The number of seconds in an hour.
35 const SECS_PER_HOUR: i64 = 3600;
36 /// The number of (non-leap) seconds in days.
37 const SECS_PER_DAY: i64 = 86400;
38 /// The number of (non-leap) seconds in a week.
39 const SECS_PER_WEEK: i64 = 604800;
42 ($e:expr) => (match $e { Some(v) => v, None => return None })
46 /// ISO 8601 time duration with nanosecond precision.
47 /// This also allows for the negative duration; see individual methods for details.
48 #[deriving(Clone, PartialEq, Eq, PartialOrd, Ord)]
51 nanos: i32, // Always 0 <= nanos < NANOS_PER_SEC
54 /// The minimum possible `Duration`: `i64::MIN` milliseconds.
55 pub const MIN: Duration = Duration {
56 secs: i64::MIN / MILLIS_PER_SEC - 1,
57 nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
60 /// The maximum possible `Duration`: `i64::MAX` milliseconds.
61 pub const MAX: Duration = Duration {
62 secs: i64::MAX / MILLIS_PER_SEC,
63 nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
67 /// Makes a new `Duration` with given number of weeks.
68 /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60), with overflow checks.
69 /// Fails when the duration is out of bounds.
71 pub fn weeks(weeks: i64) -> Duration {
72 let secs = weeks.checked_mul(&SECS_PER_WEEK).expect("Duration::weeks out of bounds");
73 Duration::seconds(secs)
76 /// Makes a new `Duration` with given number of days.
77 /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
78 /// Fails when the duration is out of bounds.
80 pub fn days(days: i64) -> Duration {
81 let secs = days.checked_mul(&SECS_PER_DAY).expect("Duration::days out of bounds");
82 Duration::seconds(secs)
85 /// Makes a new `Duration` with given number of hours.
86 /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
87 /// Fails when the duration is out of bounds.
89 pub fn hours(hours: i64) -> Duration {
90 let secs = hours.checked_mul(&SECS_PER_HOUR).expect("Duration::hours ouf of bounds");
91 Duration::seconds(secs)
94 /// Makes a new `Duration` with given number of minutes.
95 /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
96 /// Fails when the duration is out of bounds.
98 pub fn minutes(minutes: i64) -> Duration {
99 let secs = minutes.checked_mul(&SECS_PER_MINUTE).expect("Duration::minutes out of bounds");
100 Duration::seconds(secs)
103 /// Makes a new `Duration` with given number of seconds.
104 /// Fails when the duration is more than `i64::MAX` milliseconds
105 /// or less than `i64::MIN` milliseconds.
107 pub fn seconds(seconds: i64) -> Duration {
108 let d = Duration { secs: seconds, nanos: 0 };
109 if d < MIN || d > MAX {
110 panic!("Duration::seconds out of bounds");
115 /// Makes a new `Duration` with given number of milliseconds.
117 pub fn milliseconds(milliseconds: i64) -> Duration {
118 let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
119 let nanos = millis as i32 * NANOS_PER_MILLI;
120 Duration { secs: secs, nanos: nanos }
123 /// Makes a new `Duration` with given number of microseconds.
125 pub fn microseconds(microseconds: i64) -> Duration {
126 let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
127 let nanos = micros as i32 * NANOS_PER_MICRO;
128 Duration { secs: secs, nanos: nanos }
131 /// Makes a new `Duration` with given number of nanoseconds.
133 pub fn nanoseconds(nanos: i64) -> Duration {
134 let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64);
135 Duration { secs: secs, nanos: nanos as i32 }
138 /// Returns the total number of whole weeks in the duration.
140 pub fn num_weeks(&self) -> i64 {
144 /// Returns the total number of whole days in the duration.
145 pub fn num_days(&self) -> i64 {
146 self.num_seconds() / SECS_PER_DAY
149 /// Returns the total number of whole hours in the duration.
151 pub fn num_hours(&self) -> i64 {
152 self.num_seconds() / SECS_PER_HOUR
155 /// Returns the total number of whole minutes in the duration.
157 pub fn num_minutes(&self) -> i64 {
158 self.num_seconds() / SECS_PER_MINUTE
161 /// Returns the total number of whole seconds in the duration.
162 pub fn num_seconds(&self) -> i64 {
163 // If secs is negative, nanos should be subtracted from the duration.
164 if self.secs < 0 && self.nanos > 0 {
171 /// Returns the number of nanoseconds such that
172 /// `nanos_mod_sec() + num_seconds() * NANOS_PER_SEC` is the total number of
173 /// nanoseconds in the duration.
174 fn nanos_mod_sec(&self) -> i32 {
175 if self.secs < 0 && self.nanos > 0 {
176 self.nanos - NANOS_PER_SEC
182 /// Returns the total number of whole milliseconds in the duration,
183 pub fn num_milliseconds(&self) -> i64 {
184 // A proper Duration will not overflow, because MIN and MAX are defined
185 // such that the range is exactly i64 milliseconds.
186 let secs_part = self.num_seconds() * MILLIS_PER_SEC;
187 let nanos_part = self.nanos_mod_sec() / NANOS_PER_MILLI;
188 secs_part + nanos_part as i64
191 /// Returns the total number of whole microseconds in the duration,
192 /// or `None` on overflow (exceeding 2^63 microseconds in either direction).
193 pub fn num_microseconds(&self) -> Option<i64> {
194 let secs_part = try_opt!(self.num_seconds().checked_mul(&MICROS_PER_SEC));
195 let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO;
196 secs_part.checked_add(&(nanos_part as i64))
199 /// Returns the total number of whole nanoseconds in the duration,
200 /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
201 pub fn num_nanoseconds(&self) -> Option<i64> {
202 let secs_part = try_opt!(self.num_seconds().checked_mul(&(NANOS_PER_SEC as i64)));
203 let nanos_part = self.nanos_mod_sec();
204 secs_part.checked_add(&(nanos_part as i64))
208 impl num::Bounded for Duration {
209 #[inline] fn min_value() -> Duration { MIN }
210 #[inline] fn max_value() -> Duration { MAX }
213 impl num::Zero for Duration {
215 fn zero() -> Duration {
216 Duration { secs: 0, nanos: 0 }
220 fn is_zero(&self) -> bool {
221 self.secs == 0 && self.nanos == 0
225 impl Neg<Duration> for Duration {
227 fn neg(&self) -> Duration {
229 Duration { secs: -self.secs, nanos: 0 }
231 Duration { secs: -self.secs - 1, nanos: NANOS_PER_SEC - self.nanos }
236 impl Add<Duration,Duration> for Duration {
237 fn add(&self, rhs: &Duration) -> Duration {
238 let mut secs = self.secs + rhs.secs;
239 let mut nanos = self.nanos + rhs.nanos;
240 if nanos >= NANOS_PER_SEC {
241 nanos -= NANOS_PER_SEC;
244 Duration { secs: secs, nanos: nanos }
248 impl num::CheckedAdd for Duration {
249 fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
250 let mut secs = try_opt!(self.secs.checked_add(&rhs.secs));
251 let mut nanos = self.nanos + rhs.nanos;
252 if nanos >= NANOS_PER_SEC {
253 nanos -= NANOS_PER_SEC;
254 secs = try_opt!(secs.checked_add(&1));
256 let d = Duration { secs: secs, nanos: nanos };
257 // Even if d is within the bounds of i64 seconds,
258 // it might still overflow i64 milliseconds.
259 if d < MIN || d > MAX { None } else { Some(d) }
263 impl Sub<Duration,Duration> for Duration {
264 fn sub(&self, rhs: &Duration) -> Duration {
265 let mut secs = self.secs - rhs.secs;
266 let mut nanos = self.nanos - rhs.nanos;
268 nanos += NANOS_PER_SEC;
271 Duration { secs: secs, nanos: nanos }
275 impl num::CheckedSub for Duration {
276 fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
277 let mut secs = try_opt!(self.secs.checked_sub(&rhs.secs));
278 let mut nanos = self.nanos - rhs.nanos;
280 nanos += NANOS_PER_SEC;
281 secs = try_opt!(secs.checked_sub(&1));
283 let d = Duration { secs: secs, nanos: nanos };
284 // Even if d is within the bounds of i64 seconds,
285 // it might still overflow i64 milliseconds.
286 if d < MIN || d > MAX { None } else { Some(d) }
290 impl Mul<i32,Duration> for Duration {
291 fn mul(&self, rhs: &i32) -> Duration {
292 // Multiply nanoseconds as i64, because it cannot overflow that way.
293 let total_nanos = self.nanos as i64 * *rhs as i64;
294 let (extra_secs, nanos) = div_mod_floor_64(total_nanos, NANOS_PER_SEC as i64);
295 let secs = self.secs * *rhs as i64 + extra_secs;
296 Duration { secs: secs, nanos: nanos as i32 }
300 impl Div<i32,Duration> for Duration {
301 fn div(&self, rhs: &i32) -> Duration {
302 let mut secs = self.secs / *rhs as i64;
303 let carry = self.secs - secs * *rhs as i64;
304 let extra_nanos = carry * NANOS_PER_SEC as i64 / *rhs as i64;
305 let mut nanos = self.nanos / *rhs + extra_nanos as i32;
306 if nanos >= NANOS_PER_SEC {
307 nanos -= NANOS_PER_SEC;
311 nanos += NANOS_PER_SEC;
314 Duration { secs: secs, nanos: nanos }
318 impl fmt::Show for Duration {
319 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320 // technically speaking, negative duration is not valid ISO 8601,
321 // but we need to print it anyway.
322 let (abs, sign) = if self.secs < 0 { (-self, "-") } else { (*self, "") };
324 let days = abs.secs / SECS_PER_DAY;
325 let secs = abs.secs - days * SECS_PER_DAY;
326 let hasdate = days != 0;
327 let hastime = (secs != 0 || abs.nanos != 0) || !hasdate;
329 try!(write!(f, "{}P", sign));
332 try!(write!(f, "{}D", days));
336 try!(write!(f, "T{}S", secs));
337 } else if abs.nanos % NANOS_PER_MILLI == 0 {
338 try!(write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI));
339 } else if abs.nanos % NANOS_PER_MICRO == 0 {
340 try!(write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO));
342 try!(write!(f, "T{}.{:09}S", secs, abs.nanos));
349 // Copied from libnum
351 fn div_mod_floor_64(this: i64, other: i64) -> (i64, i64) {
352 (div_floor_64(this, other), mod_floor_64(this, other))
356 fn div_floor_64(this: i64, other: i64) -> i64 {
357 match div_rem_64(this, other) {
358 (d, r) if (r > 0 && other < 0)
359 || (r < 0 && other > 0) => d - 1,
365 fn mod_floor_64(this: i64, other: i64) -> i64 {
367 r if (r > 0 && other < 0)
368 || (r < 0 && other > 0) => r + other,
374 fn div_rem_64(this: i64, other: i64) -> (i64, i64) {
375 (this / other, this % other)
380 use super::{Duration, MIN, MAX};
382 use num::{Zero, CheckedAdd, CheckedSub};
383 use option::{Some, None};
384 use to_string::ToString;
388 let d: Duration = Zero::zero();
389 assert_eq!(d, Zero::zero());
390 assert!(Duration::seconds(1) != Zero::zero());
391 assert_eq!(Duration::seconds(1) + Duration::seconds(2), Duration::seconds(3));
392 assert_eq!(Duration::seconds(86399) + Duration::seconds(4),
393 Duration::days(1) + Duration::seconds(3));
394 assert_eq!(Duration::days(10) - Duration::seconds(1000), Duration::seconds(863000));
395 assert_eq!(Duration::days(10) - Duration::seconds(1000000), Duration::seconds(-136000));
396 assert_eq!(Duration::days(2) + Duration::seconds(86399) +
397 Duration::nanoseconds(1234567890),
398 Duration::days(3) + Duration::nanoseconds(234567890));
399 assert_eq!(-Duration::days(3), Duration::days(-3));
400 assert_eq!(-(Duration::days(3) + Duration::seconds(70)),
401 Duration::days(-4) + Duration::seconds(86400-70));
405 fn test_duration_num_days() {
406 let d: Duration = Zero::zero();
407 assert_eq!(d.num_days(), 0);
408 assert_eq!(Duration::days(1).num_days(), 1);
409 assert_eq!(Duration::days(-1).num_days(), -1);
410 assert_eq!(Duration::seconds(86399).num_days(), 0);
411 assert_eq!(Duration::seconds(86401).num_days(), 1);
412 assert_eq!(Duration::seconds(-86399).num_days(), 0);
413 assert_eq!(Duration::seconds(-86401).num_days(), -1);
414 assert_eq!(Duration::days(i32::MAX as i64).num_days(), i32::MAX as i64);
415 assert_eq!(Duration::days(i32::MIN as i64).num_days(), i32::MIN as i64);
419 fn test_duration_num_seconds() {
420 let d: Duration = Zero::zero();
421 assert_eq!(d.num_seconds(), 0);
422 assert_eq!(Duration::seconds(1).num_seconds(), 1);
423 assert_eq!(Duration::seconds(-1).num_seconds(), -1);
424 assert_eq!(Duration::milliseconds(999).num_seconds(), 0);
425 assert_eq!(Duration::milliseconds(1001).num_seconds(), 1);
426 assert_eq!(Duration::milliseconds(-999).num_seconds(), 0);
427 assert_eq!(Duration::milliseconds(-1001).num_seconds(), -1);
431 fn test_duration_num_milliseconds() {
432 let d: Duration = Zero::zero();
433 assert_eq!(d.num_milliseconds(), 0);
434 assert_eq!(Duration::milliseconds(1).num_milliseconds(), 1);
435 assert_eq!(Duration::milliseconds(-1).num_milliseconds(), -1);
436 assert_eq!(Duration::microseconds(999).num_milliseconds(), 0);
437 assert_eq!(Duration::microseconds(1001).num_milliseconds(), 1);
438 assert_eq!(Duration::microseconds(-999).num_milliseconds(), 0);
439 assert_eq!(Duration::microseconds(-1001).num_milliseconds(), -1);
440 assert_eq!(Duration::milliseconds(i64::MAX).num_milliseconds(), i64::MAX);
441 assert_eq!(Duration::milliseconds(i64::MIN).num_milliseconds(), i64::MIN);
442 assert_eq!(MAX.num_milliseconds(), i64::MAX);
443 assert_eq!(MIN.num_milliseconds(), i64::MIN);
447 fn test_duration_num_microseconds() {
448 let d: Duration = Zero::zero();
449 assert_eq!(d.num_microseconds(), Some(0));
450 assert_eq!(Duration::microseconds(1).num_microseconds(), Some(1));
451 assert_eq!(Duration::microseconds(-1).num_microseconds(), Some(-1));
452 assert_eq!(Duration::nanoseconds(999).num_microseconds(), Some(0));
453 assert_eq!(Duration::nanoseconds(1001).num_microseconds(), Some(1));
454 assert_eq!(Duration::nanoseconds(-999).num_microseconds(), Some(0));
455 assert_eq!(Duration::nanoseconds(-1001).num_microseconds(), Some(-1));
456 assert_eq!(Duration::microseconds(i64::MAX).num_microseconds(), Some(i64::MAX));
457 assert_eq!(Duration::microseconds(i64::MIN).num_microseconds(), Some(i64::MIN));
458 assert_eq!(MAX.num_microseconds(), None);
459 assert_eq!(MIN.num_microseconds(), None);
462 const MICROS_PER_DAY: i64 = 86400_000_000;
463 assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY).num_microseconds(),
464 Some(i64::MAX / MICROS_PER_DAY * MICROS_PER_DAY));
465 assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY).num_microseconds(),
466 Some(i64::MIN / MICROS_PER_DAY * MICROS_PER_DAY));
467 assert_eq!(Duration::days(i64::MAX / MICROS_PER_DAY + 1).num_microseconds(), None);
468 assert_eq!(Duration::days(i64::MIN / MICROS_PER_DAY - 1).num_microseconds(), None);
472 fn test_duration_num_nanoseconds() {
473 let d: Duration = Zero::zero();
474 assert_eq!(d.num_nanoseconds(), Some(0));
475 assert_eq!(Duration::nanoseconds(1).num_nanoseconds(), Some(1));
476 assert_eq!(Duration::nanoseconds(-1).num_nanoseconds(), Some(-1));
477 assert_eq!(Duration::nanoseconds(i64::MAX).num_nanoseconds(), Some(i64::MAX));
478 assert_eq!(Duration::nanoseconds(i64::MIN).num_nanoseconds(), Some(i64::MIN));
479 assert_eq!(MAX.num_nanoseconds(), None);
480 assert_eq!(MIN.num_nanoseconds(), None);
483 const NANOS_PER_DAY: i64 = 86400_000_000_000;
484 assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY).num_nanoseconds(),
485 Some(i64::MAX / NANOS_PER_DAY * NANOS_PER_DAY));
486 assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY).num_nanoseconds(),
487 Some(i64::MIN / NANOS_PER_DAY * NANOS_PER_DAY));
488 assert_eq!(Duration::days(i64::MAX / NANOS_PER_DAY + 1).num_nanoseconds(), None);
489 assert_eq!(Duration::days(i64::MIN / NANOS_PER_DAY - 1).num_nanoseconds(), None);
493 fn test_duration_checked_ops() {
494 assert_eq!(Duration::milliseconds(i64::MAX - 1).checked_add(&Duration::microseconds(999)),
495 Some(Duration::milliseconds(i64::MAX - 2) + Duration::microseconds(1999)));
496 assert!(Duration::milliseconds(i64::MAX).checked_add(&Duration::microseconds(1000))
499 assert_eq!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(0)),
500 Some(Duration::milliseconds(i64::MIN)));
501 assert!(Duration::milliseconds(i64::MIN).checked_sub(&Duration::milliseconds(1))
506 fn test_duration_mul() {
507 let d: Duration = Zero::zero();
508 assert_eq!(d * i32::MAX, d);
509 assert_eq!(d * i32::MIN, d);
510 assert_eq!(Duration::nanoseconds(1) * 0, Zero::zero());
511 assert_eq!(Duration::nanoseconds(1) * 1, Duration::nanoseconds(1));
512 assert_eq!(Duration::nanoseconds(1) * 1_000_000_000, Duration::seconds(1));
513 assert_eq!(Duration::nanoseconds(1) * -1_000_000_000, -Duration::seconds(1));
514 assert_eq!(-Duration::nanoseconds(1) * 1_000_000_000, -Duration::seconds(1));
515 assert_eq!(Duration::nanoseconds(30) * 333_333_333,
516 Duration::seconds(10) - Duration::nanoseconds(10));
517 assert_eq!((Duration::nanoseconds(1) + Duration::seconds(1) + Duration::days(1)) * 3,
518 Duration::nanoseconds(3) + Duration::seconds(3) + Duration::days(3));
519 assert_eq!(Duration::milliseconds(1500) * -2, Duration::seconds(-3));
520 assert_eq!(Duration::milliseconds(-1500) * 2, Duration::seconds(-3));
524 fn test_duration_div() {
525 let d: Duration = Zero::zero();
526 assert_eq!(d / i32::MAX, d);
527 assert_eq!(d / i32::MIN, d);
528 assert_eq!(Duration::nanoseconds(123_456_789) / 1, Duration::nanoseconds(123_456_789));
529 assert_eq!(Duration::nanoseconds(123_456_789) / -1, -Duration::nanoseconds(123_456_789));
530 assert_eq!(-Duration::nanoseconds(123_456_789) / -1, Duration::nanoseconds(123_456_789));
531 assert_eq!(-Duration::nanoseconds(123_456_789) / 1, -Duration::nanoseconds(123_456_789));
532 assert_eq!(Duration::seconds(1) / 3, Duration::nanoseconds(333_333_333));
533 assert_eq!(Duration::seconds(4) / 3, Duration::nanoseconds(1_333_333_333));
534 assert_eq!(Duration::seconds(-1) / 2, Duration::milliseconds(-500));
535 assert_eq!(Duration::seconds(1) / -2, Duration::milliseconds(-500));
536 assert_eq!(Duration::seconds(-1) / -2, Duration::milliseconds(500));
537 assert_eq!(Duration::seconds(-4) / 3, Duration::nanoseconds(-1_333_333_333));
538 assert_eq!(Duration::seconds(-4) / -3, Duration::nanoseconds(1_333_333_333));
542 fn test_duration_fmt() {
543 let d: Duration = Zero::zero();
544 assert_eq!(d.to_string(), "PT0S".to_string());
545 assert_eq!(Duration::days(42).to_string(), "P42D".to_string());
546 assert_eq!(Duration::days(-42).to_string(), "-P42D".to_string());
547 assert_eq!(Duration::seconds(42).to_string(), "PT42S".to_string());
548 assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S".to_string());
549 assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S".to_string());
550 assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S".to_string());
551 assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(),
552 "P7DT6.543S".to_string());
553 assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S".to_string());
554 assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S".to_string());
556 // the format specifier should have no effect on `Duration`
557 assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)),
558 "P1DT2.345S".to_string());