lambda_appsync/aws_scalars/
timestamp.rs

1use serde::{Deserialize, Serialize};
2use std::time::{Duration, SystemTime};
3
4/// AWS AppSync specific GraphQL scalar type implemented [SystemTime] new-type.
5/// Note that this type implements Copy
6#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
7#[serde(from = "u64", into = "u64")]
8pub struct AWSTimestamp(SystemTime);
9
10impl AWSTimestamp {
11    /// Returns an [AWSTimestamp] representing the current date and time, as reported by the system clock.
12    ///
13    /// # Example
14    /// ```
15    /// use lambda_appsync::AWSTimestamp;
16    ///
17    /// let now = AWSTimestamp::now();
18    /// ```
19    pub fn now() -> Self {
20        Self(SystemTime::now())
21    }
22
23    /// Converts timestamp into UNIX epoch as number of seconds.
24    ///
25    /// # Examples
26    /// ```
27    /// use lambda_appsync::AWSTimestamp;
28    ///
29    /// let ts = AWSTimestamp::from(1234);
30    /// assert_eq!(ts.into_u64(), 1234);
31    /// ```
32    pub fn into_u64(self) -> u64 {
33        self.into()
34    }
35
36    /// Creates an [AWSTimestamp] from a u64 representing seconds since the UNIX epoch.
37    ///
38    /// # Examples
39    /// ```
40    /// use lambda_appsync::AWSTimestamp;
41    ///
42    /// let ts = AWSTimestamp::from_u64(1234);
43    /// assert_eq!(ts.into_u64(), 1234);
44    /// ```
45    pub fn from_u64(value: u64) -> Self {
46        Self::from(value)
47    }
48}
49
50impl From<SystemTime> for AWSTimestamp {
51    fn from(time: SystemTime) -> Self {
52        Self(time)
53    }
54}
55
56impl PartialEq<SystemTime> for AWSTimestamp {
57    fn eq(&self, other: &SystemTime) -> bool {
58        self.0 == *other
59    }
60}
61
62impl From<AWSTimestamp> for u64 {
63    fn from(value: AWSTimestamp) -> Self {
64        value
65            .0
66            .duration_since(std::time::UNIX_EPOCH)
67            .expect("we should never manipulate dates earlier than EPOCH")
68            .as_secs()
69    }
70}
71
72impl std::fmt::Display for AWSTimestamp {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        write!(f, "{}", u64::from(*self))
75    }
76}
77
78impl From<u64> for AWSTimestamp {
79    fn from(value: u64) -> Self {
80        Self(std::time::UNIX_EPOCH + Duration::from_secs(value))
81    }
82}
83
84impl Default for AWSTimestamp {
85    fn default() -> Self {
86        Self::now()
87    }
88}
89
90impl std::ops::Add<Duration> for AWSTimestamp {
91    type Output = Self;
92    fn add(self, rhs: Duration) -> Self::Output {
93        Self(self.0 + rhs)
94    }
95}
96
97impl std::ops::AddAssign<Duration> for AWSTimestamp {
98    fn add_assign(&mut self, rhs: Duration) {
99        self.0 += rhs;
100    }
101}
102
103impl std::ops::Sub<Duration> for AWSTimestamp {
104    type Output = Self;
105    fn sub(self, rhs: Duration) -> Self::Output {
106        Self(self.0 - rhs)
107    }
108}
109
110impl std::ops::SubAssign<Duration> for AWSTimestamp {
111    fn sub_assign(&mut self, rhs: Duration) {
112        self.0 -= rhs;
113    }
114}
115
116impl std::ops::Sub<AWSTimestamp> for AWSTimestamp {
117    type Output = Duration;
118    fn sub(self, rhs: AWSTimestamp) -> Self::Output {
119        self.0
120            .duration_since(rhs.0)
121            .expect("the substracted AWSTimestamp MUST be earlier")
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    #[test]
130    fn test_timestamp_now() {
131        let ts = AWSTimestamp::now();
132        let now = SystemTime::now();
133        let diff = now.duration_since(ts.0).unwrap();
134        assert!(diff < Duration::from_secs(1));
135    }
136
137    #[test]
138    fn test_timestamp_default() {
139        let ts = AWSTimestamp::default();
140        let now = SystemTime::now();
141        let diff = now.duration_since(ts.0).unwrap();
142        assert!(diff < Duration::from_secs(1));
143    }
144
145    #[test]
146    fn test_timestamp_conversion() {
147        let now = SystemTime::now();
148        let secs = now.duration_since(std::time::UNIX_EPOCH).unwrap().as_secs();
149        let ts = AWSTimestamp::from(secs);
150        let back_to_secs: u64 = ts.into();
151        assert_eq!(secs, back_to_secs);
152    }
153
154    #[test]
155    fn test_timestamp_add() {
156        let ts = AWSTimestamp::from(1000);
157        let ts2 = ts + Duration::from_secs(500);
158        let secs: u64 = ts2.into();
159        assert_eq!(secs, 1500);
160    }
161
162    #[test]
163    fn test_timestamp_add_assign() {
164        let mut ts = AWSTimestamp::from(1000);
165        ts += Duration::from_secs(500);
166        let secs: u64 = ts.into();
167        assert_eq!(secs, 1500);
168    }
169
170    #[test]
171    fn test_timestamp_sub_duration() {
172        let ts = AWSTimestamp::from(1000);
173        let ts2 = ts - Duration::from_secs(500);
174        let secs: u64 = ts2.into();
175        assert_eq!(secs, 500);
176    }
177
178    #[test]
179    fn test_timestamp_sub_assign() {
180        let mut ts = AWSTimestamp::from(1000);
181        ts -= Duration::from_secs(500);
182        let secs: u64 = ts.into();
183        assert_eq!(secs, 500);
184    }
185
186    #[test]
187    fn test_timestamp_sub_timestamp() {
188        let ts1 = AWSTimestamp::from(1500);
189        let ts2 = AWSTimestamp::from(1000);
190        let diff = ts1 - ts2;
191        assert_eq!(diff.as_secs(), 500);
192    }
193
194    #[test]
195    #[should_panic(expected = "the substracted AWSTimestamp MUST be earlier")]
196    fn test_timestamp_sub_panic() {
197        let ts1 = AWSTimestamp::from(1000);
198        let ts2 = AWSTimestamp::from(1500);
199        let _diff = ts1 - ts2;
200    }
201
202    #[test]
203    fn test_display() {
204        let ts = AWSTimestamp::from(1234);
205        assert_eq!(ts.to_string(), "1234");
206    }
207
208    #[test]
209    fn test_from_system_time() {
210        let now = SystemTime::now();
211        let ts = AWSTimestamp::from(now);
212        assert_eq!(ts.0, now);
213    }
214
215    #[test]
216    fn test_partial_eq_system_time() {
217        let now = SystemTime::now();
218        let ts = AWSTimestamp::from(now);
219        assert_eq!(ts, now);
220    }
221
222    #[test]
223    fn test_into_u64() {
224        let ts = AWSTimestamp::from(1234);
225        assert_eq!(ts.into_u64(), 1234);
226    }
227
228    #[test]
229    fn test_from_u64() {
230        let ts = AWSTimestamp::from_u64(1234);
231        assert_eq!(ts.into_u64(), 1234);
232    }
233}