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