1 use humantime;
2 use std::{
3     fmt,
4     time::{Duration, SystemTime, UNIX_EPOCH},
5 };
6 
7 /// A UTC timestamp used for serialization to and from the plist date type.
8 ///
9 /// Note that while this type implements `Serialize` and `Deserialize` it will behave strangely if
10 /// used with serializers from outside this crate.
11 #[derive(Clone, Copy, Eq, Hash, PartialEq)]
12 pub struct Date {
13     inner: SystemTime,
14 }
15 
16 pub(crate) struct InfiniteOrNanDate;
17 
18 impl Date {
19     /// The unix timestamp of the plist epoch.
20     const PLIST_EPOCH_UNIX_TIMESTAMP: Duration = Duration::from_secs(978_307_200);
21 
from_rfc3339(date: &str) -> Result<Self, ()>22     pub(crate) fn from_rfc3339(date: &str) -> Result<Self, ()> {
23         Ok(Date {
24             inner: humantime::parse_rfc3339(date).map_err(|_| ())?,
25         })
26     }
27 
to_rfc3339(&self) -> String28     pub(crate) fn to_rfc3339(&self) -> String {
29         format!("{}", humantime::format_rfc3339(self.inner))
30     }
31 
from_seconds_since_plist_epoch( timestamp: f64, ) -> Result<Date, InfiniteOrNanDate>32     pub(crate) fn from_seconds_since_plist_epoch(
33         timestamp: f64,
34     ) -> Result<Date, InfiniteOrNanDate> {
35         // `timestamp` is the number of seconds since the plist epoch of 1/1/2001 00:00:00.
36         let plist_epoch = UNIX_EPOCH + Date::PLIST_EPOCH_UNIX_TIMESTAMP;
37 
38         if !timestamp.is_finite() {
39             return Err(InfiniteOrNanDate);
40         }
41 
42         let is_negative = timestamp < 0.0;
43         let timestamp = timestamp.abs();
44         let seconds = timestamp.floor() as u64;
45         let subsec_nanos = (timestamp.fract() * 1e9) as u32;
46 
47         let dur_since_plist_epoch = Duration::new(seconds, subsec_nanos);
48 
49         let inner = if is_negative {
50             plist_epoch - dur_since_plist_epoch
51         } else {
52             plist_epoch + dur_since_plist_epoch
53         };
54 
55         Ok(Date { inner })
56     }
57 
to_seconds_since_plist_epoch(&self) -> f6458     pub(crate) fn to_seconds_since_plist_epoch(&self) -> f64 {
59         // needed until #![feature(duration_float)] is stabilized
60         fn as_secs_f64(d: Duration) -> f64 {
61             const NANOS_PER_SEC: f64 = 1_000_000_000.00;
62             (d.as_secs() as f64) + f64::from(d.subsec_nanos()) / NANOS_PER_SEC
63         }
64 
65         let plist_epoch = UNIX_EPOCH + Date::PLIST_EPOCH_UNIX_TIMESTAMP;
66         match self.inner.duration_since(plist_epoch) {
67             Ok(dur_since_plist_epoch) => as_secs_f64(dur_since_plist_epoch),
68             Err(err) => -as_secs_f64(err.duration()),
69         }
70     }
71 }
72 
73 impl fmt::Debug for Date {
fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error>74     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
75         let rfc3339 = humantime::format_rfc3339(self.inner);
76         <humantime::Rfc3339Timestamp as fmt::Display>::fmt(&rfc3339, f)
77     }
78 }
79 
80 impl From<SystemTime> for Date {
from(date: SystemTime) -> Self81     fn from(date: SystemTime) -> Self {
82         Date { inner: date }
83     }
84 }
85 
86 impl Into<SystemTime> for Date {
into(self) -> SystemTime87     fn into(self) -> SystemTime {
88         self.inner
89     }
90 }
91 
92 #[cfg(feature = "serde")]
93 pub mod serde_impls {
94     use serde::{
95         de::{Deserialize, Deserializer, Error, Unexpected, Visitor},
96         ser::{Serialize, Serializer},
97     };
98     use std::fmt;
99 
100     use crate::Date;
101 
102     pub const DATE_NEWTYPE_STRUCT_NAME: &str = "PLIST-DATE";
103 
104     impl Serialize for Date {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,105         fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
106         where
107             S: Serializer,
108         {
109             let date_str = self.to_rfc3339();
110             serializer.serialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, &date_str)
111         }
112     }
113 
114     struct DateNewtypeVisitor;
115 
116     impl<'de> Visitor<'de> for DateNewtypeVisitor {
117         type Value = Date;
118 
expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result119         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
120             formatter.write_str("a plist date newtype")
121         }
122 
visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error> where D: Deserializer<'de>,123         fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
124         where
125             D: Deserializer<'de>,
126         {
127             deserializer.deserialize_str(DateStrVisitor)
128         }
129     }
130 
131     struct DateStrVisitor;
132 
133     impl<'de> Visitor<'de> for DateStrVisitor {
134         type Value = Date;
135 
expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result136         fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
137             formatter.write_str("a plist date string")
138         }
139 
visit_str<E>(self, v: &str) -> Result<Self::Value, E> where E: Error,140         fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
141         where
142             E: Error,
143         {
144             Date::from_rfc3339(v).map_err(|()| E::invalid_value(Unexpected::Str(v), &self))
145         }
146     }
147 
148     impl<'de> Deserialize<'de> for Date {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,149         fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
150         where
151             D: Deserializer<'de>,
152         {
153             deserializer.deserialize_newtype_struct(DATE_NEWTYPE_STRUCT_NAME, DateNewtypeVisitor)
154         }
155     }
156 }
157