|
9 | 9 | use std::{fmt, num, i32};
|
10 | 10 | use num::Integer;
|
11 | 11 |
|
12 |
| -pub static MIN_DAYS: i32 = i32::MIN; |
13 |
| -pub static MAX_DAYS: i32 = i32::MAX; |
| 12 | +/// `Duration`'s `days` component should have no more than this value. |
| 13 | +static MIN_DAYS: i32 = i32::MIN; |
| 14 | +/// `Duration`'s `days` component should have no less than this value. |
| 15 | +static MAX_DAYS: i32 = i32::MAX; |
14 | 16 |
|
| 17 | +/// The number of nanoseconds in seconds. |
15 | 18 | static NANOS_PER_SEC: i32 = 1_000_000_000;
|
| 19 | +/// The number of (non-leap) seconds in days. |
16 | 20 | static SECS_PER_DAY: i32 = 86400;
|
17 | 21 |
|
18 | 22 | macro_rules! earlyexit(
|
19 | 23 | ($e:expr) => (match $e { Some(v) => v, None => return None })
|
20 | 24 | )
|
21 | 25 |
|
| 26 | +/// ISO 8601 time duration with nanosecond precision. |
| 27 | +/// This also allows for the negative duration; see individual methods for details. |
22 | 28 | #[deriving(PartialEq, Eq, PartialOrd, Ord)]
|
23 | 29 | pub struct Duration {
|
24 | 30 | days: i32,
|
25 | 31 | secs: u32,
|
26 | 32 | nanos: u32,
|
27 | 33 | }
|
28 | 34 |
|
| 35 | +/// The minimum possible `Duration`. |
| 36 | +pub static MIN: Duration = Duration { days: MIN_DAYS, secs: 0, nanos: 0 }; |
| 37 | +/// The maximum possible `Duration`. |
| 38 | +pub static MAX: Duration = Duration { days: MAX_DAYS, secs: SECS_PER_DAY as u32 - 1, |
| 39 | + nanos: NANOS_PER_SEC as u32 - 1 }; |
| 40 | + |
29 | 41 | impl Duration {
|
30 |
| - pub fn new(days: i32, secs: i32, nanos: i32) -> Option<Duration> { |
| 42 | + /// Makes a new `Duration` with given number of days, seconds and nanoseconds. |
| 43 | + /// |
| 44 | + /// Fails when the duration is out of bounds. |
| 45 | + #[inline] |
| 46 | + pub fn new(days: i32, secs: i32, nanos: i32) -> Duration { |
| 47 | + Duration::new_opt(days, secs, nanos).expect("Duration::new out of bounds") |
| 48 | + } |
| 49 | + |
| 50 | + /// Makes a new `Duration` with given number of days, seconds and nanoseconds. |
| 51 | + /// Returns `None` when the duration is out of bounds. |
| 52 | + pub fn new_opt(days: i32, secs: i32, nanos: i32) -> Option<Duration> { |
31 | 53 | let (secs_, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
|
32 | 54 | let secs = earlyexit!(secs.checked_add(&secs_));
|
33 | 55 | let (days_, secs) = secs.div_mod_floor(&SECS_PER_DAY);
|
34 | 56 | let days = earlyexit!(days.checked_add(&days_).and_then(|v| v.to_i32()));
|
35 | 57 | Some(Duration { days: days, secs: secs as u32, nanos: nanos as u32 })
|
36 | 58 | }
|
37 | 59 |
|
| 60 | + /// Makes a new `Duration` with zero seconds. |
38 | 61 | #[inline]
|
39 | 62 | pub fn zero() -> Duration {
|
40 | 63 | Duration { days: 0, secs: 0, nanos: 0 }
|
41 | 64 | }
|
42 | 65 |
|
| 66 | + /// Makes a new `Duration` with given number of weeks. |
| 67 | + /// Equivalent to `Duration::new(weeks * 7, 0, 0)` with overflow checks. |
| 68 | + /// |
| 69 | + /// Fails when the duration is out of bounds. |
43 | 70 | #[inline]
|
44 | 71 | pub fn weeks(weeks: i32) -> Duration {
|
45 |
| - Duration::days(weeks * 7) |
| 72 | + let days = weeks.checked_mul(&7).expect("Duration::weeks out of bounds"); |
| 73 | + Duration::days(days) |
46 | 74 | }
|
47 | 75 |
|
| 76 | + /// Makes a new `Duration` with given number of days. |
| 77 | + /// Equivalent to `Duration::new(days, 0, 0)`. |
| 78 | + /// |
| 79 | + /// Fails when the duration is out of bounds. |
48 | 80 | #[inline]
|
49 | 81 | pub fn days(days: i32) -> Duration {
|
50 | 82 | let days = days.to_i32().expect("Duration::days out of bounds");
|
51 | 83 | Duration { days: days, secs: 0, nanos: 0 }
|
52 | 84 | }
|
53 | 85 |
|
| 86 | + /// Makes a new `Duration` with given number of hours. |
| 87 | + /// Equivalent to `Duration::new(0, hours * 3600, 0)` with overflow checks. |
| 88 | + /// |
| 89 | + /// Fails when the duration is out of bounds. |
54 | 90 | #[inline]
|
55 | 91 | pub fn hours(hours: i32) -> Duration {
|
56 | 92 | let (days, hours) = hours.div_mod_floor(&(SECS_PER_DAY / 3600));
|
57 | 93 | let secs = hours * 3600;
|
58 | 94 | Duration { secs: secs as u32, ..Duration::days(days) }
|
59 | 95 | }
|
60 | 96 |
|
| 97 | + /// Makes a new `Duration` with given number of minutes. |
| 98 | + /// Equivalent to `Duration::new(0, mins * 60, 0)` with overflow checks. |
| 99 | + /// |
| 100 | + /// Fails when the duration is out of bounds. |
61 | 101 | #[inline]
|
62 | 102 | pub fn minutes(mins: i32) -> Duration {
|
63 | 103 | let (days, mins) = mins.div_mod_floor(&(SECS_PER_DAY / 60));
|
64 | 104 | let secs = mins * 60;
|
65 | 105 | Duration { secs: secs as u32, ..Duration::days(days) }
|
66 | 106 | }
|
67 | 107 |
|
| 108 | + /// Makes a new `Duration` with given number of seconds. |
| 109 | + /// Equivalent to `Duration::new(0, secs, 0)`. |
| 110 | + /// |
| 111 | + /// Fails when the duration is out of bounds. |
68 | 112 | #[inline]
|
69 | 113 | pub fn seconds(secs: i32) -> Duration {
|
70 | 114 | let (days, secs) = secs.div_mod_floor(&SECS_PER_DAY);
|
71 | 115 | Duration { secs: secs as u32, ..Duration::days(days) }
|
72 | 116 | }
|
73 | 117 |
|
| 118 | + /// Makes a new `Duration` with given number of milliseconds. |
| 119 | + /// Equivalent to `Duration::new(0, 0, millis * 1_000_000)` with overflow checks. |
| 120 | + /// |
| 121 | + /// Fails when the duration is out of bounds. |
74 | 122 | #[inline]
|
75 | 123 | pub fn milliseconds(millis: i32) -> Duration {
|
76 | 124 | let (secs, millis) = millis.div_mod_floor(&(NANOS_PER_SEC / 1_000_000));
|
77 | 125 | let nanos = millis * 1_000_000;
|
78 | 126 | Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
79 | 127 | }
|
80 | 128 |
|
| 129 | + /// Makes a new `Duration` with given number of microseconds. |
| 130 | + /// Equivalent to `Duration::new(0, 0, micros * 1_000)` with overflow checks. |
| 131 | + /// |
| 132 | + /// Fails when the duration is out of bounds. |
81 | 133 | #[inline]
|
82 | 134 | pub fn microseconds(micros: i32) -> Duration {
|
83 | 135 | let (secs, micros) = micros.div_mod_floor(&(NANOS_PER_SEC / 1_000));
|
84 | 136 | let nanos = micros * 1_000;
|
85 | 137 | Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
86 | 138 | }
|
87 | 139 |
|
| 140 | + /// Makes a new `Duration` with given number of nanoseconds. |
| 141 | + /// Equivalent to `Duration::new(0, 0, nanos)`. |
| 142 | + /// |
| 143 | + /// Fails when the duration is out of bounds. |
88 | 144 | #[inline]
|
89 | 145 | pub fn nanoseconds(nanos: i32) -> Duration {
|
90 | 146 | let (secs, nanos) = nanos.div_mod_floor(&NANOS_PER_SEC);
|
91 | 147 | Duration { nanos: nanos as u32, ..Duration::seconds(secs) }
|
92 | 148 | }
|
93 | 149 |
|
| 150 | + /// Returns the number of days in the duration. |
| 151 | + /// For the negative duration, this is a largest integral number of days smaller than `self`. |
94 | 152 | #[inline]
|
95 | 153 | pub fn ndays(&self) -> i32 {
|
96 | 154 | self.days as i32
|
97 | 155 | }
|
98 | 156 |
|
| 157 | + /// Returns the number of (non-leap) seconds in the duration. |
| 158 | + /// This never goes negative even when the duration is negative. |
99 | 159 | #[inline]
|
100 | 160 | pub fn nseconds(&self) -> u32 {
|
101 | 161 | self.secs as u32
|
102 | 162 | }
|
103 | 163 |
|
| 164 | + /// Returns the number of nanoseconds in the duration. |
| 165 | + /// This never goes negative even when the duration is negative. |
104 | 166 | #[inline]
|
105 | 167 | pub fn nnanoseconds(&self) -> u32 {
|
106 | 168 | self.nanos as u32
|
107 | 169 | }
|
108 | 170 | }
|
109 | 171 |
|
| 172 | +impl num::Bounded for Duration { |
| 173 | + #[inline] fn min_value() -> Duration { MIN } |
| 174 | + #[inline] fn max_value() -> Duration { MAX } |
| 175 | +} |
| 176 | + |
110 | 177 | impl num::Zero for Duration {
|
111 | 178 | #[inline]
|
112 | 179 | fn zero() -> Duration {
|
|
0 commit comments