zebra_chain/serialization/
date_time.rs1use std::{
4 fmt,
5 num::{ParseIntError, TryFromIntError},
6 str::FromStr,
7};
8
9use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
10use chrono::{TimeZone, Utc};
11
12use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize};
13
14#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
16#[serde(transparent)]
17pub struct DateTime32 {
18 timestamp: u32,
19}
20
21#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
23pub struct Duration32 {
24 seconds: u32,
25}
26
27impl DateTime32 {
28 pub const MIN: DateTime32 = DateTime32 {
30 timestamp: u32::MIN,
31 };
32
33 pub const MAX: DateTime32 = DateTime32 {
35 timestamp: u32::MAX,
36 };
37
38 pub fn timestamp(&self) -> u32 {
40 self.timestamp
41 }
42
43 pub fn to_chrono(self) -> chrono::DateTime<Utc> {
45 self.into()
46 }
47
48 pub fn now() -> DateTime32 {
54 chrono::Utc::now()
55 .try_into()
56 .expect("unexpected out of range chrono::DateTime")
57 }
58
59 pub fn checked_duration_since(&self, earlier: DateTime32) -> Option<Duration32> {
62 self.timestamp
63 .checked_sub(earlier.timestamp)
64 .map(Duration32::from)
65 }
66
67 pub fn saturating_duration_since(&self, earlier: DateTime32) -> Duration32 {
70 Duration32::from(self.timestamp.saturating_sub(earlier.timestamp))
71 }
72
73 #[allow(clippy::unwrap_in_result)]
76 pub fn checked_elapsed(&self, now: chrono::DateTime<Utc>) -> Option<Duration32> {
77 DateTime32::try_from(now)
78 .expect("unexpected out of range chrono::DateTime")
79 .checked_duration_since(*self)
80 }
81
82 pub fn saturating_elapsed(&self, now: chrono::DateTime<Utc>) -> Duration32 {
85 DateTime32::try_from(now)
86 .expect("unexpected out of range chrono::DateTime")
87 .saturating_duration_since(*self)
88 }
89
90 pub fn checked_add(&self, duration: Duration32) -> Option<DateTime32> {
93 self.timestamp
94 .checked_add(duration.seconds)
95 .map(DateTime32::from)
96 }
97
98 pub fn saturating_add(&self, duration: Duration32) -> DateTime32 {
101 DateTime32::from(self.timestamp.saturating_add(duration.seconds))
102 }
103
104 pub fn checked_sub(&self, duration: Duration32) -> Option<DateTime32> {
107 self.timestamp
108 .checked_sub(duration.seconds)
109 .map(DateTime32::from)
110 }
111
112 pub fn saturating_sub(&self, duration: Duration32) -> DateTime32 {
115 DateTime32::from(self.timestamp.saturating_sub(duration.seconds))
116 }
117}
118
119impl Duration32 {
120 pub const MIN: Duration32 = Duration32 { seconds: u32::MIN };
122
123 pub const MAX: Duration32 = Duration32 { seconds: u32::MAX };
125
126 pub const fn from_seconds(seconds: u32) -> Self {
128 Duration32 { seconds }
129 }
130
131 pub const fn from_minutes(minutes: u32) -> Self {
136 Duration32::from_seconds(minutes.saturating_mul(60))
137 }
138
139 pub const fn from_hours(hours: u32) -> Self {
144 Duration32::from_minutes(hours.saturating_mul(60))
145 }
146
147 pub const fn from_days(days: u32) -> Self {
152 Duration32::from_hours(days.saturating_mul(24))
153 }
154
155 pub fn seconds(&self) -> u32 {
157 self.seconds
158 }
159
160 pub fn to_chrono(self) -> chrono::Duration {
162 self.into()
163 }
164
165 pub fn to_std(self) -> std::time::Duration {
167 self.into()
168 }
169
170 pub fn checked_add(&self, duration: Duration32) -> Option<Duration32> {
173 self.seconds
174 .checked_add(duration.seconds)
175 .map(Duration32::from)
176 }
177
178 pub fn saturating_add(&self, duration: Duration32) -> Duration32 {
181 Duration32::from(self.seconds.saturating_add(duration.seconds))
182 }
183
184 pub fn checked_sub(&self, duration: Duration32) -> Option<Duration32> {
187 self.seconds
188 .checked_sub(duration.seconds)
189 .map(Duration32::from)
190 }
191
192 pub fn saturating_sub(&self, duration: Duration32) -> Duration32 {
195 Duration32::from(self.seconds.saturating_sub(duration.seconds))
196 }
197}
198
199impl fmt::Debug for DateTime32 {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 f.debug_struct("DateTime32")
202 .field("timestamp", &self.timestamp)
203 .field("calendar", &chrono::DateTime::<Utc>::from(*self))
204 .finish()
205 }
206}
207
208impl fmt::Debug for Duration32 {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 f.debug_struct("Duration32")
211 .field("seconds", &self.seconds)
212 .field("calendar", &chrono::Duration::from(*self))
213 .finish()
214 }
215}
216
217impl From<u32> for DateTime32 {
218 fn from(value: u32) -> Self {
219 DateTime32 { timestamp: value }
220 }
221}
222
223impl From<&u32> for DateTime32 {
224 fn from(value: &u32) -> Self {
225 (*value).into()
226 }
227}
228
229impl From<DateTime32> for chrono::DateTime<Utc> {
230 fn from(value: DateTime32) -> Self {
231 Utc.timestamp_opt(value.timestamp.into(), 0)
233 .single()
234 .expect("in-range number of seconds and valid nanosecond")
235 }
236}
237
238impl From<&DateTime32> for chrono::DateTime<Utc> {
239 fn from(value: &DateTime32) -> Self {
240 (*value).into()
241 }
242}
243
244impl From<u32> for Duration32 {
245 fn from(value: u32) -> Self {
246 Duration32 { seconds: value }
247 }
248}
249
250impl From<&u32> for Duration32 {
251 fn from(value: &u32) -> Self {
252 (*value).into()
253 }
254}
255
256impl From<Duration32> for chrono::Duration {
257 fn from(value: Duration32) -> Self {
258 chrono::Duration::seconds(value.seconds.into())
260 }
261}
262
263impl From<&Duration32> for chrono::Duration {
264 fn from(value: &Duration32) -> Self {
265 (*value).into()
266 }
267}
268
269impl From<Duration32> for std::time::Duration {
270 fn from(value: Duration32) -> Self {
271 std::time::Duration::from_secs(value.seconds.into())
273 }
274}
275
276impl From<&Duration32> for std::time::Duration {
277 fn from(value: &Duration32) -> Self {
278 (*value).into()
279 }
280}
281
282impl TryFrom<chrono::DateTime<Utc>> for DateTime32 {
283 type Error = TryFromIntError;
284
285 fn try_from(value: chrono::DateTime<Utc>) -> Result<Self, Self::Error> {
289 Ok(Self {
290 timestamp: value.timestamp().try_into()?,
291 })
292 }
293}
294
295impl TryFrom<&chrono::DateTime<Utc>> for DateTime32 {
296 type Error = TryFromIntError;
297
298 fn try_from(value: &chrono::DateTime<Utc>) -> Result<Self, Self::Error> {
302 (*value).try_into()
303 }
304}
305
306impl TryFrom<chrono::Duration> for Duration32 {
307 type Error = TryFromIntError;
308
309 fn try_from(value: chrono::Duration) -> Result<Self, Self::Error> {
313 Ok(Self {
314 seconds: value.num_seconds().try_into()?,
315 })
316 }
317}
318
319impl TryFrom<&chrono::Duration> for Duration32 {
320 type Error = TryFromIntError;
321
322 fn try_from(value: &chrono::Duration) -> Result<Self, Self::Error> {
326 (*value).try_into()
327 }
328}
329
330impl TryFrom<std::time::Duration> for Duration32 {
331 type Error = TryFromIntError;
332
333 fn try_from(value: std::time::Duration) -> Result<Self, Self::Error> {
337 Ok(Self {
338 seconds: value.as_secs().try_into()?,
339 })
340 }
341}
342
343impl TryFrom<&std::time::Duration> for Duration32 {
344 type Error = TryFromIntError;
345
346 fn try_from(value: &std::time::Duration) -> Result<Self, Self::Error> {
350 (*value).try_into()
351 }
352}
353
354impl FromStr for DateTime32 {
355 type Err = ParseIntError;
356
357 fn from_str(s: &str) -> Result<Self, Self::Err> {
358 Ok(DateTime32 {
359 timestamp: s.parse()?,
360 })
361 }
362}
363
364impl FromStr for Duration32 {
365 type Err = ParseIntError;
366
367 fn from_str(s: &str) -> Result<Self, Self::Err> {
368 Ok(Duration32 {
369 seconds: s.parse()?,
370 })
371 }
372}
373
374impl ZcashSerialize for DateTime32 {
375 fn zcash_serialize<W: std::io::Write>(&self, mut writer: W) -> Result<(), std::io::Error> {
376 writer.write_u32::<LittleEndian>(self.timestamp)
377 }
378}
379
380impl ZcashDeserialize for DateTime32 {
381 fn zcash_deserialize<R: std::io::Read>(mut reader: R) -> Result<Self, SerializationError> {
382 Ok(DateTime32 {
383 timestamp: reader.read_u32::<LittleEndian>()?,
384 })
385 }
386}