|
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