Skip to main content

openleadr_wire/
interval.rs

1//! Descriptions of temporal periods
2
3use crate::{Duration, values_map::ValuesMap};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use serde_with::skip_serializing_none;
7
8/// An object defining a temporal window and a list of valuesMaps. if intervalPeriod present may set
9/// temporal aspects of interval or override event.intervalPeriod.
10#[derive(Clone, Debug, PartialEq, Default, Serialize, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct Interval {
13    /// A client generated number assigned an interval object. Not a sequence number.
14    pub id: i32,
15    /// Defines start and durations of intervals.
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub interval_period: Option<IntervalPeriod>,
18    /// A list of valuesMap objects.
19    pub payloads: Vec<ValuesMap>,
20}
21
22impl Interval {
23    pub fn new(id: i32, payloads: Vec<ValuesMap>) -> Self {
24        Self {
25            id,
26            interval_period: None,
27            payloads,
28        }
29    }
30}
31
32/// Defines temporal aspects of intervals.
33///
34/// A start of "0001-01-01" or "0001-01-01T00:00:00" may indicate 'now'. See User Guide.
35/// A duration of "P9999Y" may indicate infinity. See User Guide.
36/// A randomizeStart indicates absolute range of client applied offset to start. See User Guide.
37#[skip_serializing_none]
38#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
39#[serde(rename_all = "camelCase")]
40pub struct IntervalPeriod {
41    /// The start time of an interval or set of intervals.
42    #[serde(with = "crate::serde_rfc3339")]
43    // FIXME field not required, though, it's unclear how to interpret it if it's missing
44    pub start: DateTime<Utc>,
45    /// The duration of an interval or set of intervals.
46    pub duration: Option<Duration>,
47    /// Indicates a randomization time that may be applied to start.
48    pub randomize_start: Option<Duration>,
49}
50
51impl IntervalPeriod {
52    pub fn new(start: DateTime<Utc>) -> Self {
53        Self {
54            start,
55            duration: None,
56            randomize_start: None,
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use crate::interval::IntervalPeriod;
64
65    #[test]
66    fn parse_interval_period() {
67        let only_start = r#"{"start": "2021-01-01T00:00:00Z"}"#;
68        let interval: IntervalPeriod = serde_json::from_str(only_start).unwrap();
69        assert_eq!(interval.start.to_rfc3339(), "2021-01-01T00:00:00+00:00");
70        assert!(interval.duration.is_none());
71        assert!(interval.randomize_start.is_none());
72
73        let start_now = r#"{"start": "0001-01-01T00:00:00Z"}"#;
74        let interval: IntervalPeriod = serde_json::from_str(start_now).unwrap();
75        assert_eq!(interval.start.to_rfc3339(), "0001-01-01T00:00:00+00:00");
76        assert!(interval.duration.is_none());
77        assert!(interval.randomize_start.is_none());
78
79        let infinit_duration = r#"{"duration": "P9999Y", "start":"2021-01-01T00:00:00Z"}"#;
80        let interval: IntervalPeriod = serde_json::from_str(infinit_duration).unwrap();
81        assert_eq!(interval.duration.unwrap().to_string(), "P9999Y0M0DT0H0M0S");
82        assert_eq!(interval.start.to_rfc3339(), "2021-01-01T00:00:00+00:00");
83        assert!(interval.randomize_start.is_none());
84
85        let all_fields = r#"{
86                  "duration": "P0Y1M2DT3H4M5S",
87                  "start": "2021-01-01T01:02:03Z",
88                  "randomizeStart": "PT3M"
89               }"#;
90        let interval: IntervalPeriod = serde_json::from_str(all_fields).unwrap();
91        assert_eq!(interval.duration.unwrap().to_string(), "P0Y1M2DT3H4M5S");
92        assert_eq!(interval.start.to_rfc3339(), "2021-01-01T01:02:03+00:00");
93        assert_eq!(
94            interval.randomize_start.unwrap().to_string(),
95            "P0Y0M0DT0H3M0S"
96        );
97    }
98}