datetime/
duration.rs

1//! Lengths of time on the timeline.
2
3use std::ops::{Add, Sub, Mul};
4
5
6/// A **duration** is a length of time on the timeline, irrespective of
7/// time zone or calendar format, with millisecond precision.
8#[derive(Clone, PartialEq, Eq, Debug, Copy)]
9pub struct Duration {
10    seconds: i64,
11    milliseconds: i16,
12}
13
14impl Duration {
15
16    /// Create a new zero-length duration.
17    pub fn zero() -> Self {
18        Self { seconds: 0, milliseconds: 0 }
19    }
20
21    /// Create a new duration that’s the given number of seconds long.
22    pub fn of(seconds: i64) -> Self {
23        Self { seconds, milliseconds: 0 }
24    }
25
26    /// Create a new duration that’s the given number of seconds and
27    /// milliseconds long.
28    pub fn of_ms(seconds: i64, milliseconds: i16) -> Self {
29        assert!(milliseconds >= 0 && milliseconds <= 999);  // TODO: replace assert with returning Result
30        Self { seconds, milliseconds }
31    }
32
33    /// Return the seconds and milliseconds portions of the duration as
34    /// a 2-element tuple.
35    pub fn lengths(&self) -> (i64, i16) {
36        (self.seconds, self.milliseconds)
37    }
38
39    // I’ve done it like this instead of having separate seconds() and
40    // milliseconds() functions, because I think there’s a danger that
41    // people will think that milliseconds() returns the *total* length
42    // in milliseconds, rather than just this particular portion. This
43    // way, it’s clear that there are two separate values being returned.
44}
45
46#[allow(clippy::suspicious_arithmetic_impl)]
47impl Add<Duration> for Duration {
48    type Output = Self;
49
50    fn add(self, rhs: Self) -> Self {
51        let ms = self.milliseconds + rhs.milliseconds;
52        if ms >= 1000 {
53            Self::of_ms(self.seconds + rhs.seconds + 1, ms - 1000)
54        }
55        else {
56            Self::of_ms(self.seconds + rhs.seconds, ms)
57        }
58    }
59}
60
61#[allow(clippy::suspicious_arithmetic_impl)]
62impl Sub<Duration> for Duration {
63    type Output = Self;
64
65    fn sub(self, rhs: Self) -> Self {
66        let ms = self.milliseconds - rhs.milliseconds;
67        if ms < 0 {
68            Self::of_ms(self.seconds - rhs.seconds - 1, ms + 1000)
69        }
70        else {
71            Self::of_ms(self.seconds - rhs.seconds, ms)
72        }
73    }
74}
75
76#[allow(clippy::suspicious_arithmetic_impl)]
77impl Mul<i64> for Duration {
78    type Output = Self;
79
80    fn mul(self, amount: i64) -> Self {
81        let ms = self.milliseconds as i64 * amount;
82        Self::of_ms(self.seconds * amount + ms / 1000, (ms % 1000) as i16)
83    }
84}