diff --git a/.travis.yml b/.travis.yml index 12dc11e..56a4b57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,8 +9,10 @@ env: script: - cargo build -v - cargo build -v --features rustc-serialize + - cargo build -v --features serde - cargo test -v - cargo test -v --features rustc-serialize + - cargo test -v --features serde - cargo doc after_script: - cd target && curl http://www.rust-ci.org/artifacts/put?t=$RUSTCI_TOKEN | sh diff --git a/Cargo.toml b/Cargo.toml index a205ce0..326367e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,4 +18,7 @@ name = "chrono" time = "*" num = "*" rustc-serialize = { version = "0.3", optional = true } +serde = { version = "^0.6.0", optional = true } +[dev-dependencies] +serde_json = { version = "^0.6.0" } diff --git a/src/datetime.rs b/src/datetime.rs index 0b464fe..f7eb63f 100644 --- a/src/datetime.rs +++ b/src/datetime.rs @@ -366,6 +366,64 @@ impl str::FromStr for DateTime { } } +#[cfg(feature = "serde")] +mod serde { + use super::DateTime; + use offset::TimeZone; + use offset::utc::UTC; + use offset::local::Local; + use offset::fixed::FixedOffset; + use std::fmt::Display; + use serde::{ser, de}; + + impl ser::Serialize for DateTime + where Tz::Offset: Display + { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: ser::Serializer + { + // Debug formatting is correct RFC3339, and it allows Zulu. + serializer.visit_str(&format!("{:?}", self)) + } + } + + struct DateTimeVisitor; + + impl de::Visitor for DateTimeVisitor { + type Value = DateTime; + + fn visit_str(&mut self, value: &str) -> Result, E> + where E: de::Error + { + value.parse().map_err(|err| E::syntax(&format!("{}", err))) + } + } + + impl de::Deserialize for DateTime { + fn deserialize(deserializer: &mut D) -> Result + where D: de::Deserializer + { + deserializer.visit(DateTimeVisitor) + } + } + + impl de::Deserialize for DateTime { + fn deserialize(deserializer: &mut D) -> Result + where D: de::Deserializer + { + deserializer.visit(DateTimeVisitor).map(|dt| dt.with_timezone(&UTC)) + } + } + + impl de::Deserialize for DateTime { + fn deserialize(deserializer: &mut D) -> Result + where D: de::Deserializer + { + deserializer.visit(DateTimeVisitor).map(|dt| dt.with_timezone(&Local)) + } + } +} + #[cfg(test)] mod tests { use super::DateTime; @@ -518,5 +576,30 @@ mod tests { let _ = a; }).join().unwrap(); } + + #[cfg(feature = "serde")] + extern crate serde_json; + + #[cfg(feature = "serde")] + #[test] + fn test_serde_serialize() { + use self::serde_json::to_string; + + let date = UTC.ymd(2014, 7, 24).and_hms(12, 34, 6); + let serialized = to_string(&date).unwrap(); + + assert_eq!(serialized, "\"2014-07-24T12:34:06Z\""); + } + + #[cfg(feature = "serde")] + #[test] + fn test_serde_deserialize() { + use self::serde_json::from_str; + + let date = UTC.ymd(2014, 7, 24).and_hms(12, 34, 6); + let deserialized: DateTime = from_str("\"2014-07-24T12:34:06Z\"").unwrap(); + + assert_eq!(deserialized, date); + } } diff --git a/src/lib.rs b/src/lib.rs index 11e3069..7dd084a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -275,6 +275,8 @@ extern crate time as stdtime; extern crate num; #[cfg(feature = "rustc-serialize")] extern crate rustc_serialize; +#[cfg(feature = "serde")] +extern crate serde; pub use duration::Duration; pub use offset::{TimeZone, Offset, LocalResult}; diff --git a/src/naive/date.rs b/src/naive/date.rs index f42e9fc..8bb29f0 100644 --- a/src/naive/date.rs +++ b/src/naive/date.rs @@ -1051,6 +1051,41 @@ impl str::FromStr for NaiveDate { } } + +#[cfg(feature = "serde")] +mod serde { + use super::NaiveDate; + use serde::{ser, de}; + + impl ser::Serialize for NaiveDate { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: ser::Serializer + { + serializer.visit_str(&format!("{:?}", self)) + } + } + + struct NaiveDateVisitor; + + impl de::Visitor for NaiveDateVisitor { + type Value = NaiveDate; + + fn visit_str(&mut self, value: &str) -> Result + where E: de::Error + { + value.parse().map_err(|err| E::syntax(&format!("{}", err))) + } + } + + impl de::Deserialize for NaiveDate { + fn deserialize(deserializer: &mut D) -> Result + where D: de::Deserializer + { + deserializer.visit(NaiveDateVisitor) + } + } +} + #[cfg(test)] mod tests { use super::NaiveDate; @@ -1477,6 +1512,31 @@ mod tests { assert_eq!(NaiveDate::from_ymd(2010, 1, 3).format("%G,%g,%U,%W,%V").to_string(), "2009,09,01,00,53"); } + + #[cfg(feature = "serde")] + extern crate serde_json; + + #[cfg(feature = "serde")] + #[test] + fn test_serde_serialize() { + use self::serde_json::to_string; + + let date = NaiveDate::from_ymd(2014, 7, 24); + let serialized = to_string(&date).unwrap(); + + assert_eq!(serialized, "\"2014-07-24\""); + } + + #[cfg(feature = "serde")] + #[test] + fn test_serde_deserialize() { + use self::serde_json::from_str; + + let date = NaiveDate::from_ymd(2014, 7, 24); + let deserialized: NaiveDate = from_str("\"2014-07-24\"").unwrap(); + + assert_eq!(deserialized, date); + } } /** diff --git a/src/naive/datetime.rs b/src/naive/datetime.rs index e6b240f..75d7ca4 100644 --- a/src/naive/datetime.rs +++ b/src/naive/datetime.rs @@ -315,6 +315,40 @@ impl str::FromStr for NaiveDateTime { } } +#[cfg(feature = "serde")] +mod serde { + use super::NaiveDateTime; + use serde::{ser, de}; + + impl ser::Serialize for NaiveDateTime { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: ser::Serializer + { + serializer.visit_str(&format!("{:?}", self)) + } + } + + struct NaiveDateTimeVisitor; + + impl de::Visitor for NaiveDateTimeVisitor { + type Value = NaiveDateTime; + + fn visit_str(&mut self, value: &str) -> Result + where E: de::Error + { + value.parse().map_err(|err| E::syntax(&format!("{}", err))) + } + } + + impl de::Deserialize for NaiveDateTime { + fn deserialize(deserializer: &mut D) -> Result + where D: de::Deserializer + { + deserializer.visit(NaiveDateTimeVisitor) + } + } +} + #[cfg(test)] mod tests { use super::NaiveDateTime; @@ -468,5 +502,30 @@ mod tests { let time = base + Duration::microseconds(t); assert_eq!(t, (time - base).num_microseconds().unwrap()); } + + #[cfg(feature = "serde")] + extern crate serde_json; + + #[cfg(feature = "serde")] + #[test] + fn test_serde_serialize() { + use self::serde_json::to_string; + + let date = NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6); + let serialized = to_string(&date).unwrap(); + + assert_eq!(serialized, "\"2014-07-24T12:34:06\""); + } + + #[cfg(feature = "serde")] + #[test] + fn test_serde_deserialize() { + use self::serde_json::from_str; + + let date = NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6); + let deserialized: NaiveDateTime = from_str("\"2014-07-24T12:34:06\"").unwrap(); + + assert_eq!(deserialized, date); + } } diff --git a/src/naive/time.rs b/src/naive/time.rs index 56baf26..07af42a 100644 --- a/src/naive/time.rs +++ b/src/naive/time.rs @@ -574,6 +574,40 @@ impl str::FromStr for NaiveTime { } } +#[cfg(feature = "serde")] +mod serde { + use super::NaiveTime; + use serde::{ser, de}; + + impl ser::Serialize for NaiveTime { + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + where S: ser::Serializer + { + serializer.visit_str(&format!("{:?}", self)) + } + } + + struct NaiveTimeVisitor; + + impl de::Visitor for NaiveTimeVisitor { + type Value = NaiveTime; + + fn visit_str(&mut self, value: &str) -> Result + where E: de::Error + { + value.parse().map_err(|err| E::syntax(&format!("{}", err))) + } + } + + impl de::Deserialize for NaiveTime { + fn deserialize(deserializer: &mut D) -> Result + where D: de::Deserializer + { + deserializer.visit(NaiveTimeVisitor) + } + } +} + #[cfg(test)] mod tests { use super::NaiveTime; @@ -764,5 +798,30 @@ mod tests { assert_eq!(NaiveTime::from_hms_milli(23, 59, 59, 1_000).format("%X").to_string(), "23:59:60"); } + + #[cfg(feature = "serde")] + extern crate serde_json; + + #[cfg(feature = "serde")] + #[test] + fn test_serde_serialize() { + use self::serde_json::to_string; + + let time = NaiveTime::from_hms_nano(3, 5, 7, 98765432); + let serialized = to_string(&time).unwrap(); + + assert_eq!(serialized, "\"03:05:07.098765432\""); + } + + #[cfg(feature = "serde")] + #[test] + fn test_serde_deserialize() { + use self::serde_json::from_str; + + let time = NaiveTime::from_hms_nano(3, 5, 7, 98765432); + let deserialized: NaiveTime = from_str("\"03:05:07.098765432\"").unwrap(); + + assert_eq!(deserialized, time); + } }