]> git.proxmox.com Git - proxmox.git/commitdiff
tools: make date_time_as_rfc3339 work for all TimeZones
authorWolfgang Bumiller <w.bumiller@proxmox.com>
Tue, 18 Jun 2019 10:10:45 +0000 (12:10 +0200)
committerWolfgang Bumiller <w.bumiller@proxmox.com>
Tue, 18 Jun 2019 10:11:23 +0000 (12:11 +0200)
and add a doc-test passing `cargo test`
(and formatting fixup)

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
proxmox-tools/Cargo.toml
proxmox-tools/src/serde.rs

index c9ee4a93497dd77640b4bfb0ff97784f6e056e29..89dabf366c1c55d4c29c02c420a096fdf69be33a 100644 (file)
@@ -23,3 +23,4 @@ valgrind = [ "valgrind_request" ]
 # Docs should be able to reference the proxmox crate.
 [dev-dependencies]
 proxmox = { path = "../proxmox" }
+serde_json = "1.0"
index 26bf618b518753e9c049df4bc56b9ce9b1e868c5..45b3ce12a05a283adc4dc93202dc29f6bb38d2e9 100644 (file)
@@ -1,51 +1,79 @@
 //! Serialization helpers for serde
 
-/// Sertialize DateTime<Local> as RFC3339
+/// Serialize DateTime<Local> as RFC3339.
+///
+/// Usage example:
+/// ```
+/// # pub extern crate proxmox_tools;
+/// # mod proxmox { pub use proxmox_tools as tools; }
+///
+/// use chrono::{DateTime, TimeZone, Utc};
+/// use serde::{Deserialize, Serialize};
+///
+/// # #[derive(Debug)]
+/// #[derive(Deserialize, PartialEq, Serialize)]
+/// struct Foo {
+///     #[serde(with = "proxmox::tools::serde::date_time_as_rfc3339")]
+///     date: DateTime<Utc>,
+/// }
+///
+/// let obj = Foo { date: Utc.timestamp_millis(86400000) }; // random test value
+/// let json = serde_json::to_string(&obj).unwrap();
+/// assert_eq!(json, r#"{"date":"1970-01-02T00:00:00+00:00"}"#);
+///
+/// let deserialized: Foo = serde_json::from_str(&json).unwrap();
+/// assert_eq!(obj, deserialized);
+/// ```
 pub mod date_time_as_rfc3339 {
+    use chrono::{DateTime, TimeZone};
+    use serde::{Deserialize, Deserializer, Serializer};
 
-    use chrono::{Local, DateTime};
-    use serde::{Serializer, Deserializer, Deserialize};
-
-    pub fn serialize<S>(time: &DateTime<Local>, serializer: S) -> Result<S::Ok, S::Error>
-        where S: Serializer,
+    pub fn serialize<S, Tz>(time: &DateTime<Tz>, serializer: S) -> Result<S::Ok, S::Error>
+    where
+        S: Serializer,
+        Tz: TimeZone,
+        Tz::Offset: std::fmt::Display,
     {
         serializer.serialize_str(&time.to_rfc3339())
     }
 
-    pub fn deserialize<'de, D>(deserializer: D) -> Result<DateTime<Local>, D::Error>
-        where D: Deserializer<'de>
+    pub fn deserialize<'de, D, Tz>(deserializer: D) -> Result<DateTime<Tz>, D::Error>
+    where
+        D: Deserializer<'de>,
+        Tz: TimeZone,
+        DateTime<Tz>: std::str::FromStr,
+        <DateTime<Tz> as std::str::FromStr>::Err: std::string::ToString,
     {
         use serde::de::Error;
-        String::deserialize(deserializer)
-            .and_then(|string| {
-                string.parse::<DateTime<Local>>()
-                    .map_err(|err| Error::custom(err.to_string()))
-            })
+        String::deserialize(deserializer).and_then(|string| {
+            string
+                .parse::<DateTime<Tz>>()
+                .map_err(|err| Error::custom(err.to_string()))
+        })
     }
 }
 
-
 /// Serialize Vec<u8> as base64 encoded string.
 pub mod bytes_as_base64 {
 
     use base64;
-    use serde::{Serializer,Deserializer, Deserialize};
+    use serde::{Deserialize, Deserializer, Serializer};
 
     pub fn serialize<S, T>(data: &T, serializer: S) -> Result<S::Ok, S::Error>
-        where T: AsRef<[u8]>,
-              S: Serializer,
+    where
+        T: AsRef<[u8]>,
+        S: Serializer,
     {
         serializer.serialize_str(&base64::encode(data.as_ref()))
     }
 
     pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
-        where D: Deserializer<'de>
+    where
+        D: Deserializer<'de>,
     {
         use serde::de::Error;
-        String::deserialize(deserializer)
-            .and_then(|string| {
-                base64::decode(&string)
-                    .map_err(|err| Error::custom(err.to_string()))
-            })
+        String::deserialize(deserializer).and_then(|string| {
+            base64::decode(&string).map_err(|err| Error::custom(err.to_string()))
+        })
     }
 }