diff --git a/edn/src/edn.rustpeg b/edn/src/edn.rustpeg index 4d1d5d82..6c3e2bd7 100644 --- a/edn/src/edn.rustpeg +++ b/edn/src/edn.rustpeg @@ -101,7 +101,7 @@ inst_string -> DateTime = "T" [0-2][0-9] ":" [0-5][0-9] ":" [0-6][0-9] ("." [0-9]+)? - "Z" / (("+" / "-") [0-2][0-9] ":" [0-5][0-9]) + ("Z" / (("+" / "-") [0-2][0-9] ":" [0-5][0-9])) ) "\"" {? DateTime::parse_from_rfc3339(d) diff --git a/edn/src/pretty_print.rs b/edn/src/pretty_print.rs index de0525dd..e2669f5d 100644 --- a/edn/src/pretty_print.rs +++ b/edn/src/pretty_print.rs @@ -8,6 +8,10 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. +use chrono::{ + SecondsFormat, +}; + use itertools::Itertools; use pretty; @@ -70,6 +74,7 @@ impl Value { Value::Keyword(ref v) => pp.text(":").append(v.0.as_ref()), Value::Text(ref v) => pp.text("\"").append(v.as_ref()).append("\""), Value::Uuid(ref u) => pp.text("#uuid \"").append(u.hyphenated().to_string()).append("\""), + Value::Instant(ref v) => pp.text("#inst \"").append(v.to_rfc3339_opts(SecondsFormat::AutoSi, true)).append("\""), _ => pp.text(self.to_string()) } } diff --git a/edn/src/types.rs b/edn/src/types.rs index 549dfb71..f930afcf 100644 --- a/edn/src/types.rs +++ b/edn/src/types.rs @@ -17,6 +17,7 @@ use std::f64; use chrono::{ DateTime, + SecondsFormat, TimeZone, // For Utc::timestamp. The compiler incorrectly complains that this is unused. Utc, }; @@ -461,7 +462,7 @@ macro_rules! def_common_value_display { $t::Nil => write!($f, "nil"), $t::Boolean(v) => write!($f, "{}", v), $t::Integer(v) => write!($f, "{}", v), - $t::Instant(v) => write!($f, "{}", v), + $t::Instant(v) => write!($f, "#inst \"{}\"", v.to_rfc3339_opts(SecondsFormat::AutoSi, true)), $t::BigInteger(ref v) => write!($f, "{}N", v), // TODO: make sure float syntax is correct. $t::Float(ref v) => { diff --git a/edn/tests/tests.rs b/edn/tests/tests.rs index 48692467..c1a8e74b 100644 --- a/edn/tests/tests.rs +++ b/edn/tests/tests.rs @@ -264,10 +264,31 @@ fn test_uuid() { let expected = uuid::Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000") .expect("valid UUID"); - let actual = parse::uuid("#uuid \"550e8400-e29b-41d4-a716-446655440000\"") + let s = "#uuid \"550e8400-e29b-41d4-a716-446655440000\""; + let actual = parse::uuid(s) .expect("parse success") .into(); - assert_eq!(self::Value::Uuid(expected), actual); + let value = self::Value::Uuid(expected); + assert_eq!(value, actual); + assert_eq!(format!("{}", value), s); + assert_eq!(value.to_pretty(100).unwrap(), s); +} + +#[test] +fn test_inst() { + assert!(parse::value("#inst\"2016-01-01T11:00:00.000Z\"").is_err()); // No whitespace. + assert!(parse::value("#inst \"2016-01-01T11:00:00.000\"").is_err()); // No timezone. + assert!(parse::value("#inst \"2016-01-01T11:00:00.000z\"").is_err()); // Lowercase timezone. + + let expected = Utc.timestamp(1493410985, 187000000); + let s = "#inst \"2017-04-28T20:23:05.187Z\""; + let actual = parse::value(s) + .expect("parse success") + .into(); + let value = self::Value::Instant(expected); + assert_eq!(value, actual); + assert_eq!(format!("{}", value), s); + assert_eq!(value.to_pretty(100).unwrap(), s); } #[test]