1 use super::DateTime;
2 use crate::format::SecondsFormat;
3 #[cfg(feature = "clock")]
4 use crate::offset::Local;
5 use crate::offset::{FixedOffset, LocalResult, TimeZone, Utc};
6 use core::fmt;
7 use core::ops::Deref;
8 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
9 
10 impl<Tz: TimeZone> Encodable for DateTime<Tz> {
encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error>11     fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
12         self.to_rfc3339_opts(SecondsFormat::AutoSi, true).encode(s)
13     }
14 }
15 
16 // lik? function to convert a LocalResult into a serde-ish Result
from<T, D>(me: LocalResult<T>, d: &mut D) -> Result<T, D::Error> where D: Decoder, T: fmt::Display,17 fn from<T, D>(me: LocalResult<T>, d: &mut D) -> Result<T, D::Error>
18 where
19     D: Decoder,
20     T: fmt::Display,
21 {
22     match me {
23         LocalResult::None => Err(d.error("value is not a legal timestamp")),
24         LocalResult::Ambiguous(..) => Err(d.error("value is an ambiguous timestamp")),
25         LocalResult::Single(val) => Ok(val),
26     }
27 }
28 
29 impl Decodable for DateTime<FixedOffset> {
decode<D: Decoder>(d: &mut D) -> Result<DateTime<FixedOffset>, D::Error>30     fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<FixedOffset>, D::Error> {
31         d.read_str()?.parse::<DateTime<FixedOffset>>().map_err(|_| d.error("invalid date and time"))
32     }
33 }
34 
35 #[allow(deprecated)]
36 impl Decodable for TsSeconds<FixedOffset> {
37     #[allow(deprecated)]
decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<FixedOffset>, D::Error>38     fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<FixedOffset>, D::Error> {
39         from(FixedOffset::east_opt(0).unwrap().timestamp_opt(d.read_i64()?, 0), d).map(TsSeconds)
40     }
41 }
42 
43 impl Decodable for DateTime<Utc> {
decode<D: Decoder>(d: &mut D) -> Result<DateTime<Utc>, D::Error>44     fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Utc>, D::Error> {
45         d.read_str()?
46             .parse::<DateTime<FixedOffset>>()
47             .map(|dt| dt.with_timezone(&Utc))
48             .map_err(|_| d.error("invalid date and time"))
49     }
50 }
51 
52 /// A [`DateTime`] that can be deserialized from a timestamp
53 ///
54 /// A timestamp here is seconds since the epoch
55 #[derive(Debug)]
56 pub struct TsSeconds<Tz: TimeZone>(DateTime<Tz>);
57 
58 #[allow(deprecated)]
59 impl<Tz: TimeZone> From<TsSeconds<Tz>> for DateTime<Tz> {
60     /// Pull the inner `DateTime<Tz>` out
61     #[allow(deprecated)]
from(obj: TsSeconds<Tz>) -> DateTime<Tz>62     fn from(obj: TsSeconds<Tz>) -> DateTime<Tz> {
63         obj.0
64     }
65 }
66 
67 #[allow(deprecated)]
68 impl<Tz: TimeZone> Deref for TsSeconds<Tz> {
69     type Target = DateTime<Tz>;
70 
deref(&self) -> &Self::Target71     fn deref(&self) -> &Self::Target {
72         &self.0
73     }
74 }
75 
76 #[allow(deprecated)]
77 impl Decodable for TsSeconds<Utc> {
decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<Utc>, D::Error>78     fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<Utc>, D::Error> {
79         from(Utc.timestamp_opt(d.read_i64()?, 0), d).map(TsSeconds)
80     }
81 }
82 
83 #[cfg(feature = "clock")]
84 impl Decodable for DateTime<Local> {
decode<D: Decoder>(d: &mut D) -> Result<DateTime<Local>, D::Error>85     fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Local>, D::Error> {
86         match d.read_str()?.parse::<DateTime<FixedOffset>>() {
87             Ok(dt) => Ok(dt.with_timezone(&Local)),
88             Err(_) => Err(d.error("invalid date and time")),
89         }
90     }
91 }
92 
93 #[cfg(feature = "clock")]
94 #[allow(deprecated)]
95 impl Decodable for TsSeconds<Local> {
96     #[allow(deprecated)]
decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<Local>, D::Error>97     fn decode<D: Decoder>(d: &mut D) -> Result<TsSeconds<Local>, D::Error> {
98         from(Utc.timestamp_opt(d.read_i64()?, 0), d).map(|dt| TsSeconds(dt.with_timezone(&Local)))
99     }
100 }
101 
102 #[cfg(test)]
103 mod tests {
104     use crate::datetime::test_encodable_json;
105     use crate::datetime::{test_decodable_json, test_decodable_json_timestamps};
106     use rustc_serialize::json;
107 
108     #[test]
test_encodable()109     fn test_encodable() {
110         test_encodable_json(json::encode, json::encode);
111     }
112 
113     #[cfg(feature = "clock")]
114     #[test]
test_decodable()115     fn test_decodable() {
116         test_decodable_json(json::decode, json::decode, json::decode);
117     }
118 
119     #[cfg(feature = "clock")]
120     #[test]
test_decodable_timestamps()121     fn test_decodable_timestamps() {
122         test_decodable_json_timestamps(json::decode, json::decode, json::decode);
123     }
124 }
125