Skip to main content

sofie_core/clock/
shifted.rs

1use jiff::{SignedDuration, Timestamp};
2
3use super::{Clock, Source};
4use crate::Instant;
5
6impl Clock {
7    #[must_use]
8    pub fn starting_at(start: Instant) -> Self {
9        Self {
10            source: Source::Shifted(start.timestamp().duration_since(Timestamp::now())),
11        }
12    }
13
14    /// Runs on from `seconds` past this clock's now; a test clock's shifted copy no longer stands still.
15    #[must_use]
16    pub fn shifted(&self, seconds: i64) -> Self {
17        let offset = self.now().timestamp().duration_since(Timestamp::now());
18        Self {
19            source: Source::Shifted(offset.saturating_add(SignedDuration::from_secs(seconds))),
20        }
21    }
22}
23
24/// Saturating by a `SignedDuration` cannot fail; only calendar units could.
25pub(super) fn now(offset: SignedDuration) -> Instant {
26    Instant::from(
27        Timestamp::now()
28            .saturating_add(offset)
29            .unwrap_or(Timestamp::MAX),
30    )
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn a_shifted_clock_starts_at_its_moment_and_runs_on() {
39        let start = Instant::parse("2027-01-01T09:00").unwrap();
40
41        let clock = Clock::starting_at(start);
42
43        let now = clock.now().timestamp();
44        assert!(now >= start.timestamp(), "{now}");
45        assert!(now.duration_since(start.timestamp()) < SignedDuration::from_secs(5));
46    }
47
48    #[test]
49    fn a_shifted_clock_runs_the_given_seconds_ahead_of_its_source() {
50        let start = Instant::parse("2027-01-01T09:00").unwrap();
51
52        let clock = Clock::starting_at(start).shifted(-3600);
53
54        let behind = start.timestamp().duration_since(clock.now().timestamp());
55        assert!(behind > SignedDuration::from_mins(59), "{behind}");
56        assert!(behind <= SignedDuration::from_mins(60), "{behind}");
57    }
58}