]> git.proxmox.com Git - rustc.git/blame - src/libstd/time/duration.rs
New upstream version 1.13.0+dfsg1
[rustc.git] / src / libstd / time / duration.rs
CommitLineData
1a4d82fc
JJ
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.
4//
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.
10
54a0048b 11use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign};
d9579d0f
AL
12
13const NANOS_PER_SEC: u32 = 1_000_000_000;
14const NANOS_PER_MILLI: u32 = 1_000_000;
15const MILLIS_PER_SEC: u64 = 1_000;
16
17/// A duration type to represent a span of time, typically used for system
18/// timeouts.
19///
20/// Each duration is composed of a number of seconds and nanosecond precision.
21/// APIs binding a system timeout will typically round up the nanosecond
22/// precision if the underlying system does not support that level of precision.
23///
24/// Durations implement many common traits, including `Add`, `Sub`, and other
25/// ops traits. Currently a duration may only be inspected for its number of
26/// seconds and its nanosecond precision.
27///
28/// # Examples
29///
30/// ```
d9579d0f
AL
31/// use std::time::Duration;
32///
33/// let five_seconds = Duration::new(5, 0);
34/// let five_seconds_and_five_nanos = five_seconds + Duration::new(0, 5);
35///
c1a9b12d
SL
36/// assert_eq!(five_seconds_and_five_nanos.as_secs(), 5);
37/// assert_eq!(five_seconds_and_five_nanos.subsec_nanos(), 5);
d9579d0f
AL
38///
39/// let ten_millis = Duration::from_millis(10);
40/// ```
c1a9b12d 41#[stable(feature = "duration", since = "1.3.0")]
9cc50fc6 42#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
1a4d82fc 43pub struct Duration {
d9579d0f
AL
44 secs: u64,
45 nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC
1a4d82fc
JJ
46}
47
1a4d82fc 48impl Duration {
b039eaaf 49 /// Creates a new `Duration` from the specified number of seconds and
d9579d0f
AL
50 /// additional nanosecond precision.
51 ///
52 /// If the nanoseconds is greater than 1 billion (the number of nanoseconds
53 /// in a second), then it will carry over into the seconds provided.
a7813a04
XL
54 ///
55 /// # Panics
56 ///
57 /// This constructor will panic if the carry from the nanoseconds overflows
58 /// the seconds counter.
c1a9b12d 59 #[stable(feature = "duration", since = "1.3.0")]
54a0048b 60 #[inline]
d9579d0f 61 pub fn new(secs: u64, nanos: u32) -> Duration {
a7813a04
XL
62 let secs = secs.checked_add((nanos / NANOS_PER_SEC) as u64)
63 .expect("overflow in Duration::new");
d9579d0f 64 let nanos = nanos % NANOS_PER_SEC;
1a4d82fc
JJ
65 Duration { secs: secs, nanos: nanos }
66 }
67
d9579d0f 68 /// Creates a new `Duration` from the specified number of seconds.
c1a9b12d 69 #[stable(feature = "duration", since = "1.3.0")]
54a0048b 70 #[inline]
d9579d0f
AL
71 pub fn from_secs(secs: u64) -> Duration {
72 Duration { secs: secs, nanos: 0 }
1a4d82fc
JJ
73 }
74
d9579d0f 75 /// Creates a new `Duration` from the specified number of milliseconds.
c1a9b12d 76 #[stable(feature = "duration", since = "1.3.0")]
54a0048b 77 #[inline]
d9579d0f
AL
78 pub fn from_millis(millis: u64) -> Duration {
79 let secs = millis / MILLIS_PER_SEC;
80 let nanos = ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI;
81 Duration { secs: secs, nanos: nanos }
1a4d82fc 82 }
1a4d82fc 83
d9579d0f
AL
84 /// Returns the number of whole seconds represented by this duration.
85 ///
9e0c209e 86 /// The extra precision represented by this duration is ignored (i.e. extra
d9579d0f 87 /// nanoseconds are not represented in the returned value).
c1a9b12d 88 #[stable(feature = "duration", since = "1.3.0")]
54a0048b 89 #[inline]
c1a9b12d
SL
90 pub fn as_secs(&self) -> u64 { self.secs }
91
c1a9b12d
SL
92 /// Returns the nanosecond precision represented by this duration.
93 ///
94 /// This method does **not** return the length of the duration when
95 /// represented by nanoseconds. The returned number always represents a
9e0c209e 96 /// fractional portion of a second (i.e. it is less than one billion).
c1a9b12d 97 #[stable(feature = "duration", since = "1.3.0")]
54a0048b 98 #[inline]
c1a9b12d 99 pub fn subsec_nanos(&self) -> u32 { self.nanos }
9e0c209e
SL
100
101 /// Checked duration addition. Computes `self + other`, returning `None`
102 /// if overflow occurred.
103 ///
104 /// # Examples
105 ///
106 /// Basic usage:
107 ///
108 /// ```
109 /// #![feature(duration_checked_ops)]
110 ///
111 /// use std::time::Duration;
112 ///
113 /// assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)), Some(Duration::new(0, 1)));
114 /// assert_eq!(Duration::new(1, 0).checked_add(Duration::new(std::u64::MAX, 0)), None);
115 /// ```
116 #[unstable(feature = "duration_checked_ops", issue = "35774")]
117 #[inline]
118 pub fn checked_add(self, rhs: Duration) -> Option<Duration> {
119 if let Some(mut secs) = self.secs.checked_add(rhs.secs) {
120 let mut nanos = self.nanos + rhs.nanos;
121 if nanos >= NANOS_PER_SEC {
122 nanos -= NANOS_PER_SEC;
123 if let Some(new_secs) = secs.checked_add(1) {
124 secs = new_secs;
125 } else {
126 return None;
127 }
128 }
129 debug_assert!(nanos < NANOS_PER_SEC);
130 Some(Duration {
131 secs: secs,
132 nanos: nanos,
133 })
134 } else {
135 None
136 }
137 }
138
139 /// Checked duration subtraction. Computes `self + other`, returning `None`
140 /// if the result would be negative or if underflow occurred.
141 ///
142 /// # Examples
143 ///
144 /// Basic usage:
145 ///
146 /// ```
147 /// #![feature(duration_checked_ops)]
148 ///
149 /// use std::time::Duration;
150 ///
151 /// assert_eq!(Duration::new(0, 1).checked_sub(Duration::new(0, 0)), Some(Duration::new(0, 1)));
152 /// assert_eq!(Duration::new(0, 0).checked_sub(Duration::new(0, 1)), None);
153 /// ```
154 #[unstable(feature = "duration_checked_ops", issue = "35774")]
155 #[inline]
156 pub fn checked_sub(self, rhs: Duration) -> Option<Duration> {
157 if let Some(mut secs) = self.secs.checked_sub(rhs.secs) {
158 let nanos = if self.nanos >= rhs.nanos {
159 self.nanos - rhs.nanos
160 } else {
161 if let Some(sub_secs) = secs.checked_sub(1) {
162 secs = sub_secs;
163 self.nanos + NANOS_PER_SEC - rhs.nanos
164 } else {
165 return None;
166 }
167 };
168 debug_assert!(nanos < NANOS_PER_SEC);
169 Some(Duration { secs: secs, nanos: nanos })
170 } else {
171 None
172 }
173 }
174
175 /// Checked duration multiplication. Computes `self * other`, returning
176 /// `None` if underflow or overflow occurred.
177 ///
178 /// # Examples
179 ///
180 /// Basic usage:
181 ///
182 /// ```
183 /// #![feature(duration_checked_ops)]
184 ///
185 /// use std::time::Duration;
186 ///
187 /// assert_eq!(Duration::new(0, 500_000_001).checked_mul(2), Some(Duration::new(1, 2)));
188 /// assert_eq!(Duration::new(std::u64::MAX - 1, 0).checked_mul(2), None);
189 /// ```
190 #[unstable(feature = "duration_checked_ops", issue = "35774")]
191 #[inline]
192 pub fn checked_mul(self, rhs: u32) -> Option<Duration> {
193 // Multiply nanoseconds as u64, because it cannot overflow that way.
194 let total_nanos = self.nanos as u64 * rhs as u64;
195 let extra_secs = total_nanos / (NANOS_PER_SEC as u64);
196 let nanos = (total_nanos % (NANOS_PER_SEC as u64)) as u32;
197 if let Some(secs) = self.secs
198 .checked_mul(rhs as u64)
199 .and_then(|s| s.checked_add(extra_secs)) {
200 debug_assert!(nanos < NANOS_PER_SEC);
201 Some(Duration {
202 secs: secs,
203 nanos: nanos,
204 })
205 } else {
206 None
207 }
208 }
209
210 /// Checked duration division. Computes `self / other`, returning `None`
211 /// if `other == 0` or the operation results in underflow or overflow.
212 ///
213 /// # Examples
214 ///
215 /// Basic usage:
216 ///
217 /// ```
218 /// #![feature(duration_checked_ops)]
219 ///
220 /// use std::time::Duration;
221 ///
222 /// assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
223 /// assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
224 /// assert_eq!(Duration::new(2, 0).checked_div(0), None);
225 /// ```
226 #[unstable(feature = "duration_checked_ops", issue = "35774")]
227 #[inline]
228 pub fn checked_div(self, rhs: u32) -> Option<Duration> {
229 if rhs != 0 {
230 let secs = self.secs / (rhs as u64);
231 let carry = self.secs - secs * (rhs as u64);
232 let extra_nanos = carry * (NANOS_PER_SEC as u64) / (rhs as u64);
233 let nanos = self.nanos / rhs + (extra_nanos as u32);
234 debug_assert!(nanos < NANOS_PER_SEC);
235 Some(Duration { secs: secs, nanos: nanos })
236 } else {
237 None
238 }
239 }
1a4d82fc
JJ
240}
241
92a42be0 242#[stable(feature = "duration", since = "1.3.0")]
1a4d82fc
JJ
243impl Add for Duration {
244 type Output = Duration;
245
246 fn add(self, rhs: Duration) -> Duration {
9e0c209e 247 self.checked_add(rhs).expect("overflow when adding durations")
1a4d82fc
JJ
248 }
249}
250
54a0048b
SL
251#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
252impl AddAssign for Duration {
253 fn add_assign(&mut self, rhs: Duration) {
254 *self = *self + rhs;
255 }
256}
257
92a42be0 258#[stable(feature = "duration", since = "1.3.0")]
1a4d82fc
JJ
259impl Sub for Duration {
260 type Output = Duration;
261
262 fn sub(self, rhs: Duration) -> Duration {
9e0c209e 263 self.checked_sub(rhs).expect("overflow when subtracting durations")
1a4d82fc
JJ
264 }
265}
266
54a0048b
SL
267#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
268impl SubAssign for Duration {
269 fn sub_assign(&mut self, rhs: Duration) {
270 *self = *self - rhs;
271 }
272}
273
92a42be0 274#[stable(feature = "duration", since = "1.3.0")]
d9579d0f 275impl Mul<u32> for Duration {
1a4d82fc
JJ
276 type Output = Duration;
277
d9579d0f 278 fn mul(self, rhs: u32) -> Duration {
9e0c209e 279 self.checked_mul(rhs).expect("overflow when multiplying duration by scalar")
1a4d82fc
JJ
280 }
281}
282
54a0048b
SL
283#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
284impl MulAssign<u32> for Duration {
285 fn mul_assign(&mut self, rhs: u32) {
286 *self = *self * rhs;
287 }
288}
289
92a42be0 290#[stable(feature = "duration", since = "1.3.0")]
d9579d0f 291impl Div<u32> for Duration {
1a4d82fc
JJ
292 type Output = Duration;
293
d9579d0f 294 fn div(self, rhs: u32) -> Duration {
9e0c209e 295 self.checked_div(rhs).expect("divide by zero error when dividing duration by scalar")
1a4d82fc
JJ
296 }
297}
298
54a0048b
SL
299#[stable(feature = "time_augmented_assignment", since = "1.9.0")]
300impl DivAssign<u32> for Duration {
301 fn div_assign(&mut self, rhs: u32) {
302 *self = *self / rhs;
303 }
304}
305
1a4d82fc
JJ
306#[cfg(test)]
307mod tests {
d9579d0f 308 use super::Duration;
1a4d82fc
JJ
309
310 #[test]
d9579d0f
AL
311 fn creation() {
312 assert!(Duration::from_secs(1) != Duration::from_secs(0));
313 assert_eq!(Duration::from_secs(1) + Duration::from_secs(2),
314 Duration::from_secs(3));
315 assert_eq!(Duration::from_millis(10) + Duration::from_secs(4),
316 Duration::new(4, 10 * 1_000_000));
317 assert_eq!(Duration::from_millis(4000), Duration::new(4, 0));
1a4d82fc
JJ
318 }
319
320 #[test]
d9579d0f 321 fn secs() {
c1a9b12d
SL
322 assert_eq!(Duration::new(0, 0).as_secs(), 0);
323 assert_eq!(Duration::from_secs(1).as_secs(), 1);
324 assert_eq!(Duration::from_millis(999).as_secs(), 0);
325 assert_eq!(Duration::from_millis(1001).as_secs(), 1);
1a4d82fc
JJ
326 }
327
328 #[test]
d9579d0f 329 fn nanos() {
c1a9b12d
SL
330 assert_eq!(Duration::new(0, 0).subsec_nanos(), 0);
331 assert_eq!(Duration::new(0, 5).subsec_nanos(), 5);
332 assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1);
333 assert_eq!(Duration::from_secs(1).subsec_nanos(), 0);
334 assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000);
335 assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000);
1a4d82fc
JJ
336 }
337
338 #[test]
d9579d0f
AL
339 fn add() {
340 assert_eq!(Duration::new(0, 0) + Duration::new(0, 1),
341 Duration::new(0, 1));
342 assert_eq!(Duration::new(0, 500_000_000) + Duration::new(0, 500_000_001),
343 Duration::new(1, 1));
1a4d82fc
JJ
344 }
345
9e0c209e
SL
346 #[test]
347 fn checked_add() {
348 assert_eq!(Duration::new(0, 0).checked_add(Duration::new(0, 1)),
349 Some(Duration::new(0, 1)));
350 assert_eq!(Duration::new(0, 500_000_000).checked_add(Duration::new(0, 500_000_001)),
351 Some(Duration::new(1, 1)));
352 assert_eq!(Duration::new(1, 0).checked_add(Duration::new(::u64::MAX, 0)), None);
353 }
354
1a4d82fc 355 #[test]
d9579d0f
AL
356 fn sub() {
357 assert_eq!(Duration::new(0, 1) - Duration::new(0, 0),
358 Duration::new(0, 1));
359 assert_eq!(Duration::new(0, 500_000_001) - Duration::new(0, 500_000_000),
360 Duration::new(0, 1));
361 assert_eq!(Duration::new(1, 0) - Duration::new(0, 1),
362 Duration::new(0, 999_999_999));
1a4d82fc
JJ
363 }
364
9e0c209e
SL
365 #[test]
366 fn checked_sub() {
367 let zero = Duration::new(0, 0);
368 let one_nano = Duration::new(0, 1);
369 let one_sec = Duration::new(1, 0);
370 assert_eq!(one_nano.checked_sub(zero), Some(Duration::new(0, 1)));
371 assert_eq!(one_sec.checked_sub(one_nano),
372 Some(Duration::new(0, 999_999_999)));
373 assert_eq!(zero.checked_sub(one_nano), None);
374 assert_eq!(zero.checked_sub(one_sec), None);
375 }
376
d9579d0f
AL
377 #[test] #[should_panic]
378 fn sub_bad1() {
379 Duration::new(0, 0) - Duration::new(0, 1);
1a4d82fc
JJ
380 }
381
d9579d0f
AL
382 #[test] #[should_panic]
383 fn sub_bad2() {
384 Duration::new(0, 0) - Duration::new(1, 0);
1a4d82fc
JJ
385 }
386
387 #[test]
d9579d0f
AL
388 fn mul() {
389 assert_eq!(Duration::new(0, 1) * 2, Duration::new(0, 2));
390 assert_eq!(Duration::new(1, 1) * 3, Duration::new(3, 3));
391 assert_eq!(Duration::new(0, 500_000_001) * 4, Duration::new(2, 4));
392 assert_eq!(Duration::new(0, 500_000_001) * 4000,
393 Duration::new(2000, 4000));
1a4d82fc
JJ
394 }
395
9e0c209e
SL
396 #[test]
397 fn checked_mul() {
398 assert_eq!(Duration::new(0, 1).checked_mul(2), Some(Duration::new(0, 2)));
399 assert_eq!(Duration::new(1, 1).checked_mul(3), Some(Duration::new(3, 3)));
400 assert_eq!(Duration::new(0, 500_000_001).checked_mul(4), Some(Duration::new(2, 4)));
401 assert_eq!(Duration::new(0, 500_000_001).checked_mul(4000),
402 Some(Duration::new(2000, 4000)));
403 assert_eq!(Duration::new(::u64::MAX - 1, 0).checked_mul(2), None);
404 }
405
1a4d82fc 406 #[test]
d9579d0f
AL
407 fn div() {
408 assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0));
409 assert_eq!(Duration::new(1, 1) / 3, Duration::new(0, 333_333_333));
410 assert_eq!(Duration::new(99, 999_999_000) / 100,
411 Duration::new(0, 999_999_990));
1a4d82fc 412 }
9e0c209e
SL
413
414 #[test]
415 fn checked_div() {
416 assert_eq!(Duration::new(2, 0).checked_div(2), Some(Duration::new(1, 0)));
417 assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000)));
418 assert_eq!(Duration::new(2, 0).checked_div(0), None);
419 }
1a4d82fc 420}