/rust/registry/src/index.crates.io-1949cf8c6b5b557f/chrono-0.4.44/src/datetime/serde.rs
Line | Count | Source |
1 | | use core::fmt; |
2 | | use serde::{de, ser}; |
3 | | |
4 | | use super::DateTime; |
5 | | use crate::format::{SecondsFormat, write_rfc3339}; |
6 | | #[cfg(feature = "clock")] |
7 | | use crate::offset::Local; |
8 | | use crate::offset::{FixedOffset, Offset, TimeZone, Utc}; |
9 | | |
10 | | #[doc(hidden)] |
11 | | #[derive(Debug)] |
12 | | pub struct SecondsTimestampVisitor; |
13 | | |
14 | | #[doc(hidden)] |
15 | | #[derive(Debug)] |
16 | | pub struct NanoSecondsTimestampVisitor; |
17 | | |
18 | | #[doc(hidden)] |
19 | | #[derive(Debug)] |
20 | | pub struct MicroSecondsTimestampVisitor; |
21 | | |
22 | | #[doc(hidden)] |
23 | | #[derive(Debug)] |
24 | | pub struct MilliSecondsTimestampVisitor; |
25 | | |
26 | | /// Serialize to an RFC 3339 formatted string |
27 | | /// |
28 | | /// As an extension to RFC 3339 this can serialize `DateTime`s outside the range of 0-9999 years |
29 | | /// using an ISO 8601 syntax (which prepends an `-` or `+`). |
30 | | /// |
31 | | /// See [the `serde` module](crate::serde) for alternate serializations. |
32 | | impl<Tz: TimeZone> ser::Serialize for DateTime<Tz> { |
33 | 0 | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
34 | 0 | where |
35 | 0 | S: ser::Serializer, |
36 | | { |
37 | | struct FormatIso8601<'a, Tz: TimeZone> { |
38 | | inner: &'a DateTime<Tz>, |
39 | | } |
40 | | |
41 | | impl<Tz: TimeZone> fmt::Display for FormatIso8601<'_, Tz> { |
42 | 0 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
43 | 0 | let naive = self.inner.naive_local(); |
44 | 0 | let offset = self.inner.offset.fix(); |
45 | 0 | write_rfc3339(f, naive, offset, SecondsFormat::AutoSi, true) |
46 | 0 | } |
47 | | } |
48 | | |
49 | 0 | serializer.collect_str(&FormatIso8601 { inner: self }) |
50 | 0 | } |
51 | | } |
52 | | |
53 | | struct DateTimeVisitor; |
54 | | |
55 | | impl de::Visitor<'_> for DateTimeVisitor { |
56 | | type Value = DateTime<FixedOffset>; |
57 | | |
58 | 0 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
59 | 0 | formatter.write_str("an RFC 3339 formatted date and time string") |
60 | 0 | } |
61 | | |
62 | 0 | fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> |
63 | 0 | where |
64 | 0 | E: de::Error, |
65 | | { |
66 | 0 | value.parse().map_err(E::custom) |
67 | 0 | } |
68 | | } |
69 | | |
70 | | /// Deserialize an RFC 3339 formatted string into a `DateTime<FixedOffset>` |
71 | | /// |
72 | | /// As an extension to RFC 3339 this can deserialize to `DateTime`s outside the range of 0-9999 |
73 | | /// years using an ISO 8601 syntax (which prepends an `-` or `+`). |
74 | | /// |
75 | | /// See [the `serde` module](crate::serde) for alternate deserialization formats. |
76 | | impl<'de> de::Deserialize<'de> for DateTime<FixedOffset> { |
77 | 0 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
78 | 0 | where |
79 | 0 | D: de::Deserializer<'de>, |
80 | | { |
81 | 0 | deserializer.deserialize_str(DateTimeVisitor) |
82 | 0 | } |
83 | | } |
84 | | |
85 | | /// Deserialize an RFC 3339 formatted string into a `DateTime<Utc>` |
86 | | /// |
87 | | /// If the value contains an offset from UTC that is not zero, the value will be converted to UTC. |
88 | | /// |
89 | | /// As an extension to RFC 3339 this can deserialize to `DateTime`s outside the range of 0-9999 |
90 | | /// years using an ISO 8601 syntax (which prepends an `-` or `+`). |
91 | | /// |
92 | | /// See [the `serde` module](crate::serde) for alternate deserialization formats. |
93 | | impl<'de> de::Deserialize<'de> for DateTime<Utc> { |
94 | 0 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
95 | 0 | where |
96 | 0 | D: de::Deserializer<'de>, |
97 | | { |
98 | 0 | deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Utc)) |
99 | 0 | } |
100 | | } |
101 | | |
102 | | /// Deserialize an RFC 3339 formatted string into a `DateTime<Local>` |
103 | | /// |
104 | | /// The value will remain the same instant in UTC, but the offset will be recalculated to match |
105 | | /// that of the `Local` platform time zone. |
106 | | /// |
107 | | /// As an extension to RFC 3339 this can deserialize to `DateTime`s outside the range of 0-9999 |
108 | | /// years using an ISO 8601 syntax (which prepends an `-` or `+`). |
109 | | /// |
110 | | /// See [the `serde` module](crate::serde) for alternate deserialization formats. |
111 | | #[cfg(feature = "clock")] |
112 | | impl<'de> de::Deserialize<'de> for DateTime<Local> { |
113 | 0 | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
114 | 0 | where |
115 | 0 | D: de::Deserializer<'de>, |
116 | | { |
117 | 0 | deserializer.deserialize_str(DateTimeVisitor).map(|dt| dt.with_timezone(&Local)) |
118 | 0 | } |
119 | | } |
120 | | |
121 | | /// Ser/de to/from timestamps in nanoseconds |
122 | | /// |
123 | | /// Intended for use with `serde`'s `with` attribute. |
124 | | /// |
125 | | /// # Example: |
126 | | /// |
127 | | /// ```rust |
128 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
129 | | /// # use serde_derive::{Deserialize, Serialize}; |
130 | | /// use chrono::serde::ts_nanoseconds; |
131 | | /// #[derive(Deserialize, Serialize)] |
132 | | /// struct S { |
133 | | /// #[serde(with = "ts_nanoseconds")] |
134 | | /// time: DateTime<Utc>, |
135 | | /// } |
136 | | /// |
137 | | /// let time = NaiveDate::from_ymd_opt(2018, 5, 17) |
138 | | /// .unwrap() |
139 | | /// .and_hms_nano_opt(02, 04, 59, 918355733) |
140 | | /// .unwrap() |
141 | | /// .and_utc(); |
142 | | /// let my_s = S { time: time.clone() }; |
143 | | /// |
144 | | /// let as_string = serde_json::to_string(&my_s)?; |
145 | | /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); |
146 | | /// let my_s: S = serde_json::from_str(&as_string)?; |
147 | | /// assert_eq!(my_s.time, time); |
148 | | /// # Ok::<(), serde_json::Error>(()) |
149 | | /// ``` |
150 | | pub mod ts_nanoseconds { |
151 | | use core::fmt; |
152 | | use serde::{de, ser}; |
153 | | |
154 | | use crate::serde::invalid_ts; |
155 | | use crate::{DateTime, Utc}; |
156 | | |
157 | | use super::NanoSecondsTimestampVisitor; |
158 | | |
159 | | /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch |
160 | | /// |
161 | | /// Intended for use with `serde`s `serialize_with` attribute. |
162 | | /// |
163 | | /// # Errors |
164 | | /// |
165 | | /// An `i64` with nanosecond precision can span a range of ~584 years. This function returns an |
166 | | /// error on an out of range `DateTime`. |
167 | | /// |
168 | | /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and |
169 | | /// 2262-04-11T23:47:16.854775804. |
170 | | /// |
171 | | /// # Example: |
172 | | /// |
173 | | /// ```rust |
174 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
175 | | /// # use serde_derive::Serialize; |
176 | | /// use chrono::serde::ts_nanoseconds::serialize as to_nano_ts; |
177 | | /// #[derive(Serialize)] |
178 | | /// struct S { |
179 | | /// #[serde(serialize_with = "to_nano_ts")] |
180 | | /// time: DateTime<Utc>, |
181 | | /// } |
182 | | /// |
183 | | /// let my_s = S { |
184 | | /// time: NaiveDate::from_ymd_opt(2018, 5, 17) |
185 | | /// .unwrap() |
186 | | /// .and_hms_nano_opt(02, 04, 59, 918355733) |
187 | | /// .unwrap() |
188 | | /// .and_utc(), |
189 | | /// }; |
190 | | /// let as_string = serde_json::to_string(&my_s)?; |
191 | | /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); |
192 | | /// # Ok::<(), serde_json::Error>(()) |
193 | | /// ``` |
194 | 0 | pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> |
195 | 0 | where |
196 | 0 | S: ser::Serializer, |
197 | | { |
198 | 0 | serializer.serialize_i64(dt.timestamp_nanos_opt().ok_or(ser::Error::custom( |
199 | | "value out of range for a timestamp with nanosecond precision", |
200 | 0 | ))?) |
201 | 0 | } |
202 | | |
203 | | /// Deserialize a [`DateTime`] from a nanosecond timestamp |
204 | | /// |
205 | | /// Intended for use with `serde`s `deserialize_with` attribute. |
206 | | /// |
207 | | /// # Example: |
208 | | /// |
209 | | /// ```rust |
210 | | /// # use chrono::{DateTime, TimeZone, Utc}; |
211 | | /// # use serde_derive::Deserialize; |
212 | | /// use chrono::serde::ts_nanoseconds::deserialize as from_nano_ts; |
213 | | /// #[derive(Debug, PartialEq, Deserialize)] |
214 | | /// struct S { |
215 | | /// #[serde(deserialize_with = "from_nano_ts")] |
216 | | /// time: DateTime<Utc>, |
217 | | /// } |
218 | | /// |
219 | | /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; |
220 | | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355733).unwrap() }); |
221 | | /// |
222 | | /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?; |
223 | | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(-1, 999_999_999).unwrap() }); |
224 | | /// # Ok::<(), serde_json::Error>(()) |
225 | | /// ``` |
226 | 0 | pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> |
227 | 0 | where |
228 | 0 | D: de::Deserializer<'de>, |
229 | | { |
230 | 0 | d.deserialize_i64(NanoSecondsTimestampVisitor) |
231 | 0 | } |
232 | | |
233 | | impl de::Visitor<'_> for NanoSecondsTimestampVisitor { |
234 | | type Value = DateTime<Utc>; |
235 | | |
236 | 0 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
237 | 0 | formatter.write_str("a unix timestamp in nanoseconds") |
238 | 0 | } |
239 | | |
240 | | /// Deserialize a timestamp in nanoseconds since the epoch |
241 | 0 | fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> |
242 | 0 | where |
243 | 0 | E: de::Error, |
244 | | { |
245 | 0 | Ok(DateTime::from_timestamp_nanos(value)) |
246 | 0 | } |
247 | | |
248 | | /// Deserialize a timestamp in nanoseconds since the epoch |
249 | 0 | fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> |
250 | 0 | where |
251 | 0 | E: de::Error, |
252 | | { |
253 | 0 | DateTime::from_timestamp((value / 1_000_000_000) as i64, (value % 1_000_000_000) as u32) |
254 | 0 | .ok_or_else(|| invalid_ts(value)) |
255 | 0 | } |
256 | | } |
257 | | } |
258 | | |
259 | | /// Ser/de to/from optional timestamps in nanoseconds |
260 | | /// |
261 | | /// Intended for use with `serde`'s `with` attribute. |
262 | | /// |
263 | | /// # Example: |
264 | | /// |
265 | | /// ```rust |
266 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
267 | | /// # use serde_derive::{Deserialize, Serialize}; |
268 | | /// use chrono::serde::ts_nanoseconds_option; |
269 | | /// #[derive(Deserialize, Serialize)] |
270 | | /// struct S { |
271 | | /// #[serde(with = "ts_nanoseconds_option")] |
272 | | /// time: Option<DateTime<Utc>>, |
273 | | /// } |
274 | | /// |
275 | | /// let time = Some( |
276 | | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
277 | | /// .unwrap() |
278 | | /// .and_hms_nano_opt(02, 04, 59, 918355733) |
279 | | /// .unwrap() |
280 | | /// .and_utc(), |
281 | | /// ); |
282 | | /// let my_s = S { time: time.clone() }; |
283 | | /// |
284 | | /// let as_string = serde_json::to_string(&my_s)?; |
285 | | /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); |
286 | | /// let my_s: S = serde_json::from_str(&as_string)?; |
287 | | /// assert_eq!(my_s.time, time); |
288 | | /// # Ok::<(), serde_json::Error>(()) |
289 | | /// ``` |
290 | | pub mod ts_nanoseconds_option { |
291 | | use core::fmt; |
292 | | use serde::{de, ser}; |
293 | | |
294 | | use crate::{DateTime, Utc}; |
295 | | |
296 | | use super::NanoSecondsTimestampVisitor; |
297 | | |
298 | | /// Serialize a UTC datetime into an integer number of nanoseconds since the epoch or none |
299 | | /// |
300 | | /// Intended for use with `serde`s `serialize_with` attribute. |
301 | | /// |
302 | | /// # Errors |
303 | | /// |
304 | | /// An `i64` with nanosecond precision can span a range of ~584 years. This function returns an |
305 | | /// error on an out of range `DateTime`. |
306 | | /// |
307 | | /// The dates that can be represented as nanoseconds are between 1677-09-21T00:12:44.0 and |
308 | | /// 2262-04-11T23:47:16.854775804. |
309 | | /// |
310 | | /// # Example: |
311 | | /// |
312 | | /// ```rust |
313 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
314 | | /// # use serde_derive::Serialize; |
315 | | /// use chrono::serde::ts_nanoseconds_option::serialize as to_nano_tsopt; |
316 | | /// #[derive(Serialize)] |
317 | | /// struct S { |
318 | | /// #[serde(serialize_with = "to_nano_tsopt")] |
319 | | /// time: Option<DateTime<Utc>>, |
320 | | /// } |
321 | | /// |
322 | | /// let my_s = S { |
323 | | /// time: Some( |
324 | | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
325 | | /// .unwrap() |
326 | | /// .and_hms_nano_opt(02, 04, 59, 918355733) |
327 | | /// .unwrap() |
328 | | /// .and_utc(), |
329 | | /// ), |
330 | | /// }; |
331 | | /// let as_string = serde_json::to_string(&my_s)?; |
332 | | /// assert_eq!(as_string, r#"{"time":1526522699918355733}"#); |
333 | | /// # Ok::<(), serde_json::Error>(()) |
334 | | /// ``` |
335 | 0 | pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> |
336 | 0 | where |
337 | 0 | S: ser::Serializer, |
338 | | { |
339 | 0 | match *opt { |
340 | 0 | Some(ref dt) => serializer.serialize_some(&dt.timestamp_nanos_opt().ok_or( |
341 | 0 | ser::Error::custom("value out of range for a timestamp with nanosecond precision"), |
342 | 0 | )?), |
343 | 0 | None => serializer.serialize_none(), |
344 | | } |
345 | 0 | } |
346 | | |
347 | | /// Deserialize a `DateTime` from a nanosecond timestamp or none |
348 | | /// |
349 | | /// Intended for use with `serde`s `deserialize_with` attribute. |
350 | | /// |
351 | | /// # Example: |
352 | | /// |
353 | | /// ```rust |
354 | | /// # use chrono::{DateTime, TimeZone, Utc}; |
355 | | /// # use serde_derive::Deserialize; |
356 | | /// use chrono::serde::ts_nanoseconds_option::deserialize as from_nano_tsopt; |
357 | | /// #[derive(Debug, PartialEq, Deserialize)] |
358 | | /// struct S { |
359 | | /// #[serde(deserialize_with = "from_nano_tsopt")] |
360 | | /// time: Option<DateTime<Utc>>, |
361 | | /// } |
362 | | /// |
363 | | /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355733 }"#)?; |
364 | | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355733).single() }); |
365 | | /// # Ok::<(), serde_json::Error>(()) |
366 | | /// ``` |
367 | 0 | pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> |
368 | 0 | where |
369 | 0 | D: de::Deserializer<'de>, |
370 | | { |
371 | 0 | d.deserialize_option(OptionNanoSecondsTimestampVisitor) |
372 | 0 | } |
373 | | |
374 | | struct OptionNanoSecondsTimestampVisitor; |
375 | | |
376 | | impl<'de> de::Visitor<'de> for OptionNanoSecondsTimestampVisitor { |
377 | | type Value = Option<DateTime<Utc>>; |
378 | | |
379 | 0 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
380 | 0 | formatter.write_str("a unix timestamp in nanoseconds or none") |
381 | 0 | } |
382 | | |
383 | | /// Deserialize a timestamp in nanoseconds since the epoch |
384 | 0 | fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error> |
385 | 0 | where |
386 | 0 | D: de::Deserializer<'de>, |
387 | | { |
388 | 0 | d.deserialize_i64(NanoSecondsTimestampVisitor).map(Some) |
389 | 0 | } |
390 | | |
391 | | /// Deserialize a timestamp in nanoseconds since the epoch |
392 | 0 | fn visit_none<E>(self) -> Result<Self::Value, E> |
393 | 0 | where |
394 | 0 | E: de::Error, |
395 | | { |
396 | 0 | Ok(None) |
397 | 0 | } |
398 | | |
399 | | /// Deserialize a timestamp in nanoseconds since the epoch |
400 | 0 | fn visit_unit<E>(self) -> Result<Self::Value, E> |
401 | 0 | where |
402 | 0 | E: de::Error, |
403 | | { |
404 | 0 | Ok(None) |
405 | 0 | } |
406 | | } |
407 | | } |
408 | | |
409 | | /// Ser/de to/from timestamps in microseconds |
410 | | /// |
411 | | /// Intended for use with `serde`'s `with` attribute. |
412 | | /// |
413 | | /// # Example: |
414 | | /// |
415 | | /// ```rust |
416 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
417 | | /// # use serde_derive::{Deserialize, Serialize}; |
418 | | /// use chrono::serde::ts_microseconds; |
419 | | /// #[derive(Deserialize, Serialize)] |
420 | | /// struct S { |
421 | | /// #[serde(with = "ts_microseconds")] |
422 | | /// time: DateTime<Utc>, |
423 | | /// } |
424 | | /// |
425 | | /// let time = NaiveDate::from_ymd_opt(2018, 5, 17) |
426 | | /// .unwrap() |
427 | | /// .and_hms_micro_opt(02, 04, 59, 918355) |
428 | | /// .unwrap() |
429 | | /// .and_utc(); |
430 | | /// let my_s = S { time: time.clone() }; |
431 | | /// |
432 | | /// let as_string = serde_json::to_string(&my_s)?; |
433 | | /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); |
434 | | /// let my_s: S = serde_json::from_str(&as_string)?; |
435 | | /// assert_eq!(my_s.time, time); |
436 | | /// # Ok::<(), serde_json::Error>(()) |
437 | | /// ``` |
438 | | pub mod ts_microseconds { |
439 | | use core::fmt; |
440 | | use serde::{de, ser}; |
441 | | |
442 | | use crate::serde::invalid_ts; |
443 | | use crate::{DateTime, Utc}; |
444 | | |
445 | | use super::MicroSecondsTimestampVisitor; |
446 | | |
447 | | /// Serialize a UTC datetime into an integer number of microseconds since the epoch |
448 | | /// |
449 | | /// Intended for use with `serde`s `serialize_with` attribute. |
450 | | /// |
451 | | /// # Example: |
452 | | /// |
453 | | /// ```rust |
454 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
455 | | /// # use serde_derive::Serialize; |
456 | | /// use chrono::serde::ts_microseconds::serialize as to_micro_ts; |
457 | | /// #[derive(Serialize)] |
458 | | /// struct S { |
459 | | /// #[serde(serialize_with = "to_micro_ts")] |
460 | | /// time: DateTime<Utc>, |
461 | | /// } |
462 | | /// |
463 | | /// let my_s = S { |
464 | | /// time: NaiveDate::from_ymd_opt(2018, 5, 17) |
465 | | /// .unwrap() |
466 | | /// .and_hms_micro_opt(02, 04, 59, 918355) |
467 | | /// .unwrap() |
468 | | /// .and_utc(), |
469 | | /// }; |
470 | | /// let as_string = serde_json::to_string(&my_s)?; |
471 | | /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); |
472 | | /// # Ok::<(), serde_json::Error>(()) |
473 | | /// ``` |
474 | 0 | pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> |
475 | 0 | where |
476 | 0 | S: ser::Serializer, |
477 | | { |
478 | 0 | serializer.serialize_i64(dt.timestamp_micros()) |
479 | 0 | } |
480 | | |
481 | | /// Deserialize a `DateTime` from a microsecond timestamp |
482 | | /// |
483 | | /// Intended for use with `serde`s `deserialize_with` attribute. |
484 | | /// |
485 | | /// # Example: |
486 | | /// |
487 | | /// ```rust |
488 | | /// # use chrono::{DateTime, TimeZone, Utc}; |
489 | | /// # use serde_derive::Deserialize; |
490 | | /// use chrono::serde::ts_microseconds::deserialize as from_micro_ts; |
491 | | /// #[derive(Debug, PartialEq, Deserialize)] |
492 | | /// struct S { |
493 | | /// #[serde(deserialize_with = "from_micro_ts")] |
494 | | /// time: DateTime<Utc>, |
495 | | /// } |
496 | | /// |
497 | | /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; |
498 | | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355000).unwrap() }); |
499 | | /// |
500 | | /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?; |
501 | | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(-1, 999_999_000).unwrap() }); |
502 | | /// # Ok::<(), serde_json::Error>(()) |
503 | | /// ``` |
504 | 0 | pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> |
505 | 0 | where |
506 | 0 | D: de::Deserializer<'de>, |
507 | | { |
508 | 0 | d.deserialize_i64(MicroSecondsTimestampVisitor) |
509 | 0 | } |
510 | | |
511 | | impl de::Visitor<'_> for MicroSecondsTimestampVisitor { |
512 | | type Value = DateTime<Utc>; |
513 | | |
514 | 0 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
515 | 0 | formatter.write_str("a unix timestamp in microseconds") |
516 | 0 | } |
517 | | |
518 | | /// Deserialize a timestamp in milliseconds since the epoch |
519 | 0 | fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> |
520 | 0 | where |
521 | 0 | E: de::Error, |
522 | | { |
523 | 0 | DateTime::from_timestamp_micros(value).ok_or_else(|| invalid_ts(value)) |
524 | 0 | } |
525 | | |
526 | | /// Deserialize a timestamp in milliseconds since the epoch |
527 | 0 | fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> |
528 | 0 | where |
529 | 0 | E: de::Error, |
530 | | { |
531 | 0 | DateTime::from_timestamp( |
532 | 0 | (value / 1_000_000) as i64, |
533 | 0 | ((value % 1_000_000) * 1_000) as u32, |
534 | | ) |
535 | 0 | .ok_or_else(|| invalid_ts(value)) |
536 | 0 | } |
537 | | } |
538 | | } |
539 | | |
540 | | /// Ser/de to/from optional timestamps in microseconds |
541 | | /// |
542 | | /// Intended for use with `serde`'s `with` attribute. |
543 | | /// |
544 | | /// # Example: |
545 | | /// |
546 | | /// ```rust |
547 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
548 | | /// # use serde_derive::{Deserialize, Serialize}; |
549 | | /// use chrono::serde::ts_microseconds_option; |
550 | | /// #[derive(Deserialize, Serialize)] |
551 | | /// struct S { |
552 | | /// #[serde(with = "ts_microseconds_option")] |
553 | | /// time: Option<DateTime<Utc>>, |
554 | | /// } |
555 | | /// |
556 | | /// let time = Some( |
557 | | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
558 | | /// .unwrap() |
559 | | /// .and_hms_micro_opt(02, 04, 59, 918355) |
560 | | /// .unwrap() |
561 | | /// .and_utc(), |
562 | | /// ); |
563 | | /// let my_s = S { time: time.clone() }; |
564 | | /// |
565 | | /// let as_string = serde_json::to_string(&my_s)?; |
566 | | /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); |
567 | | /// let my_s: S = serde_json::from_str(&as_string)?; |
568 | | /// assert_eq!(my_s.time, time); |
569 | | /// # Ok::<(), serde_json::Error>(()) |
570 | | /// ``` |
571 | | pub mod ts_microseconds_option { |
572 | | use core::fmt; |
573 | | use serde::{de, ser}; |
574 | | |
575 | | use super::MicroSecondsTimestampVisitor; |
576 | | use crate::{DateTime, Utc}; |
577 | | |
578 | | /// Serialize a UTC datetime into an integer number of microseconds since the epoch or none |
579 | | /// |
580 | | /// Intended for use with `serde`s `serialize_with` attribute. |
581 | | /// |
582 | | /// # Example: |
583 | | /// |
584 | | /// ```rust |
585 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
586 | | /// # use serde_derive::Serialize; |
587 | | /// use chrono::serde::ts_microseconds_option::serialize as to_micro_tsopt; |
588 | | /// #[derive(Serialize)] |
589 | | /// struct S { |
590 | | /// #[serde(serialize_with = "to_micro_tsopt")] |
591 | | /// time: Option<DateTime<Utc>>, |
592 | | /// } |
593 | | /// |
594 | | /// let my_s = S { |
595 | | /// time: Some( |
596 | | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
597 | | /// .unwrap() |
598 | | /// .and_hms_micro_opt(02, 04, 59, 918355) |
599 | | /// .unwrap() |
600 | | /// .and_utc(), |
601 | | /// ), |
602 | | /// }; |
603 | | /// let as_string = serde_json::to_string(&my_s)?; |
604 | | /// assert_eq!(as_string, r#"{"time":1526522699918355}"#); |
605 | | /// # Ok::<(), serde_json::Error>(()) |
606 | | /// ``` |
607 | 0 | pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> |
608 | 0 | where |
609 | 0 | S: ser::Serializer, |
610 | | { |
611 | 0 | match *opt { |
612 | 0 | Some(ref dt) => serializer.serialize_some(&dt.timestamp_micros()), |
613 | 0 | None => serializer.serialize_none(), |
614 | | } |
615 | 0 | } |
616 | | |
617 | | /// Deserialize a `DateTime` from a microsecond timestamp or none |
618 | | /// |
619 | | /// Intended for use with `serde`s `deserialize_with` attribute. |
620 | | /// |
621 | | /// # Example: |
622 | | /// |
623 | | /// ```rust |
624 | | /// # use chrono::{DateTime, TimeZone, Utc}; |
625 | | /// # use serde_derive::Deserialize; |
626 | | /// use chrono::serde::ts_microseconds_option::deserialize as from_micro_tsopt; |
627 | | /// #[derive(Debug, PartialEq, Deserialize)] |
628 | | /// struct S { |
629 | | /// #[serde(deserialize_with = "from_micro_tsopt")] |
630 | | /// time: Option<DateTime<Utc>>, |
631 | | /// } |
632 | | /// |
633 | | /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918355 }"#)?; |
634 | | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918355000).single() }); |
635 | | /// # Ok::<(), serde_json::Error>(()) |
636 | | /// ``` |
637 | 0 | pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> |
638 | 0 | where |
639 | 0 | D: de::Deserializer<'de>, |
640 | | { |
641 | 0 | d.deserialize_option(OptionMicroSecondsTimestampVisitor) |
642 | 0 | } |
643 | | |
644 | | struct OptionMicroSecondsTimestampVisitor; |
645 | | |
646 | | impl<'de> de::Visitor<'de> for OptionMicroSecondsTimestampVisitor { |
647 | | type Value = Option<DateTime<Utc>>; |
648 | | |
649 | 0 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
650 | 0 | formatter.write_str("a unix timestamp in microseconds or none") |
651 | 0 | } |
652 | | |
653 | | /// Deserialize a timestamp in microseconds since the epoch |
654 | 0 | fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error> |
655 | 0 | where |
656 | 0 | D: de::Deserializer<'de>, |
657 | | { |
658 | 0 | d.deserialize_i64(MicroSecondsTimestampVisitor).map(Some) |
659 | 0 | } |
660 | | |
661 | | /// Deserialize a timestamp in microseconds since the epoch |
662 | 0 | fn visit_none<E>(self) -> Result<Self::Value, E> |
663 | 0 | where |
664 | 0 | E: de::Error, |
665 | | { |
666 | 0 | Ok(None) |
667 | 0 | } |
668 | | |
669 | | /// Deserialize a timestamp in microseconds since the epoch |
670 | 0 | fn visit_unit<E>(self) -> Result<Self::Value, E> |
671 | 0 | where |
672 | 0 | E: de::Error, |
673 | | { |
674 | 0 | Ok(None) |
675 | 0 | } |
676 | | } |
677 | | } |
678 | | |
679 | | /// Ser/de to/from timestamps in milliseconds |
680 | | /// |
681 | | /// Intended for use with `serde`s `with` attribute. |
682 | | /// |
683 | | /// # Example |
684 | | /// |
685 | | /// ```rust |
686 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
687 | | /// # use serde_derive::{Deserialize, Serialize}; |
688 | | /// use chrono::serde::ts_milliseconds; |
689 | | /// #[derive(Deserialize, Serialize)] |
690 | | /// struct S { |
691 | | /// #[serde(with = "ts_milliseconds")] |
692 | | /// time: DateTime<Utc>, |
693 | | /// } |
694 | | /// |
695 | | /// let time = NaiveDate::from_ymd_opt(2018, 5, 17) |
696 | | /// .unwrap() |
697 | | /// .and_hms_milli_opt(02, 04, 59, 918) |
698 | | /// .unwrap() |
699 | | /// .and_utc(); |
700 | | /// let my_s = S { time: time.clone() }; |
701 | | /// |
702 | | /// let as_string = serde_json::to_string(&my_s)?; |
703 | | /// assert_eq!(as_string, r#"{"time":1526522699918}"#); |
704 | | /// let my_s: S = serde_json::from_str(&as_string)?; |
705 | | /// assert_eq!(my_s.time, time); |
706 | | /// # Ok::<(), serde_json::Error>(()) |
707 | | /// ``` |
708 | | pub mod ts_milliseconds { |
709 | | use core::fmt; |
710 | | use serde::{de, ser}; |
711 | | |
712 | | use crate::serde::invalid_ts; |
713 | | use crate::{DateTime, Utc}; |
714 | | |
715 | | use super::MilliSecondsTimestampVisitor; |
716 | | |
717 | | /// Serialize a UTC datetime into an integer number of milliseconds since the epoch |
718 | | /// |
719 | | /// Intended for use with `serde`s `serialize_with` attribute. |
720 | | /// |
721 | | /// # Example: |
722 | | /// |
723 | | /// ```rust |
724 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
725 | | /// # use serde_derive::Serialize; |
726 | | /// use chrono::serde::ts_milliseconds::serialize as to_milli_ts; |
727 | | /// #[derive(Serialize)] |
728 | | /// struct S { |
729 | | /// #[serde(serialize_with = "to_milli_ts")] |
730 | | /// time: DateTime<Utc>, |
731 | | /// } |
732 | | /// |
733 | | /// let my_s = S { |
734 | | /// time: NaiveDate::from_ymd_opt(2018, 5, 17) |
735 | | /// .unwrap() |
736 | | /// .and_hms_milli_opt(02, 04, 59, 918) |
737 | | /// .unwrap() |
738 | | /// .and_utc(), |
739 | | /// }; |
740 | | /// let as_string = serde_json::to_string(&my_s)?; |
741 | | /// assert_eq!(as_string, r#"{"time":1526522699918}"#); |
742 | | /// # Ok::<(), serde_json::Error>(()) |
743 | | /// ``` |
744 | 0 | pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> |
745 | 0 | where |
746 | 0 | S: ser::Serializer, |
747 | | { |
748 | 0 | serializer.serialize_i64(dt.timestamp_millis()) |
749 | 0 | } |
750 | | |
751 | | /// Deserialize a `DateTime` from a millisecond timestamp |
752 | | /// |
753 | | /// Intended for use with `serde`s `deserialize_with` attribute. |
754 | | /// |
755 | | /// # Example: |
756 | | /// |
757 | | /// ```rust |
758 | | /// # use chrono::{DateTime, TimeZone, Utc}; |
759 | | /// # use serde_derive::Deserialize; |
760 | | /// use chrono::serde::ts_milliseconds::deserialize as from_milli_ts; |
761 | | /// #[derive(Debug, PartialEq, Deserialize)] |
762 | | /// struct S { |
763 | | /// #[serde(deserialize_with = "from_milli_ts")] |
764 | | /// time: DateTime<Utc>, |
765 | | /// } |
766 | | /// |
767 | | /// let my_s: S = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; |
768 | | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1526522699, 918000000).unwrap() }); |
769 | | /// |
770 | | /// let my_s: S = serde_json::from_str(r#"{ "time": -1 }"#)?; |
771 | | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(-1, 999_000_000).unwrap() }); |
772 | | /// # Ok::<(), serde_json::Error>(()) |
773 | | /// ``` |
774 | 0 | pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> |
775 | 0 | where |
776 | 0 | D: de::Deserializer<'de>, |
777 | | { |
778 | 0 | d.deserialize_i64(MilliSecondsTimestampVisitor).map(|dt| dt.with_timezone(&Utc)) |
779 | 0 | } |
780 | | |
781 | | impl de::Visitor<'_> for MilliSecondsTimestampVisitor { |
782 | | type Value = DateTime<Utc>; |
783 | | |
784 | 0 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
785 | 0 | formatter.write_str("a unix timestamp in milliseconds") |
786 | 0 | } |
787 | | |
788 | | /// Deserialize a timestamp in milliseconds since the epoch |
789 | 0 | fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> |
790 | 0 | where |
791 | 0 | E: de::Error, |
792 | | { |
793 | 0 | DateTime::from_timestamp_millis(value).ok_or_else(|| invalid_ts(value)) |
794 | 0 | } |
795 | | |
796 | | /// Deserialize a timestamp in milliseconds since the epoch |
797 | 0 | fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> |
798 | 0 | where |
799 | 0 | E: de::Error, |
800 | | { |
801 | 0 | DateTime::from_timestamp((value / 1000) as i64, ((value % 1000) * 1_000_000) as u32) |
802 | 0 | .ok_or_else(|| invalid_ts(value)) |
803 | 0 | } |
804 | | } |
805 | | } |
806 | | |
807 | | /// Ser/de to/from optional timestamps in milliseconds |
808 | | /// |
809 | | /// Intended for use with `serde`s `with` attribute. |
810 | | /// |
811 | | /// # Example |
812 | | /// |
813 | | /// ```rust |
814 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
815 | | /// # use serde_derive::{Deserialize, Serialize}; |
816 | | /// use chrono::serde::ts_milliseconds_option; |
817 | | /// #[derive(Deserialize, Serialize)] |
818 | | /// struct S { |
819 | | /// #[serde(with = "ts_milliseconds_option")] |
820 | | /// time: Option<DateTime<Utc>>, |
821 | | /// } |
822 | | /// |
823 | | /// let time = Some( |
824 | | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
825 | | /// .unwrap() |
826 | | /// .and_hms_milli_opt(02, 04, 59, 918) |
827 | | /// .unwrap() |
828 | | /// .and_utc(), |
829 | | /// ); |
830 | | /// let my_s = S { time: time.clone() }; |
831 | | /// |
832 | | /// let as_string = serde_json::to_string(&my_s)?; |
833 | | /// assert_eq!(as_string, r#"{"time":1526522699918}"#); |
834 | | /// let my_s: S = serde_json::from_str(&as_string)?; |
835 | | /// assert_eq!(my_s.time, time); |
836 | | /// # Ok::<(), serde_json::Error>(()) |
837 | | /// ``` |
838 | | pub mod ts_milliseconds_option { |
839 | | use core::fmt; |
840 | | use serde::{de, ser}; |
841 | | |
842 | | use super::MilliSecondsTimestampVisitor; |
843 | | use crate::{DateTime, Utc}; |
844 | | |
845 | | /// Serialize a UTC datetime into an integer number of milliseconds since the epoch or none |
846 | | /// |
847 | | /// Intended for use with `serde`s `serialize_with` attribute. |
848 | | /// |
849 | | /// # Example: |
850 | | /// |
851 | | /// ```rust |
852 | | /// # use chrono::{DateTime, Utc, NaiveDate}; |
853 | | /// # use serde_derive::Serialize; |
854 | | /// use chrono::serde::ts_milliseconds_option::serialize as to_milli_tsopt; |
855 | | /// #[derive(Serialize)] |
856 | | /// struct S { |
857 | | /// #[serde(serialize_with = "to_milli_tsopt")] |
858 | | /// time: Option<DateTime<Utc>>, |
859 | | /// } |
860 | | /// |
861 | | /// let my_s = S { |
862 | | /// time: Some( |
863 | | /// NaiveDate::from_ymd_opt(2018, 5, 17) |
864 | | /// .unwrap() |
865 | | /// .and_hms_milli_opt(02, 04, 59, 918) |
866 | | /// .unwrap() |
867 | | /// .and_utc(), |
868 | | /// ), |
869 | | /// }; |
870 | | /// let as_string = serde_json::to_string(&my_s)?; |
871 | | /// assert_eq!(as_string, r#"{"time":1526522699918}"#); |
872 | | /// # Ok::<(), serde_json::Error>(()) |
873 | | /// ``` |
874 | 0 | pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> |
875 | 0 | where |
876 | 0 | S: ser::Serializer, |
877 | | { |
878 | 0 | match *opt { |
879 | 0 | Some(ref dt) => serializer.serialize_some(&dt.timestamp_millis()), |
880 | 0 | None => serializer.serialize_none(), |
881 | | } |
882 | 0 | } |
883 | | |
884 | | /// Deserialize a `DateTime` from a millisecond timestamp or none |
885 | | /// |
886 | | /// Intended for use with `serde`s `deserialize_with` attribute. |
887 | | /// |
888 | | /// # Example: |
889 | | /// |
890 | | /// ```rust |
891 | | /// # use chrono::{TimeZone, DateTime, Utc}; |
892 | | /// # use serde_derive::Deserialize; |
893 | | /// use chrono::serde::ts_milliseconds_option::deserialize as from_milli_tsopt; |
894 | | /// |
895 | | /// #[derive(Deserialize, PartialEq, Debug)] |
896 | | /// #[serde(untagged)] |
897 | | /// enum E<T> { |
898 | | /// V(T), |
899 | | /// } |
900 | | /// |
901 | | /// #[derive(Deserialize, PartialEq, Debug)] |
902 | | /// struct S { |
903 | | /// #[serde(default, deserialize_with = "from_milli_tsopt")] |
904 | | /// time: Option<DateTime<Utc>>, |
905 | | /// } |
906 | | /// |
907 | | /// let my_s: E<S> = serde_json::from_str(r#"{ "time": 1526522699918 }"#)?; |
908 | | /// assert_eq!(my_s, E::V(S { time: Some(Utc.timestamp_opt(1526522699, 918000000).unwrap()) })); |
909 | | /// let s: E<S> = serde_json::from_str(r#"{ "time": null }"#)?; |
910 | | /// assert_eq!(s, E::V(S { time: None })); |
911 | | /// let t: E<S> = serde_json::from_str(r#"{}"#)?; |
912 | | /// assert_eq!(t, E::V(S { time: None })); |
913 | | /// # Ok::<(), serde_json::Error>(()) |
914 | | /// ``` |
915 | 0 | pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> |
916 | 0 | where |
917 | 0 | D: de::Deserializer<'de>, |
918 | | { |
919 | 0 | d.deserialize_option(OptionMilliSecondsTimestampVisitor) |
920 | 0 | .map(|opt| opt.map(|dt| dt.with_timezone(&Utc))) |
921 | 0 | } |
922 | | |
923 | | struct OptionMilliSecondsTimestampVisitor; |
924 | | |
925 | | impl<'de> de::Visitor<'de> for OptionMilliSecondsTimestampVisitor { |
926 | | type Value = Option<DateTime<Utc>>; |
927 | | |
928 | 0 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
929 | 0 | formatter.write_str("a unix timestamp in milliseconds or none") |
930 | 0 | } |
931 | | |
932 | | /// Deserialize a timestamp in milliseconds since the epoch |
933 | 0 | fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error> |
934 | 0 | where |
935 | 0 | D: de::Deserializer<'de>, |
936 | | { |
937 | 0 | d.deserialize_i64(MilliSecondsTimestampVisitor).map(Some) |
938 | 0 | } |
939 | | |
940 | | /// Deserialize a timestamp in milliseconds since the epoch |
941 | 0 | fn visit_none<E>(self) -> Result<Self::Value, E> |
942 | 0 | where |
943 | 0 | E: de::Error, |
944 | | { |
945 | 0 | Ok(None) |
946 | 0 | } |
947 | | |
948 | | /// Deserialize a timestamp in milliseconds since the epoch |
949 | 0 | fn visit_unit<E>(self) -> Result<Self::Value, E> |
950 | 0 | where |
951 | 0 | E: de::Error, |
952 | | { |
953 | 0 | Ok(None) |
954 | 0 | } |
955 | | } |
956 | | } |
957 | | |
958 | | /// Ser/de to/from timestamps in seconds |
959 | | /// |
960 | | /// Intended for use with `serde`'s `with` attribute. |
961 | | /// |
962 | | /// # Example: |
963 | | /// |
964 | | /// ```rust |
965 | | /// # use chrono::{TimeZone, DateTime, Utc}; |
966 | | /// # use serde_derive::{Deserialize, Serialize}; |
967 | | /// use chrono::serde::ts_seconds; |
968 | | /// #[derive(Deserialize, Serialize)] |
969 | | /// struct S { |
970 | | /// #[serde(with = "ts_seconds")] |
971 | | /// time: DateTime<Utc>, |
972 | | /// } |
973 | | /// |
974 | | /// let time = Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap(); |
975 | | /// let my_s = S { time: time.clone() }; |
976 | | /// |
977 | | /// let as_string = serde_json::to_string(&my_s)?; |
978 | | /// assert_eq!(as_string, r#"{"time":1431684000}"#); |
979 | | /// let my_s: S = serde_json::from_str(&as_string)?; |
980 | | /// assert_eq!(my_s.time, time); |
981 | | /// # Ok::<(), serde_json::Error>(()) |
982 | | /// ``` |
983 | | pub mod ts_seconds { |
984 | | use core::fmt; |
985 | | use serde::{de, ser}; |
986 | | |
987 | | use crate::serde::invalid_ts; |
988 | | use crate::{DateTime, Utc}; |
989 | | |
990 | | use super::SecondsTimestampVisitor; |
991 | | |
992 | | /// Serialize a UTC datetime into an integer number of seconds since the epoch |
993 | | /// |
994 | | /// Intended for use with `serde`s `serialize_with` attribute. |
995 | | /// |
996 | | /// # Example: |
997 | | /// |
998 | | /// ```rust |
999 | | /// # use chrono::{TimeZone, DateTime, Utc}; |
1000 | | /// # use serde_derive::Serialize; |
1001 | | /// use chrono::serde::ts_seconds::serialize as to_ts; |
1002 | | /// #[derive(Serialize)] |
1003 | | /// struct S { |
1004 | | /// #[serde(serialize_with = "to_ts")] |
1005 | | /// time: DateTime<Utc>, |
1006 | | /// } |
1007 | | /// |
1008 | | /// let my_s = S { time: Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap() }; |
1009 | | /// let as_string = serde_json::to_string(&my_s)?; |
1010 | | /// assert_eq!(as_string, r#"{"time":1431684000}"#); |
1011 | | /// # Ok::<(), serde_json::Error>(()) |
1012 | | /// ``` |
1013 | 0 | pub fn serialize<S>(dt: &DateTime<Utc>, serializer: S) -> Result<S::Ok, S::Error> |
1014 | 0 | where |
1015 | 0 | S: ser::Serializer, |
1016 | | { |
1017 | 0 | serializer.serialize_i64(dt.timestamp()) |
1018 | 0 | } |
1019 | | |
1020 | | /// Deserialize a `DateTime` from a seconds timestamp |
1021 | | /// |
1022 | | /// Intended for use with `serde`s `deserialize_with` attribute. |
1023 | | /// |
1024 | | /// # Example: |
1025 | | /// |
1026 | | /// ```rust |
1027 | | /// # use chrono::{DateTime, TimeZone, Utc}; |
1028 | | /// # use serde_derive::Deserialize; |
1029 | | /// use chrono::serde::ts_seconds::deserialize as from_ts; |
1030 | | /// #[derive(Debug, PartialEq, Deserialize)] |
1031 | | /// struct S { |
1032 | | /// #[serde(deserialize_with = "from_ts")] |
1033 | | /// time: DateTime<Utc>, |
1034 | | /// } |
1035 | | /// |
1036 | | /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; |
1037 | | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).unwrap() }); |
1038 | | /// # Ok::<(), serde_json::Error>(()) |
1039 | | /// ``` |
1040 | 0 | pub fn deserialize<'de, D>(d: D) -> Result<DateTime<Utc>, D::Error> |
1041 | 0 | where |
1042 | 0 | D: de::Deserializer<'de>, |
1043 | | { |
1044 | 0 | d.deserialize_i64(SecondsTimestampVisitor) |
1045 | 0 | } |
1046 | | |
1047 | | impl de::Visitor<'_> for SecondsTimestampVisitor { |
1048 | | type Value = DateTime<Utc>; |
1049 | | |
1050 | 0 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
1051 | 0 | formatter.write_str("a unix timestamp in seconds") |
1052 | 0 | } |
1053 | | |
1054 | | /// Deserialize a timestamp in seconds since the epoch |
1055 | 0 | fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E> |
1056 | 0 | where |
1057 | 0 | E: de::Error, |
1058 | | { |
1059 | 0 | DateTime::from_timestamp_secs(value).ok_or_else(|| invalid_ts(value)) |
1060 | 0 | } |
1061 | | |
1062 | | /// Deserialize a timestamp in seconds since the epoch |
1063 | 0 | fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> |
1064 | 0 | where |
1065 | 0 | E: de::Error, |
1066 | | { |
1067 | 0 | if value > i64::MAX as u64 { |
1068 | 0 | Err(invalid_ts(value)) |
1069 | | } else { |
1070 | 0 | DateTime::from_timestamp_secs(value as i64).ok_or_else(|| invalid_ts(value)) |
1071 | | } |
1072 | 0 | } |
1073 | | } |
1074 | | } |
1075 | | |
1076 | | /// Ser/de to/from optional timestamps in seconds |
1077 | | /// |
1078 | | /// Intended for use with `serde`'s `with` attribute. |
1079 | | /// |
1080 | | /// # Example: |
1081 | | /// |
1082 | | /// ```rust |
1083 | | /// # use chrono::{TimeZone, DateTime, Utc}; |
1084 | | /// # use serde_derive::{Deserialize, Serialize}; |
1085 | | /// use chrono::serde::ts_seconds_option; |
1086 | | /// #[derive(Deserialize, Serialize)] |
1087 | | /// struct S { |
1088 | | /// #[serde(with = "ts_seconds_option")] |
1089 | | /// time: Option<DateTime<Utc>>, |
1090 | | /// } |
1091 | | /// |
1092 | | /// let time = Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()); |
1093 | | /// let my_s = S { time: time.clone() }; |
1094 | | /// |
1095 | | /// let as_string = serde_json::to_string(&my_s)?; |
1096 | | /// assert_eq!(as_string, r#"{"time":1431684000}"#); |
1097 | | /// let my_s: S = serde_json::from_str(&as_string)?; |
1098 | | /// assert_eq!(my_s.time, time); |
1099 | | /// # Ok::<(), serde_json::Error>(()) |
1100 | | /// ``` |
1101 | | pub mod ts_seconds_option { |
1102 | | use core::fmt; |
1103 | | use serde::{de, ser}; |
1104 | | |
1105 | | use super::SecondsTimestampVisitor; |
1106 | | use crate::{DateTime, Utc}; |
1107 | | |
1108 | | /// Serialize a UTC datetime into an integer number of seconds since the epoch or none |
1109 | | /// |
1110 | | /// Intended for use with `serde`s `serialize_with` attribute. |
1111 | | /// |
1112 | | /// # Example: |
1113 | | /// |
1114 | | /// ```rust |
1115 | | /// # use chrono::{TimeZone, DateTime, Utc}; |
1116 | | /// # use serde_derive::Serialize; |
1117 | | /// use chrono::serde::ts_seconds_option::serialize as to_tsopt; |
1118 | | /// #[derive(Serialize)] |
1119 | | /// struct S { |
1120 | | /// #[serde(serialize_with = "to_tsopt")] |
1121 | | /// time: Option<DateTime<Utc>>, |
1122 | | /// } |
1123 | | /// |
1124 | | /// let my_s = S { time: Some(Utc.with_ymd_and_hms(2015, 5, 15, 10, 0, 0).unwrap()) }; |
1125 | | /// let as_string = serde_json::to_string(&my_s)?; |
1126 | | /// assert_eq!(as_string, r#"{"time":1431684000}"#); |
1127 | | /// # Ok::<(), serde_json::Error>(()) |
1128 | | /// ``` |
1129 | 0 | pub fn serialize<S>(opt: &Option<DateTime<Utc>>, serializer: S) -> Result<S::Ok, S::Error> |
1130 | 0 | where |
1131 | 0 | S: ser::Serializer, |
1132 | | { |
1133 | 0 | match *opt { |
1134 | 0 | Some(ref dt) => serializer.serialize_some(&dt.timestamp()), |
1135 | 0 | None => serializer.serialize_none(), |
1136 | | } |
1137 | 0 | } |
1138 | | |
1139 | | /// Deserialize a `DateTime` from a seconds timestamp or none |
1140 | | /// |
1141 | | /// Intended for use with `serde`s `deserialize_with` attribute. |
1142 | | /// |
1143 | | /// # Example: |
1144 | | /// |
1145 | | /// ```rust |
1146 | | /// # use chrono::{DateTime, TimeZone, Utc}; |
1147 | | /// # use serde_derive::Deserialize; |
1148 | | /// use chrono::serde::ts_seconds_option::deserialize as from_tsopt; |
1149 | | /// #[derive(Debug, PartialEq, Deserialize)] |
1150 | | /// struct S { |
1151 | | /// #[serde(deserialize_with = "from_tsopt")] |
1152 | | /// time: Option<DateTime<Utc>>, |
1153 | | /// } |
1154 | | /// |
1155 | | /// let my_s: S = serde_json::from_str(r#"{ "time": 1431684000 }"#)?; |
1156 | | /// assert_eq!(my_s, S { time: Utc.timestamp_opt(1431684000, 0).single() }); |
1157 | | /// # Ok::<(), serde_json::Error>(()) |
1158 | | /// ``` |
1159 | 0 | pub fn deserialize<'de, D>(d: D) -> Result<Option<DateTime<Utc>>, D::Error> |
1160 | 0 | where |
1161 | 0 | D: de::Deserializer<'de>, |
1162 | | { |
1163 | 0 | d.deserialize_option(OptionSecondsTimestampVisitor) |
1164 | 0 | } |
1165 | | |
1166 | | struct OptionSecondsTimestampVisitor; |
1167 | | |
1168 | | impl<'de> de::Visitor<'de> for OptionSecondsTimestampVisitor { |
1169 | | type Value = Option<DateTime<Utc>>; |
1170 | | |
1171 | 0 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { |
1172 | 0 | formatter.write_str("a unix timestamp in seconds or none") |
1173 | 0 | } |
1174 | | |
1175 | | /// Deserialize a timestamp in seconds since the epoch |
1176 | 0 | fn visit_some<D>(self, d: D) -> Result<Self::Value, D::Error> |
1177 | 0 | where |
1178 | 0 | D: de::Deserializer<'de>, |
1179 | | { |
1180 | 0 | d.deserialize_i64(SecondsTimestampVisitor).map(Some) |
1181 | 0 | } |
1182 | | |
1183 | | /// Deserialize a timestamp in seconds since the epoch |
1184 | 0 | fn visit_none<E>(self) -> Result<Self::Value, E> |
1185 | 0 | where |
1186 | 0 | E: de::Error, |
1187 | | { |
1188 | 0 | Ok(None) |
1189 | 0 | } |
1190 | | |
1191 | | /// Deserialize a timestamp in seconds since the epoch |
1192 | 0 | fn visit_unit<E>(self) -> Result<Self::Value, E> |
1193 | 0 | where |
1194 | 0 | E: de::Error, |
1195 | | { |
1196 | 0 | Ok(None) |
1197 | 0 | } |
1198 | | } |
1199 | | } |
1200 | | |
1201 | | #[cfg(test)] |
1202 | | mod tests { |
1203 | | #[cfg(feature = "clock")] |
1204 | | use crate::Local; |
1205 | | use crate::{DateTime, FixedOffset, TimeZone, Utc}; |
1206 | | use core::fmt; |
1207 | | |
1208 | | #[test] |
1209 | | fn test_serde_serialize() { |
1210 | | assert_eq!( |
1211 | | serde_json::to_string(&Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()).ok(), |
1212 | | Some(r#""2014-07-24T12:34:06Z""#.to_owned()) |
1213 | | ); |
1214 | | assert_eq!( |
1215 | | serde_json::to_string( |
1216 | | &FixedOffset::east_opt(3660) |
1217 | | .unwrap() |
1218 | | .with_ymd_and_hms(2014, 7, 24, 12, 34, 6) |
1219 | | .unwrap() |
1220 | | ) |
1221 | | .ok(), |
1222 | | Some(r#""2014-07-24T12:34:06+01:01""#.to_owned()) |
1223 | | ); |
1224 | | assert_eq!( |
1225 | | serde_json::to_string( |
1226 | | &FixedOffset::east_opt(3650) |
1227 | | .unwrap() |
1228 | | .with_ymd_and_hms(2014, 7, 24, 12, 34, 6) |
1229 | | .unwrap() |
1230 | | ) |
1231 | | .ok(), |
1232 | | // An offset with seconds is not allowed by RFC 3339, so we round it to the nearest minute. |
1233 | | // In this case `+01:00:50` becomes `+01:01` |
1234 | | Some(r#""2014-07-24T12:34:06+01:01""#.to_owned()) |
1235 | | ); |
1236 | | } |
1237 | | |
1238 | | #[test] |
1239 | | fn test_serde_deserialize() { |
1240 | | // should check against the offset as well (the normal DateTime comparison will ignore them) |
1241 | | fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> { |
1242 | | dt.as_ref().map(|dt| (dt, dt.offset())) |
1243 | | } |
1244 | | |
1245 | | let dt: Option<DateTime<Utc>> = serde_json::from_str(r#""2014-07-24T12:34:06Z""#).ok(); |
1246 | | assert_eq!(norm(&dt), norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))); |
1247 | | let dt: Option<DateTime<Utc>> = serde_json::from_str(r#""2014-07-24T13:57:06+01:23""#).ok(); |
1248 | | assert_eq!(norm(&dt), norm(&Some(Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()))); |
1249 | | |
1250 | | let dt: Option<DateTime<FixedOffset>> = |
1251 | | serde_json::from_str(r#""2014-07-24T12:34:06Z""#).ok(); |
1252 | | assert_eq!( |
1253 | | norm(&dt), |
1254 | | norm(&Some( |
1255 | | FixedOffset::east_opt(0).unwrap().with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap() |
1256 | | )) |
1257 | | ); |
1258 | | let dt: Option<DateTime<FixedOffset>> = |
1259 | | serde_json::from_str(r#""2014-07-24T13:57:06+01:23""#).ok(); |
1260 | | assert_eq!( |
1261 | | norm(&dt), |
1262 | | norm(&Some( |
1263 | | FixedOffset::east_opt(60 * 60 + 23 * 60) |
1264 | | .unwrap() |
1265 | | .with_ymd_and_hms(2014, 7, 24, 13, 57, 6) |
1266 | | .unwrap() |
1267 | | )) |
1268 | | ); |
1269 | | |
1270 | | // we don't know the exact local offset but we can check that |
1271 | | // the conversion didn't change the instant itself |
1272 | | #[cfg(feature = "clock")] |
1273 | | { |
1274 | | let dt: DateTime<Local> = |
1275 | | serde_json::from_str(r#""2014-07-24T12:34:06Z""#).expect("local should parse"); |
1276 | | assert_eq!(dt, Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()); |
1277 | | |
1278 | | let dt: DateTime<Local> = serde_json::from_str(r#""2014-07-24T13:57:06+01:23""#) |
1279 | | .expect("local should parse with offset"); |
1280 | | assert_eq!(dt, Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap()); |
1281 | | } |
1282 | | |
1283 | | assert!(serde_json::from_str::<DateTime<Utc>>(r#""2014-07-32T12:34:06Z""#).is_err()); |
1284 | | assert!( |
1285 | | serde_json::from_str::<DateTime<FixedOffset>>(r#""2014-07-32T12:34:06Z""#).is_err() |
1286 | | ); |
1287 | | } |
1288 | | |
1289 | | #[test] |
1290 | | fn test_serde_bincode() { |
1291 | | // Bincode is relevant to test separately from JSON because |
1292 | | // it is not self-describing. |
1293 | | use bincode::{deserialize, serialize}; |
1294 | | |
1295 | | let dt = Utc.with_ymd_and_hms(2014, 7, 24, 12, 34, 6).unwrap(); |
1296 | | let encoded = serialize(&dt).unwrap(); |
1297 | | let decoded: DateTime<Utc> = deserialize(&encoded).unwrap(); |
1298 | | assert_eq!(dt, decoded); |
1299 | | assert_eq!(dt.offset(), decoded.offset()); |
1300 | | } |
1301 | | |
1302 | | #[test] |
1303 | | fn test_serde_no_offset_debug() { |
1304 | | use crate::{MappedLocalTime, NaiveDate, NaiveDateTime, Offset}; |
1305 | | use core::fmt::Debug; |
1306 | | |
1307 | | #[derive(Clone)] |
1308 | | struct TestTimeZone; |
1309 | | impl Debug for TestTimeZone { |
1310 | | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
1311 | | write!(f, "TEST") |
1312 | | } |
1313 | | } |
1314 | | impl TimeZone for TestTimeZone { |
1315 | | type Offset = TestTimeZone; |
1316 | | fn from_offset(_state: &TestTimeZone) -> TestTimeZone { |
1317 | | TestTimeZone |
1318 | | } |
1319 | | fn offset_from_local_date(&self, _local: &NaiveDate) -> MappedLocalTime<TestTimeZone> { |
1320 | | MappedLocalTime::Single(TestTimeZone) |
1321 | | } |
1322 | | fn offset_from_local_datetime( |
1323 | | &self, |
1324 | | _local: &NaiveDateTime, |
1325 | | ) -> MappedLocalTime<TestTimeZone> { |
1326 | | MappedLocalTime::Single(TestTimeZone) |
1327 | | } |
1328 | | fn offset_from_utc_date(&self, _utc: &NaiveDate) -> TestTimeZone { |
1329 | | TestTimeZone |
1330 | | } |
1331 | | fn offset_from_utc_datetime(&self, _utc: &NaiveDateTime) -> TestTimeZone { |
1332 | | TestTimeZone |
1333 | | } |
1334 | | } |
1335 | | impl Offset for TestTimeZone { |
1336 | | fn fix(&self) -> FixedOffset { |
1337 | | FixedOffset::east_opt(15 * 60 * 60).unwrap() |
1338 | | } |
1339 | | } |
1340 | | |
1341 | | let tz = TestTimeZone; |
1342 | | assert_eq!(format!("{:?}", &tz), "TEST"); |
1343 | | |
1344 | | let dt = tz.with_ymd_and_hms(2023, 4, 24, 21, 10, 33).unwrap(); |
1345 | | let encoded = serde_json::to_string(&dt).unwrap(); |
1346 | | dbg!(&encoded); |
1347 | | let decoded: DateTime<FixedOffset> = serde_json::from_str(&encoded).unwrap(); |
1348 | | assert_eq!(dt, decoded); |
1349 | | assert_eq!(dt.offset().fix(), *decoded.offset()); |
1350 | | } |
1351 | | } |