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