Serialization cleanup for 0.3.
- Rustc-serialize now uses the same serialization format as Serde. This also means that the older format (naturally derived from the internals) is no longer supported. - Serialization support only existed for rustc-serialize has been (temporarily) removed. This affects `Date<Tz>` and all individual time zone types. This does *not* affect `DateTime<Tz>` as it has individual support per `Tz`. Please note that this is considered a temporary solution to avoid stabilizing diverging implementations. Their implementations will likely be reintroduced later.
This commit is contained in:
parent
c63ef14734
commit
c118a3985f
52
src/date.rs
52
src/date.rs
|
@ -398,58 +398,6 @@ impl<Tz: TimeZone> fmt::Display for Date<Tz> where Tz::Offset: fmt::Display {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
mod rustc_serialize {
|
||||
use super::Date;
|
||||
use offset::TimeZone;
|
||||
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
|
||||
// TODO the current serialization format is NEVER intentionally defined.
|
||||
// in the future it is likely to be redefined to more sane and reasonable format.
|
||||
|
||||
impl<Tz: TimeZone> Encodable for Date<Tz> where Tz::Offset: Encodable {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_struct("Date", 2, |s| {
|
||||
try!(s.emit_struct_field("date", 0, |s| self.date.encode(s)));
|
||||
try!(s.emit_struct_field("offset", 1, |s| self.offset.encode(s)));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tz: TimeZone> Decodable for Date<Tz> where Tz::Offset: Decodable {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<Date<Tz>, D::Error> {
|
||||
d.read_struct("Date", 2, |d| {
|
||||
let date = try!(d.read_struct_field("date", 0, Decodable::decode));
|
||||
let offset = try!(d.read_struct_field("offset", 1, Decodable::decode));
|
||||
Ok(Date::from_utc(date, offset))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encodable() {
|
||||
use offset::utc::UTC;
|
||||
use rustc_serialize::json::encode;
|
||||
|
||||
assert_eq!(encode(&UTC.ymd(2014, 7, 24)).ok(),
|
||||
Some(r#"{"date":{"ymdf":16501977},"offset":{}}"#.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decodable() {
|
||||
use offset::utc::UTC;
|
||||
use rustc_serialize::json;
|
||||
|
||||
let decode = |s: &str| json::decode::<Date<UTC>>(s);
|
||||
|
||||
assert_eq!(decode(r#"{"date":{"ymdf":16501977},"offset":{}}"#).ok(),
|
||||
Some(UTC.ymd(2014, 7, 24)));
|
||||
|
||||
assert!(decode(r#"{"date":{"ymdf":0},"offset":{}}"#).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fmt;
|
||||
|
|
143
src/datetime.rs
143
src/datetime.rs
|
@ -405,65 +405,108 @@ impl str::FromStr for DateTime<Local> {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
|
||||
fn test_encodable_json<FUTC, FFixed, E>(to_string_utc: FUTC, to_string_fixed: FFixed)
|
||||
where FUTC: Fn(&DateTime<UTC>) -> Result<String, E>,
|
||||
FFixed: Fn(&DateTime<FixedOffset>) -> Result<String, E>,
|
||||
E: ::std::fmt::Debug
|
||||
{
|
||||
assert_eq!(to_string_utc(&UTC.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
|
||||
Some(r#""2014-07-24T12:34:06Z""#.into()));
|
||||
|
||||
assert_eq!(to_string_fixed(&FixedOffset::east(3660).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
|
||||
Some(r#""2014-07-24T12:34:06+01:01""#.into()));
|
||||
assert_eq!(to_string_fixed(&FixedOffset::east(3650).ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
|
||||
Some(r#""2014-07-24T12:34:06+01:00:50""#.into()));
|
||||
}
|
||||
|
||||
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
|
||||
fn test_decodable_json<FUTC, FFixed, FLocal, E>(utc_from_str: FUTC,
|
||||
fixed_from_str: FFixed,
|
||||
local_from_str: FLocal)
|
||||
where FUTC: Fn(&str) -> Result<DateTime<UTC>, E>,
|
||||
FFixed: Fn(&str) -> Result<DateTime<FixedOffset>, E>,
|
||||
FLocal: Fn(&str) -> Result<DateTime<Local>, E>,
|
||||
E: ::std::fmt::Debug
|
||||
{
|
||||
// should check against the offset as well (the normal DateTime comparison will ignore them)
|
||||
fn norm<Tz: TimeZone>(dt: &Option<DateTime<Tz>>) -> Option<(&DateTime<Tz>, &Tz::Offset)> {
|
||||
dt.as_ref().map(|dt| (dt, dt.offset()))
|
||||
}
|
||||
|
||||
assert_eq!(norm(&utc_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
|
||||
norm(&Some(UTC.ymd(2014, 7, 24).and_hms(12, 34, 6))));
|
||||
assert_eq!(norm(&utc_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
|
||||
norm(&Some(UTC.ymd(2014, 7, 24).and_hms(12, 34, 6))));
|
||||
|
||||
assert_eq!(norm(&fixed_from_str(r#""2014-07-24T12:34:06Z""#).ok()),
|
||||
norm(&Some(FixedOffset::east(0).ymd(2014, 7, 24).and_hms(12, 34, 6))));
|
||||
assert_eq!(norm(&fixed_from_str(r#""2014-07-24T13:57:06+01:23""#).ok()),
|
||||
norm(&Some(FixedOffset::east(60*60 + 23*60).ymd(2014, 7, 24).and_hms(13, 57, 6))));
|
||||
|
||||
// we don't know the exact local offset but we can check that
|
||||
// the conversion didn't change the instant itself
|
||||
assert_eq!(local_from_str(r#""2014-07-24T12:34:06Z""#).unwrap(),
|
||||
UTC.ymd(2014, 7, 24).and_hms(12, 34, 6));
|
||||
assert_eq!(local_from_str(r#""2014-07-24T13:57:06+01:23""#).unwrap(),
|
||||
UTC.ymd(2014, 7, 24).and_hms(12, 34, 6));
|
||||
|
||||
assert!(utc_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
|
||||
assert!(fixed_from_str(r#""2014-07-32T12:34:06Z""#).is_err());
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
mod rustc_serialize {
|
||||
use super::DateTime;
|
||||
use offset::TimeZone;
|
||||
use offset::utc::UTC;
|
||||
use offset::local::Local;
|
||||
use offset::fixed::FixedOffset;
|
||||
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
|
||||
// TODO the current serialization format is NEVER intentionally defined.
|
||||
// in the future it is likely to be redefined to more sane and reasonable format.
|
||||
|
||||
impl<Tz: TimeZone> Encodable for DateTime<Tz> where Tz::Offset: Encodable {
|
||||
impl<Tz: TimeZone> Encodable for DateTime<Tz> {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_struct("DateTime", 2, |s| {
|
||||
try!(s.emit_struct_field("datetime", 0, |s| self.datetime.encode(s)));
|
||||
try!(s.emit_struct_field("offset", 1, |s| self.offset.encode(s)));
|
||||
Ok(())
|
||||
})
|
||||
format!("{:?}", self).encode(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Tz: TimeZone> Decodable for DateTime<Tz> where Tz::Offset: Decodable {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Tz>, D::Error> {
|
||||
d.read_struct("DateTime", 2, |d| {
|
||||
let datetime = try!(d.read_struct_field("datetime", 0, Decodable::decode));
|
||||
let offset = try!(d.read_struct_field("offset", 1, Decodable::decode));
|
||||
Ok(DateTime::from_utc(datetime, offset))
|
||||
})
|
||||
impl Decodable for DateTime<FixedOffset> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<FixedOffset>, D::Error> {
|
||||
match d.read_str()?.parse::<DateTime<FixedOffset>>() {
|
||||
Ok(dt) => Ok(dt),
|
||||
Err(_) => Err(d.error("invalid date and time")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for DateTime<UTC> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<UTC>, D::Error> {
|
||||
match d.read_str()?.parse::<DateTime<FixedOffset>>() {
|
||||
Ok(dt) => Ok(dt.with_timezone(&UTC)),
|
||||
Err(_) => Err(d.error("invalid date and time")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for DateTime<Local> {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<DateTime<Local>, D::Error> {
|
||||
match d.read_str()?.parse::<DateTime<FixedOffset>>() {
|
||||
Ok(dt) => Ok(dt.with_timezone(&Local)),
|
||||
Err(_) => Err(d.error("invalid date and time")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] use rustc_serialize::json;
|
||||
|
||||
#[test]
|
||||
fn test_encodable() {
|
||||
use offset::utc::UTC;
|
||||
use rustc_serialize::json::encode;
|
||||
|
||||
assert_eq!(
|
||||
encode(&UTC.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
|
||||
Some(concat!(r#"{"datetime":{"date":{"ymdf":16501977},"#,
|
||||
r#""time":{"secs":45246,"frac":0}},"#,
|
||||
r#""offset":{}}"#).into()));
|
||||
super::test_encodable_json(json::encode, json::encode);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decodable() {
|
||||
use offset::utc::UTC;
|
||||
use rustc_serialize::json;
|
||||
|
||||
let decode = |s: &str| json::decode::<DateTime<UTC>>(s);
|
||||
|
||||
assert_eq!(
|
||||
decode(r#"{"datetime":{"date":{"ymdf":16501977},
|
||||
"time":{"secs":45246,"frac":0}},
|
||||
"offset":{}}"#).ok(),
|
||||
Some(UTC.ymd(2014, 7, 24).and_hms(12, 34, 6)));
|
||||
|
||||
assert_eq!(
|
||||
decode(r#"{"datetime":{"date":{"ymdf":0},
|
||||
"time":{"secs":0,"frac":0}},
|
||||
"offset":{}}"#).ok(),
|
||||
None);
|
||||
super::test_decodable_json(json::decode, json::decode, json::decode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -475,14 +518,11 @@ mod serde {
|
|||
use offset::utc::UTC;
|
||||
use offset::local::Local;
|
||||
use offset::fixed::FixedOffset;
|
||||
use std::fmt::Display;
|
||||
use serde::{ser, de};
|
||||
|
||||
// TODO not very optimized for space (binary formats would want something better)
|
||||
|
||||
impl<Tz: TimeZone> ser::Serialize for DateTime<Tz>
|
||||
where Tz::Offset: Display
|
||||
{
|
||||
impl<Tz: TimeZone> ser::Serialize for DateTime<Tz> {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: ser::Serializer
|
||||
{
|
||||
|
@ -537,22 +577,13 @@ mod serde {
|
|||
|
||||
#[test]
|
||||
fn test_serde_serialize() {
|
||||
use self::serde_json::to_string;
|
||||
|
||||
assert_eq!(to_string(&UTC.ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
|
||||
Some(r#""2014-07-24T12:34:06Z""#.into()));
|
||||
super::test_encodable_json(self::serde_json::to_string, self::serde_json::to_string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_deserialize() {
|
||||
use self::serde_json;
|
||||
|
||||
let from_str = |s: &str| serde_json::from_str::<DateTime<UTC>>(s);
|
||||
|
||||
assert_eq!(from_str(r#""2014-07-24T12:34:06Z""#).ok(),
|
||||
Some(UTC.ymd(2014, 7, 24).and_hms(12, 34, 6)));
|
||||
|
||||
assert!(from_str(r#""2014-07-32T12:34:06Z""#).is_err());
|
||||
super::test_decodable_json(self::serde_json::from_str, self::serde_json::from_str,
|
||||
self::serde_json::from_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -136,26 +136,6 @@ impl NaiveDate {
|
|||
NaiveDate::from_of(year, mdf.to_of())
|
||||
}
|
||||
|
||||
/// Makes a new `NaiveDate` from the serialized representation.
|
||||
/// Used for serialization formats.
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
fn from_serialized(ymdf: i32) -> Option<NaiveDate> {
|
||||
// check if the year flag is correct
|
||||
if (ymdf & 0b1111) as u8 != YearFlags::from_year(ymdf >> 13).0 { return None; }
|
||||
|
||||
// check if the ordinal is in the range
|
||||
let date = NaiveDate { ymdf: ymdf };
|
||||
if !date.of().valid() { return None; }
|
||||
|
||||
Some(date)
|
||||
}
|
||||
|
||||
/// Returns a serialized representation of this `NaiveDate`.
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
fn to_serialized(&self) -> i32 {
|
||||
self.ymdf
|
||||
}
|
||||
|
||||
/// Makes a new `NaiveDate` from the [calendar date](./index.html#calendar-date)
|
||||
/// (year, month and day).
|
||||
///
|
||||
|
@ -1497,83 +1477,84 @@ impl str::FromStr for NaiveDate {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
|
||||
fn test_encodable_json<F, E>(to_string: F)
|
||||
where F: Fn(&NaiveDate) -> Result<String, E>, E: ::std::fmt::Debug
|
||||
{
|
||||
assert_eq!(to_string(&NaiveDate::from_ymd(2014, 7, 24)).ok(),
|
||||
Some(r#""2014-07-24""#.into()));
|
||||
assert_eq!(to_string(&NaiveDate::from_ymd(0, 1, 1)).ok(),
|
||||
Some(r#""0000-01-01""#.into()));
|
||||
assert_eq!(to_string(&NaiveDate::from_ymd(-1, 12, 31)).ok(),
|
||||
Some(r#""-0001-12-31""#.into()));
|
||||
assert_eq!(to_string(&MIN).ok(),
|
||||
Some(r#""-262144-01-01""#.into()));
|
||||
assert_eq!(to_string(&MAX).ok(),
|
||||
Some(r#""+262143-12-31""#.into()));
|
||||
}
|
||||
|
||||
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
|
||||
fn test_decodable_json<F, E>(from_str: F)
|
||||
where F: Fn(&str) -> Result<NaiveDate, E>, E: ::std::fmt::Debug
|
||||
{
|
||||
use std::{i32, i64};
|
||||
|
||||
assert_eq!(from_str(r#""2016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8)));
|
||||
assert_eq!(from_str(r#""2016-7-8""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8)));
|
||||
assert_eq!(from_str(r#""+002016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8)));
|
||||
assert_eq!(from_str(r#""0000-01-01""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1)));
|
||||
assert_eq!(from_str(r#""0-1-1""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1)));
|
||||
assert_eq!(from_str(r#""-0001-12-31""#).ok(), Some(NaiveDate::from_ymd(-1, 12, 31)));
|
||||
assert_eq!(from_str(r#""-262144-01-01""#).ok(), Some(MIN));
|
||||
assert_eq!(from_str(r#""+262143-12-31""#).ok(), Some(MAX));
|
||||
|
||||
// bad formats
|
||||
assert!(from_str(r#""""#).is_err());
|
||||
assert!(from_str(r#""20001231""#).is_err());
|
||||
assert!(from_str(r#""2000-00-00""#).is_err());
|
||||
assert!(from_str(r#""2000-02-30""#).is_err());
|
||||
assert!(from_str(r#""2001-02-29""#).is_err());
|
||||
assert!(from_str(r#""2002-002-28""#).is_err());
|
||||
assert!(from_str(r#""yyyy-mm-dd""#).is_err());
|
||||
assert!(from_str(r#"0"#).is_err());
|
||||
assert!(from_str(r#"20.01"#).is_err());
|
||||
assert!(from_str(&i32::MIN.to_string()).is_err());
|
||||
assert!(from_str(&i32::MAX.to_string()).is_err());
|
||||
assert!(from_str(&i64::MIN.to_string()).is_err());
|
||||
assert!(from_str(&i64::MAX.to_string()).is_err());
|
||||
assert!(from_str(r#"{}"#).is_err());
|
||||
// pre-0.3.0 rustc-serialize format is now invalid
|
||||
assert!(from_str(r#"{"ymdf":20}"#).is_err());
|
||||
assert!(from_str(r#"null"#).is_err());
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
mod rustc_serialize {
|
||||
use super::NaiveDate;
|
||||
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
|
||||
// TODO the current serialization format is NEVER intentionally defined.
|
||||
// this basically follows the automatically generated implementation for those traits,
|
||||
// plus manual verification steps for avoiding security problem.
|
||||
// in the future it is likely to be redefined to more sane and reasonable format.
|
||||
|
||||
impl Encodable for NaiveDate {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
let ymdf = self.to_serialized();
|
||||
s.emit_struct("NaiveDate", 1, |s| {
|
||||
try!(s.emit_struct_field("ymdf", 0, |s| ymdf.encode(s)));
|
||||
Ok(())
|
||||
})
|
||||
format!("{:?}", self).encode(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for NaiveDate {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<NaiveDate, D::Error> {
|
||||
d.read_struct("NaiveDate", 1, |d| {
|
||||
let ymdf = try!(d.read_struct_field("ymdf", 0, Decodable::decode));
|
||||
NaiveDate::from_serialized(ymdf).ok_or_else(|| d.error("invalid date"))
|
||||
})
|
||||
d.read_str()?.parse().map_err(|_| d.error("invalid date"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] use rustc_serialize::json;
|
||||
|
||||
#[test]
|
||||
fn test_encodable() {
|
||||
use rustc_serialize::json::encode;
|
||||
|
||||
assert_eq!(encode(&NaiveDate::from_ymd(2016, 7, 8)).ok(),
|
||||
Some(r#"{"ymdf":16518115}"#.into()));
|
||||
assert_eq!(encode(&NaiveDate::from_ymd(0, 1, 1)).ok(),
|
||||
Some(r#"{"ymdf":20}"#.into()));
|
||||
assert_eq!(encode(&NaiveDate::from_ymd(-1, 12, 31)).ok(),
|
||||
Some(r#"{"ymdf":-2341}"#.into()));
|
||||
assert_eq!(encode(&super::MIN).ok(),
|
||||
Some(r#"{"ymdf":-2147483625}"#.into()));
|
||||
assert_eq!(encode(&super::MAX).ok(),
|
||||
Some(r#"{"ymdf":2147481311}"#.into()));
|
||||
super::test_encodable_json(json::encode);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decodable() {
|
||||
use rustc_serialize::json;
|
||||
use std::{i32, i64};
|
||||
|
||||
let decode = |s: &str| json::decode::<NaiveDate>(s);
|
||||
|
||||
assert_eq!(decode(r#"{"ymdf":16518115}"#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8)));
|
||||
assert_eq!(decode(r#"{"ymdf":20}"#).ok(), Some(NaiveDate::from_ymd(0, 1, 1)));
|
||||
assert_eq!(decode(r#"{"ymdf":-2341}"#).ok(), Some(NaiveDate::from_ymd(-1, 12, 31)));
|
||||
assert_eq!(decode(r#"{"ymdf":-2147483625}"#).ok(), Some(super::MIN));
|
||||
assert_eq!(decode(r#"{"ymdf":2147481311}"#).ok(), Some(super::MAX));
|
||||
|
||||
// some extreme values and zero are always invalid
|
||||
assert!(decode(r#"{"ymdf":0}"#).is_err());
|
||||
assert!(decode(r#"{"ymdf":1}"#).is_err());
|
||||
assert!(decode(r#"{"ymdf":-1}"#).is_err());
|
||||
assert!(decode(&format!(r#"{{"ymdf":{}}}"#, i32::MIN)).is_err());
|
||||
assert!(decode(&format!(r#"{{"ymdf":{}}}"#, i32::MAX)).is_err());
|
||||
assert!(decode(&format!(r#"{{"ymdf":{}}}"#, i64::MIN)).is_err());
|
||||
assert!(decode(&format!(r#"{{"ymdf":{}}}"#, i64::MAX)).is_err());
|
||||
|
||||
// bad formats
|
||||
assert!(decode(r#"{"ymdf":20.01}"#).is_err());
|
||||
assert!(decode(r#"{"ymdf":"string"}"#).is_err());
|
||||
assert!(decode(r#"{"ymdf":null}"#).is_err());
|
||||
assert!(decode(r#"{}"#).is_err());
|
||||
assert!(decode(r#"{"date":20}"#).is_err());
|
||||
assert!(decode(r#"20"#).is_err());
|
||||
assert!(decode(r#""string""#).is_err());
|
||||
assert!(decode(r#""2016-07-08""#).is_err()); // :(
|
||||
assert!(decode(r#"null"#).is_err());
|
||||
super::test_decodable_json(json::decode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1623,53 +1604,12 @@ mod serde {
|
|||
|
||||
#[test]
|
||||
fn test_serde_serialize() {
|
||||
use self::serde_json::to_string;
|
||||
|
||||
assert_eq!(to_string(&NaiveDate::from_ymd(2014, 7, 24)).ok(),
|
||||
Some(r#""2014-07-24""#.into()));
|
||||
assert_eq!(to_string(&NaiveDate::from_ymd(0, 1, 1)).ok(),
|
||||
Some(r#""0000-01-01""#.into()));
|
||||
assert_eq!(to_string(&NaiveDate::from_ymd(-1, 12, 31)).ok(),
|
||||
Some(r#""-0001-12-31""#.into()));
|
||||
assert_eq!(to_string(&super::MIN).ok(),
|
||||
Some(r#""-262144-01-01""#.into()));
|
||||
assert_eq!(to_string(&super::MAX).ok(),
|
||||
Some(r#""+262143-12-31""#.into()));
|
||||
super::test_encodable_json(self::serde_json::to_string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_deserialize() {
|
||||
use self::serde_json;
|
||||
use std::{i32, i64};
|
||||
|
||||
let from_str = |s: &str| serde_json::from_str::<NaiveDate>(s);
|
||||
|
||||
assert_eq!(from_str(r#""2016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8)));
|
||||
assert_eq!(from_str(r#""2016-7-8""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8)));
|
||||
assert_eq!(from_str(r#""+002016-07-08""#).ok(), Some(NaiveDate::from_ymd(2016, 7, 8)));
|
||||
assert_eq!(from_str(r#""0000-01-01""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1)));
|
||||
assert_eq!(from_str(r#""0-1-1""#).ok(), Some(NaiveDate::from_ymd(0, 1, 1)));
|
||||
assert_eq!(from_str(r#""-0001-12-31""#).ok(), Some(NaiveDate::from_ymd(-1, 12, 31)));
|
||||
assert_eq!(from_str(r#""-262144-01-01""#).ok(), Some(super::MIN));
|
||||
assert_eq!(from_str(r#""+262143-12-31""#).ok(), Some(super::MAX));
|
||||
|
||||
// bad formats
|
||||
assert!(from_str(r#""""#).is_err());
|
||||
assert!(from_str(r#""20001231""#).is_err());
|
||||
assert!(from_str(r#""2000-00-00""#).is_err());
|
||||
assert!(from_str(r#""2000-02-30""#).is_err());
|
||||
assert!(from_str(r#""2001-02-29""#).is_err());
|
||||
assert!(from_str(r#""2002-002-28""#).is_err());
|
||||
assert!(from_str(r#""yyyy-mm-dd""#).is_err());
|
||||
assert!(from_str(r#"0"#).is_err());
|
||||
assert!(from_str(r#"20.01"#).is_err());
|
||||
assert!(from_str(&i32::MIN.to_string()).is_err());
|
||||
assert!(from_str(&i32::MAX.to_string()).is_err());
|
||||
assert!(from_str(&i64::MIN.to_string()).is_err());
|
||||
assert!(from_str(&i64::MAX.to_string()).is_err());
|
||||
assert!(from_str(r#"{}"#).is_err());
|
||||
assert!(from_str(r#"{"ymdf":20}"#).is_err()); // :(
|
||||
assert!(from_str(r#"null"#).is_err());
|
||||
super::test_decodable_json(self::serde_json::from_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1394,105 +1394,116 @@ impl str::FromStr for NaiveDateTime {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
|
||||
fn test_encodable_json<F, E>(to_string: F)
|
||||
where F: Fn(&NaiveDateTime) -> Result<String, E>, E: ::std::fmt::Debug
|
||||
{
|
||||
use naive::date;
|
||||
|
||||
assert_eq!(
|
||||
to_string(&NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)).ok(),
|
||||
Some(r#""2016-07-08T09:10:48.090""#.into()));
|
||||
assert_eq!(
|
||||
to_string(&NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
|
||||
Some(r#""2014-07-24T12:34:06""#.into()));
|
||||
assert_eq!(
|
||||
to_string(&NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)).ok(),
|
||||
Some(r#""0000-01-01T00:00:60""#.into()));
|
||||
assert_eq!(
|
||||
to_string(&NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7)).ok(),
|
||||
Some(r#""-0001-12-31T23:59:59.000000007""#.into()));
|
||||
assert_eq!(
|
||||
to_string(&date::MIN.and_hms(0, 0, 0)).ok(),
|
||||
Some(r#""-262144-01-01T00:00:00""#.into()));
|
||||
assert_eq!(
|
||||
to_string(&date::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)).ok(),
|
||||
Some(r#""+262143-12-31T23:59:60.999999999""#.into()));
|
||||
}
|
||||
|
||||
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
|
||||
fn test_decodable_json<F, E>(from_str: F)
|
||||
where F: Fn(&str) -> Result<NaiveDateTime, E>, E: ::std::fmt::Debug
|
||||
{
|
||||
use naive::date;
|
||||
|
||||
assert_eq!(
|
||||
from_str(r#""2016-07-08T09:10:48.090""#).ok(),
|
||||
Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)));
|
||||
assert_eq!(
|
||||
from_str(r#""2016-7-8T9:10:48.09""#).ok(),
|
||||
Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)));
|
||||
assert_eq!(
|
||||
from_str(r#""2014-07-24T12:34:06""#).ok(),
|
||||
Some(NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6)));
|
||||
assert_eq!(
|
||||
from_str(r#""0000-01-01T00:00:60""#).ok(),
|
||||
Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)));
|
||||
assert_eq!(
|
||||
from_str(r#""0-1-1T0:0:60""#).ok(),
|
||||
Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)));
|
||||
assert_eq!(
|
||||
from_str(r#""-0001-12-31T23:59:59.000000007""#).ok(),
|
||||
Some(NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7)));
|
||||
assert_eq!(
|
||||
from_str(r#""-262144-01-01T00:00:00""#).ok(),
|
||||
Some(date::MIN.and_hms(0, 0, 0)));
|
||||
assert_eq!(
|
||||
from_str(r#""+262143-12-31T23:59:60.999999999""#).ok(),
|
||||
Some(date::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)));
|
||||
assert_eq!(
|
||||
from_str(r#""+262143-12-31T23:59:60.9999999999997""#).ok(), // excess digits are ignored
|
||||
Some(date::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)));
|
||||
|
||||
// bad formats
|
||||
assert!(from_str(r#""""#).is_err());
|
||||
assert!(from_str(r#""2016-07-08""#).is_err());
|
||||
assert!(from_str(r#""09:10:48.090""#).is_err());
|
||||
assert!(from_str(r#""20160708T091048.090""#).is_err());
|
||||
assert!(from_str(r#""2000-00-00T00:00:00""#).is_err());
|
||||
assert!(from_str(r#""2000-02-30T00:00:00""#).is_err());
|
||||
assert!(from_str(r#""2001-02-29T00:00:00""#).is_err());
|
||||
assert!(from_str(r#""2002-02-28T24:00:00""#).is_err());
|
||||
assert!(from_str(r#""2002-02-28T23:60:00""#).is_err());
|
||||
assert!(from_str(r#""2002-02-28T23:59:61""#).is_err());
|
||||
assert!(from_str(r#""2016-07-08T09:10:48,090""#).is_err());
|
||||
assert!(from_str(r#""2016-07-08 09:10:48.090""#).is_err());
|
||||
assert!(from_str(r#""2016-007-08T09:10:48.090""#).is_err());
|
||||
assert!(from_str(r#""yyyy-mm-ddThh:mm:ss.fffffffff""#).is_err());
|
||||
assert!(from_str(r#"0"#).is_err());
|
||||
assert!(from_str(r#"20160708000000"#).is_err());
|
||||
assert!(from_str(r#"{}"#).is_err());
|
||||
// pre-0.3.0 rustc-serialize format is now invalid
|
||||
assert!(from_str(r#"{"date":{"ymdf":20},"time":{"secs":0,"frac":0}}"#).is_err());
|
||||
assert!(from_str(r#"null"#).is_err());
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
mod rustc_serialize {
|
||||
use super::NaiveDateTime;
|
||||
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
|
||||
// TODO the current serialization format is NEVER intentionally defined.
|
||||
// in the future it is likely to be redefined to more sane and reasonable format.
|
||||
|
||||
impl Encodable for NaiveDateTime {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
s.emit_struct("NaiveDateTime", 2, |s| {
|
||||
try!(s.emit_struct_field("date", 0, |s| self.date.encode(s)));
|
||||
try!(s.emit_struct_field("time", 1, |s| self.time.encode(s)));
|
||||
Ok(())
|
||||
})
|
||||
format!("{:?}", self).encode(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for NaiveDateTime {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<NaiveDateTime, D::Error> {
|
||||
d.read_struct("NaiveDateTime", 2, |d| {
|
||||
let date = try!(d.read_struct_field("date", 0, Decodable::decode));
|
||||
let time = try!(d.read_struct_field("time", 1, Decodable::decode));
|
||||
Ok(NaiveDateTime::new(date, time))
|
||||
})
|
||||
d.read_str()?.parse().map_err(|_| d.error("invalid date and time"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] use rustc_serialize::json;
|
||||
|
||||
#[test]
|
||||
fn test_encodable() {
|
||||
use naive::date::{self, NaiveDate};
|
||||
use rustc_serialize::json::encode;
|
||||
|
||||
assert_eq!(
|
||||
encode(&NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)).ok(),
|
||||
Some(r#"{"date":{"ymdf":16518115},"time":{"secs":33048,"frac":90000000}}"#.into()));
|
||||
assert_eq!(
|
||||
encode(&NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
|
||||
Some(r#"{"date":{"ymdf":16501977},"time":{"secs":45246,"frac":0}}"#.into()));
|
||||
assert_eq!(
|
||||
encode(&NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)).ok(),
|
||||
Some(r#"{"date":{"ymdf":20},"time":{"secs":59,"frac":1000000000}}"#.into()));
|
||||
assert_eq!(
|
||||
encode(&NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7)).ok(),
|
||||
Some(r#"{"date":{"ymdf":-2341},"time":{"secs":86399,"frac":7}}"#.into()));
|
||||
assert_eq!(
|
||||
encode(&date::MIN.and_hms(0, 0, 0)).ok(),
|
||||
Some(r#"{"date":{"ymdf":-2147483625},"time":{"secs":0,"frac":0}}"#.into()));
|
||||
assert_eq!(
|
||||
encode(&date::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)).ok(),
|
||||
Some(r#"{"date":{"ymdf":2147481311},"time":{"secs":86399,"frac":1999999999}}"#.into()));
|
||||
super::test_encodable_json(json::encode);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decodable() {
|
||||
use naive::date::{self, NaiveDate};
|
||||
use rustc_serialize::json;
|
||||
|
||||
let decode = |s: &str| json::decode::<NaiveDateTime>(s);
|
||||
|
||||
assert_eq!(
|
||||
decode(r#"{"date":{"ymdf":16518115},"time":{"secs":33048,"frac":90000000}}"#).ok(),
|
||||
Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)));
|
||||
assert_eq!(
|
||||
decode(r#"{"time":{"frac":0,"secs":45246},"date":{"ymdf":16501977}}"#).ok(),
|
||||
Some(NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6)));
|
||||
assert_eq!(
|
||||
decode(r#"{"date": {"ymdf": 20},
|
||||
"time": {"secs": 59,
|
||||
"frac": 1000000000}}"#).ok(),
|
||||
Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)));
|
||||
assert_eq!(
|
||||
decode(r#"{"date":{"ymdf":-2341},"time":{"secs":86399,"frac":7}}"#).ok(),
|
||||
Some(NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7)));
|
||||
assert_eq!(
|
||||
decode(r#"{"date":{"ymdf":-2147483625},"time":{"secs":0,"frac":0}}"#).ok(),
|
||||
Some(date::MIN.and_hms(0, 0, 0)));
|
||||
assert_eq!(
|
||||
decode(r#"{"date":{"ymdf":2147481311},"time":{"secs":86399,"frac":1999999999}}"#).ok(),
|
||||
Some(date::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)));
|
||||
|
||||
// bad formats
|
||||
assert!(decode(r#"{"date":{},"time":{}}"#).is_err());
|
||||
assert!(decode(r#"{"date":{"ymdf":0},"time":{"secs":0,"frac":0}}"#).is_err());
|
||||
assert!(decode(r#"{"date":{"ymdf":20},"time":{"secs":86400,"frac":0}}"#).is_err());
|
||||
assert!(decode(r#"{"date":{"ymdf":20},"time":{"secs":0,"frac":-1}}"#).is_err());
|
||||
assert!(decode(r#"{"date":20,"time":{"secs":0,"frac":0}}"#).is_err());
|
||||
assert!(decode(r#"{"date":"2016-08-04","time":"01:02:03.456"}"#).is_err());
|
||||
assert!(decode(r#"{"date":{"ymdf":20}}"#).is_err());
|
||||
assert!(decode(r#"{"time":{"secs":0,"frac":0}}"#).is_err());
|
||||
assert!(decode(r#"{"ymdf":20}"#).is_err());
|
||||
assert!(decode(r#"{"secs":0,"frac":0}"#).is_err());
|
||||
assert!(decode(r#"{}"#).is_err());
|
||||
assert!(decode(r#"0"#).is_err());
|
||||
assert!(decode(r#"-1"#).is_err());
|
||||
assert!(decode(r#""string""#).is_err());
|
||||
assert!(decode(r#""2016-08-04T12:34:56""#).is_err()); // :(
|
||||
assert!(decode(r#""2016-08-04T12:34:56.789""#).is_err()); // :(
|
||||
assert!(decode(r#"null"#).is_err());
|
||||
super::test_decodable_json(json::decode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1542,83 +1553,12 @@ mod serde {
|
|||
|
||||
#[test]
|
||||
fn test_serde_serialize() {
|
||||
use naive::date::{self, NaiveDate};
|
||||
use self::serde_json::to_string;
|
||||
|
||||
assert_eq!(
|
||||
to_string(&NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)).ok(),
|
||||
Some(r#""2016-07-08T09:10:48.090""#.into()));
|
||||
assert_eq!(
|
||||
to_string(&NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6)).ok(),
|
||||
Some(r#""2014-07-24T12:34:06""#.into()));
|
||||
assert_eq!(
|
||||
to_string(&NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)).ok(),
|
||||
Some(r#""0000-01-01T00:00:60""#.into()));
|
||||
assert_eq!(
|
||||
to_string(&NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7)).ok(),
|
||||
Some(r#""-0001-12-31T23:59:59.000000007""#.into()));
|
||||
assert_eq!(
|
||||
to_string(&date::MIN.and_hms(0, 0, 0)).ok(),
|
||||
Some(r#""-262144-01-01T00:00:00""#.into()));
|
||||
assert_eq!(
|
||||
to_string(&date::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)).ok(),
|
||||
Some(r#""+262143-12-31T23:59:60.999999999""#.into()));
|
||||
super::test_encodable_json(self::serde_json::to_string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_deserialize() {
|
||||
use naive::date::{self, NaiveDate};
|
||||
|
||||
let from_str = |s: &str| serde_json::from_str::<NaiveDateTime>(s);
|
||||
|
||||
assert_eq!(
|
||||
from_str(r#""2016-07-08T09:10:48.090""#).ok(),
|
||||
Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)));
|
||||
assert_eq!(
|
||||
from_str(r#""2016-7-8T9:10:48.09""#).ok(),
|
||||
Some(NaiveDate::from_ymd(2016, 7, 8).and_hms_milli(9, 10, 48, 90)));
|
||||
assert_eq!(
|
||||
from_str(r#""2014-07-24T12:34:06""#).ok(),
|
||||
Some(NaiveDate::from_ymd(2014, 7, 24).and_hms(12, 34, 6)));
|
||||
assert_eq!(
|
||||
from_str(r#""0000-01-01T00:00:60""#).ok(),
|
||||
Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)));
|
||||
assert_eq!(
|
||||
from_str(r#""0-1-1T0:0:60""#).ok(),
|
||||
Some(NaiveDate::from_ymd(0, 1, 1).and_hms_milli(0, 0, 59, 1_000)));
|
||||
assert_eq!(
|
||||
from_str(r#""-0001-12-31T23:59:59.000000007""#).ok(),
|
||||
Some(NaiveDate::from_ymd(-1, 12, 31).and_hms_nano(23, 59, 59, 7)));
|
||||
assert_eq!(
|
||||
from_str(r#""-262144-01-01T00:00:00""#).ok(),
|
||||
Some(date::MIN.and_hms(0, 0, 0)));
|
||||
assert_eq!(
|
||||
from_str(r#""+262143-12-31T23:59:60.999999999""#).ok(),
|
||||
Some(date::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)));
|
||||
assert_eq!(
|
||||
from_str(r#""+262143-12-31T23:59:60.9999999999997""#).ok(), // excess digits are ignored
|
||||
Some(date::MAX.and_hms_nano(23, 59, 59, 1_999_999_999)));
|
||||
|
||||
// bad formats
|
||||
assert!(from_str(r#""""#).is_err());
|
||||
assert!(from_str(r#""2016-07-08""#).is_err());
|
||||
assert!(from_str(r#""09:10:48.090""#).is_err());
|
||||
assert!(from_str(r#""20160708T091048.090""#).is_err());
|
||||
assert!(from_str(r#""2000-00-00T00:00:00""#).is_err());
|
||||
assert!(from_str(r#""2000-02-30T00:00:00""#).is_err());
|
||||
assert!(from_str(r#""2001-02-29T00:00:00""#).is_err());
|
||||
assert!(from_str(r#""2002-02-28T24:00:00""#).is_err());
|
||||
assert!(from_str(r#""2002-02-28T23:60:00""#).is_err());
|
||||
assert!(from_str(r#""2002-02-28T23:59:61""#).is_err());
|
||||
assert!(from_str(r#""2016-07-08T09:10:48,090""#).is_err());
|
||||
assert!(from_str(r#""2016-07-08 09:10:48.090""#).is_err());
|
||||
assert!(from_str(r#""2016-007-08T09:10:48.090""#).is_err());
|
||||
assert!(from_str(r#""yyyy-mm-ddThh:mm:ss.fffffffff""#).is_err());
|
||||
assert!(from_str(r#"0"#).is_err());
|
||||
assert!(from_str(r#"20160708000000"#).is_err());
|
||||
assert!(from_str(r#"{}"#).is_err());
|
||||
assert!(from_str(r#"{"date":{"ymdf":20},"time":{"secs":0,"frac":0}}"#).is_err()); // :(
|
||||
assert!(from_str(r#"null"#).is_err());
|
||||
super::test_decodable_json(self::serde_json::from_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -178,24 +178,6 @@ pub struct NaiveTime {
|
|||
}
|
||||
|
||||
impl NaiveTime {
|
||||
/// Makes a new `NaiveTime` from the serialized representation.
|
||||
/// Used for serialization formats.
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
fn from_serialized(secs: u32, frac: u32) -> Option<NaiveTime> {
|
||||
// check if the values are in the range
|
||||
if secs >= 86400 { return None; }
|
||||
if frac >= 2_000_000_000 { return None; }
|
||||
|
||||
let time = NaiveTime { secs: secs, frac: frac };
|
||||
Some(time)
|
||||
}
|
||||
|
||||
/// Returns a serialized representation of this `NaiveDate`.
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
fn to_serialized(&self) -> (u32, u32) {
|
||||
(self.secs, self.frac)
|
||||
}
|
||||
|
||||
/// Makes a new `NaiveTime` from hour, minute and second.
|
||||
///
|
||||
/// No [leap second](./index.html#leap-second-handling) is allowed here;
|
||||
|
@ -1285,95 +1267,99 @@ impl str::FromStr for NaiveTime {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
|
||||
fn test_encodable_json<F, E>(to_string: F)
|
||||
where F: Fn(&NaiveTime) -> Result<String, E>, E: ::std::fmt::Debug
|
||||
{
|
||||
assert_eq!(to_string(&NaiveTime::from_hms(0, 0, 0)).ok(),
|
||||
Some(r#""00:00:00""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms_milli(0, 0, 0, 950)).ok(),
|
||||
Some(r#""00:00:00.950""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms_milli(0, 0, 59, 1_000)).ok(),
|
||||
Some(r#""00:00:60""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms(0, 1, 2)).ok(),
|
||||
Some(r#""00:01:02""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms_nano(3, 5, 7, 98765432)).ok(),
|
||||
Some(r#""03:05:07.098765432""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms(7, 8, 9)).ok(),
|
||||
Some(r#""07:08:09""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms_micro(12, 34, 56, 789)).ok(),
|
||||
Some(r#""12:34:56.000789""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)).ok(),
|
||||
Some(r#""23:59:60.999999999""#.into()));
|
||||
}
|
||||
|
||||
#[cfg(all(test, any(feature = "rustc-serialize", feature = "serde")))]
|
||||
fn test_decodable_json<F, E>(from_str: F)
|
||||
where F: Fn(&str) -> Result<NaiveTime, E>, E: ::std::fmt::Debug
|
||||
{
|
||||
assert_eq!(from_str(r#""00:00:00""#).ok(),
|
||||
Some(NaiveTime::from_hms(0, 0, 0)));
|
||||
assert_eq!(from_str(r#""0:0:0""#).ok(),
|
||||
Some(NaiveTime::from_hms(0, 0, 0)));
|
||||
assert_eq!(from_str(r#""00:00:00.950""#).ok(),
|
||||
Some(NaiveTime::from_hms_milli(0, 0, 0, 950)));
|
||||
assert_eq!(from_str(r#""0:0:0.95""#).ok(),
|
||||
Some(NaiveTime::from_hms_milli(0, 0, 0, 950)));
|
||||
assert_eq!(from_str(r#""00:00:60""#).ok(),
|
||||
Some(NaiveTime::from_hms_milli(0, 0, 59, 1_000)));
|
||||
assert_eq!(from_str(r#""00:01:02""#).ok(),
|
||||
Some(NaiveTime::from_hms(0, 1, 2)));
|
||||
assert_eq!(from_str(r#""03:05:07.098765432""#).ok(),
|
||||
Some(NaiveTime::from_hms_nano(3, 5, 7, 98765432)));
|
||||
assert_eq!(from_str(r#""07:08:09""#).ok(),
|
||||
Some(NaiveTime::from_hms(7, 8, 9)));
|
||||
assert_eq!(from_str(r#""12:34:56.000789""#).ok(),
|
||||
Some(NaiveTime::from_hms_micro(12, 34, 56, 789)));
|
||||
assert_eq!(from_str(r#""23:59:60.999999999""#).ok(),
|
||||
Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)));
|
||||
assert_eq!(from_str(r#""23:59:60.9999999999997""#).ok(), // excess digits are ignored
|
||||
Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)));
|
||||
|
||||
// bad formats
|
||||
assert!(from_str(r#""""#).is_err());
|
||||
assert!(from_str(r#""000000""#).is_err());
|
||||
assert!(from_str(r#""00:00:61""#).is_err());
|
||||
assert!(from_str(r#""00:60:00""#).is_err());
|
||||
assert!(from_str(r#""24:00:00""#).is_err());
|
||||
assert!(from_str(r#""23:59:59,1""#).is_err());
|
||||
assert!(from_str(r#""012:34:56""#).is_err());
|
||||
assert!(from_str(r#""hh:mm:ss""#).is_err());
|
||||
assert!(from_str(r#"0"#).is_err());
|
||||
assert!(from_str(r#"86399"#).is_err());
|
||||
assert!(from_str(r#"{}"#).is_err());
|
||||
// pre-0.3.0 rustc-serialize format is now invalid
|
||||
assert!(from_str(r#"{"secs":0,"frac":0}"#).is_err());
|
||||
assert!(from_str(r#"null"#).is_err());
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
mod rustc_serialize {
|
||||
use super::NaiveTime;
|
||||
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
|
||||
// TODO the current serialization format is NEVER intentionally defined.
|
||||
// this basically follows the automatically generated implementation for those traits,
|
||||
// plus manual verification steps for avoiding security problem.
|
||||
// in the future it is likely to be redefined to more sane and reasonable format.
|
||||
|
||||
impl Encodable for NaiveTime {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
let (secs, frac) = self.to_serialized();
|
||||
s.emit_struct("NaiveTime", 2, |s| {
|
||||
try!(s.emit_struct_field("secs", 0, |s| secs.encode(s)));
|
||||
try!(s.emit_struct_field("frac", 1, |s| frac.encode(s)));
|
||||
Ok(())
|
||||
})
|
||||
format!("{:?}", self).encode(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for NaiveTime {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<NaiveTime, D::Error> {
|
||||
d.read_struct("NaiveTime", 2, |d| {
|
||||
let secs = try!(d.read_struct_field("secs", 0, Decodable::decode));
|
||||
let frac = try!(d.read_struct_field("frac", 1, Decodable::decode));
|
||||
NaiveTime::from_serialized(secs, frac).ok_or_else(|| d.error("invalid time"))
|
||||
})
|
||||
d.read_str()?.parse().map_err(|_| d.error("invalid time"))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)] use rustc_serialize::json;
|
||||
|
||||
#[test]
|
||||
fn test_encodable() {
|
||||
use rustc_serialize::json::encode;
|
||||
|
||||
assert_eq!(encode(&NaiveTime::from_hms(0, 0, 0)).ok(),
|
||||
Some(r#"{"secs":0,"frac":0}"#.into()));
|
||||
assert_eq!(encode(&NaiveTime::from_hms_milli(0, 0, 0, 950)).ok(),
|
||||
Some(r#"{"secs":0,"frac":950000000}"#.into()));
|
||||
assert_eq!(encode(&NaiveTime::from_hms_milli(0, 0, 59, 1_000)).ok(),
|
||||
Some(r#"{"secs":59,"frac":1000000000}"#.into()));
|
||||
assert_eq!(encode(&NaiveTime::from_hms(0, 1, 2)).ok(),
|
||||
Some(r#"{"secs":62,"frac":0}"#.into()));
|
||||
assert_eq!(encode(&NaiveTime::from_hms(7, 8, 9)).ok(),
|
||||
Some(r#"{"secs":25689,"frac":0}"#.into()));
|
||||
assert_eq!(encode(&NaiveTime::from_hms_micro(12, 34, 56, 789)).ok(),
|
||||
Some(r#"{"secs":45296,"frac":789000}"#.into()));
|
||||
assert_eq!(encode(&NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)).ok(),
|
||||
Some(r#"{"secs":86399,"frac":1999999999}"#.into()));
|
||||
super::test_encodable_json(json::encode);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decodable() {
|
||||
use rustc_serialize::json;
|
||||
|
||||
let decode = |s: &str| json::decode::<NaiveTime>(s);
|
||||
|
||||
assert_eq!(decode(r#"{"secs":0,"frac":0}"#).ok(),
|
||||
Some(NaiveTime::from_hms(0, 0, 0)));
|
||||
assert_eq!(decode(r#"{"frac":950000000,"secs":0}"#).ok(),
|
||||
Some(NaiveTime::from_hms_milli(0, 0, 0, 950)));
|
||||
assert_eq!(decode(r#"{"secs":59,"frac":1000000000}"#).ok(),
|
||||
Some(NaiveTime::from_hms_milli(0, 0, 59, 1_000)));
|
||||
assert_eq!(decode(r#"{"frac": 0,
|
||||
"secs": 62}"#).ok(),
|
||||
Some(NaiveTime::from_hms(0, 1, 2)));
|
||||
assert_eq!(decode(r#"{"secs":25689,"frac":0}"#).ok(),
|
||||
Some(NaiveTime::from_hms(7, 8, 9)));
|
||||
assert_eq!(decode(r#"{"secs":45296,"frac":789000}"#).ok(),
|
||||
Some(NaiveTime::from_hms_micro(12, 34, 56, 789)));
|
||||
assert_eq!(decode(r#"{"secs":86399,"frac":1999999999}"#).ok(),
|
||||
Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)));
|
||||
|
||||
// bad formats
|
||||
assert!(decode(r#"{"secs":0,"frac":-1}"#).is_err());
|
||||
assert!(decode(r#"{"secs":-1,"frac":0}"#).is_err());
|
||||
assert!(decode(r#"{"secs":86400,"frac":0}"#).is_err());
|
||||
assert!(decode(r#"{"secs":0,"frac":2000000000}"#).is_err());
|
||||
assert!(decode(r#"{"secs":0}"#).is_err());
|
||||
assert!(decode(r#"{"frac":0}"#).is_err());
|
||||
assert!(decode(r#"{"secs":0.3,"frac":0}"#).is_err());
|
||||
assert!(decode(r#"{"secs":0,"frac":0.4}"#).is_err());
|
||||
assert!(decode(r#"{}"#).is_err());
|
||||
assert!(decode(r#"0"#).is_err());
|
||||
assert!(decode(r#"86399"#).is_err());
|
||||
assert!(decode(r#""string""#).is_err());
|
||||
assert!(decode(r#""12:34:56""#).is_err()); // :(
|
||||
assert!(decode(r#""12:34:56.789""#).is_err()); // :(
|
||||
assert!(decode(r#"null"#).is_err());
|
||||
super::test_decodable_json(json::decode);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1424,67 +1410,12 @@ mod serde {
|
|||
|
||||
#[test]
|
||||
fn test_serde_serialize() {
|
||||
use self::serde_json::to_string;
|
||||
|
||||
assert_eq!(to_string(&NaiveTime::from_hms(0, 0, 0)).ok(),
|
||||
Some(r#""00:00:00""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms_milli(0, 0, 0, 950)).ok(),
|
||||
Some(r#""00:00:00.950""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms_milli(0, 0, 59, 1_000)).ok(),
|
||||
Some(r#""00:00:60""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms(0, 1, 2)).ok(),
|
||||
Some(r#""00:01:02""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms_nano(3, 5, 7, 98765432)).ok(),
|
||||
Some(r#""03:05:07.098765432""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms(7, 8, 9)).ok(),
|
||||
Some(r#""07:08:09""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms_micro(12, 34, 56, 789)).ok(),
|
||||
Some(r#""12:34:56.000789""#.into()));
|
||||
assert_eq!(to_string(&NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)).ok(),
|
||||
Some(r#""23:59:60.999999999""#.into()));
|
||||
super::test_encodable_json(self::serde_json::to_string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serde_deserialize() {
|
||||
let from_str = |s: &str| serde_json::from_str::<NaiveTime>(s);
|
||||
|
||||
assert_eq!(from_str(r#""00:00:00""#).ok(),
|
||||
Some(NaiveTime::from_hms(0, 0, 0)));
|
||||
assert_eq!(from_str(r#""0:0:0""#).ok(),
|
||||
Some(NaiveTime::from_hms(0, 0, 0)));
|
||||
assert_eq!(from_str(r#""00:00:00.950""#).ok(),
|
||||
Some(NaiveTime::from_hms_milli(0, 0, 0, 950)));
|
||||
assert_eq!(from_str(r#""0:0:0.95""#).ok(),
|
||||
Some(NaiveTime::from_hms_milli(0, 0, 0, 950)));
|
||||
assert_eq!(from_str(r#""00:00:60""#).ok(),
|
||||
Some(NaiveTime::from_hms_milli(0, 0, 59, 1_000)));
|
||||
assert_eq!(from_str(r#""00:01:02""#).ok(),
|
||||
Some(NaiveTime::from_hms(0, 1, 2)));
|
||||
assert_eq!(from_str(r#""03:05:07.098765432""#).ok(),
|
||||
Some(NaiveTime::from_hms_nano(3, 5, 7, 98765432)));
|
||||
assert_eq!(from_str(r#""07:08:09""#).ok(),
|
||||
Some(NaiveTime::from_hms(7, 8, 9)));
|
||||
assert_eq!(from_str(r#""12:34:56.000789""#).ok(),
|
||||
Some(NaiveTime::from_hms_micro(12, 34, 56, 789)));
|
||||
assert_eq!(from_str(r#""23:59:60.999999999""#).ok(),
|
||||
Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)));
|
||||
assert_eq!(from_str(r#""23:59:60.9999999999997""#).ok(), // excess digits are ignored
|
||||
Some(NaiveTime::from_hms_nano(23, 59, 59, 1_999_999_999)));
|
||||
|
||||
// bad formats
|
||||
assert!(from_str(r#""""#).is_err());
|
||||
assert!(from_str(r#""000000""#).is_err());
|
||||
assert!(from_str(r#""00:00:61""#).is_err());
|
||||
assert!(from_str(r#""00:60:00""#).is_err());
|
||||
assert!(from_str(r#""24:00:00""#).is_err());
|
||||
assert!(from_str(r#""23:59:59,1""#).is_err());
|
||||
assert!(from_str(r#""012:34:56""#).is_err());
|
||||
assert!(from_str(r#""hh:mm:ss""#).is_err());
|
||||
assert!(from_str(r#"0"#).is_err());
|
||||
assert!(from_str(r#"86399"#).is_err());
|
||||
assert!(from_str(r#"{}"#).is_err());
|
||||
assert!(from_str(r#"{"secs":0,"frac":0}"#).is_err()); // :(
|
||||
assert!(from_str(r#"null"#).is_err());
|
||||
super::test_decodable_json(self::serde_json::from_str);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -23,23 +23,6 @@ pub struct FixedOffset {
|
|||
}
|
||||
|
||||
impl FixedOffset {
|
||||
/// Makes a new `FixedOffset` from the serialized representation.
|
||||
/// Used for serialization formats.
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
fn from_serialized(secs: i32) -> Option<FixedOffset> {
|
||||
// check if the values are in the range
|
||||
if secs <= -86400 || 86400 <= secs { return None; }
|
||||
|
||||
let offset = FixedOffset { local_minus_utc: secs };
|
||||
Some(offset)
|
||||
}
|
||||
|
||||
/// Returns a serialized representation of this `FixedOffset`.
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
fn to_serialized(&self) -> i32 {
|
||||
self.local_minus_utc
|
||||
}
|
||||
|
||||
/// Makes a new `FixedOffset` for the Eastern Hemisphere with given timezone difference.
|
||||
/// The negative `secs` means the Western Hemisphere.
|
||||
///
|
||||
|
@ -139,72 +122,3 @@ impl fmt::Display for FixedOffset {
|
|||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(self, f) }
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustc-serialize")]
|
||||
mod rustc_serialize {
|
||||
use super::FixedOffset;
|
||||
use rustc_serialize::{Encodable, Encoder, Decodable, Decoder};
|
||||
|
||||
// TODO the current serialization format is NEVER intentionally defined.
|
||||
// this basically follows the automatically generated implementation for those traits,
|
||||
// plus manual verification steps for avoiding security problem.
|
||||
// in the future it is likely to be redefined to more sane and reasonable format.
|
||||
|
||||
impl Encodable for FixedOffset {
|
||||
fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
|
||||
let secs = self.to_serialized();
|
||||
s.emit_struct("FixedOffset", 1, |s| {
|
||||
try!(s.emit_struct_field("local_minus_utc", 0, |s| secs.encode(s)));
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Decodable for FixedOffset {
|
||||
fn decode<D: Decoder>(d: &mut D) -> Result<FixedOffset, D::Error> {
|
||||
d.read_struct("FixedOffset", 1, |d| {
|
||||
let secs = try!(d.read_struct_field("local_minus_utc", 0, Decodable::decode));
|
||||
FixedOffset::from_serialized(secs).ok_or_else(|| d.error("invalid offset"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_encodable() {
|
||||
use rustc_serialize::json::encode;
|
||||
|
||||
assert_eq!(encode(&FixedOffset::east(0)).ok(),
|
||||
Some(r#"{"local_minus_utc":0}"#.into()));
|
||||
assert_eq!(encode(&FixedOffset::east(1234)).ok(),
|
||||
Some(r#"{"local_minus_utc":1234}"#.into()));
|
||||
assert_eq!(encode(&FixedOffset::east(86399)).ok(),
|
||||
Some(r#"{"local_minus_utc":86399}"#.into()));
|
||||
assert_eq!(encode(&FixedOffset::west(1234)).ok(),
|
||||
Some(r#"{"local_minus_utc":-1234}"#.into()));
|
||||
assert_eq!(encode(&FixedOffset::west(86399)).ok(),
|
||||
Some(r#"{"local_minus_utc":-86399}"#.into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_decodable() {
|
||||
use rustc_serialize::json;
|
||||
|
||||
let decode = |s: &str| json::decode::<FixedOffset>(s);
|
||||
|
||||
assert_eq!(decode(r#"{"local_minus_utc":0}"#).ok(), Some(FixedOffset::east(0)));
|
||||
assert_eq!(decode(r#"{"local_minus_utc": 1234}"#).ok(), Some(FixedOffset::east(1234)));
|
||||
assert_eq!(decode(r#"{"local_minus_utc":86399}"#).ok(), Some(FixedOffset::east(86399)));
|
||||
assert_eq!(decode(r#"{"local_minus_utc":-1234}"#).ok(), Some(FixedOffset::west(1234)));
|
||||
assert_eq!(decode(r#"{"local_minus_utc":-86399}"#).ok(), Some(FixedOffset::west(86399)));
|
||||
|
||||
assert!(decode(r#"{"local_minus_utc":86400}"#).is_err());
|
||||
assert!(decode(r#"{"local_minus_utc":-86400}"#).is_err());
|
||||
assert!(decode(r#"{"local_minus_utc":0.1}"#).is_err());
|
||||
assert!(decode(r#"{"local_minus_utc":null}"#).is_err());
|
||||
assert!(decode(r#"{}"#).is_err());
|
||||
assert!(decode(r#"0"#).is_err());
|
||||
assert!(decode(r#"1234"#).is_err());
|
||||
assert!(decode(r#""string""#).is_err());
|
||||
assert!(decode(r#"null"#).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,6 @@ fn datetime_to_timespec(d: &NaiveDateTime, local: bool) -> oldtime::Timespec {
|
|||
/// let dt: DateTime<Local> = Local.timestamp(0, 0);
|
||||
/// ~~~~
|
||||
#[derive(Copy, Clone)]
|
||||
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
|
||||
pub struct Local;
|
||||
|
||||
impl Local {
|
||||
|
|
|
@ -33,7 +33,6 @@ use super::{TimeZone, Offset, LocalResult};
|
|||
/// assert_eq!(UTC.ymd(1970, 1, 1).and_hms(0, 1, 1), dt);
|
||||
/// ~~~~
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "rustc-serialize", derive(RustcEncodable, RustcDecodable))]
|
||||
pub struct UTC;
|
||||
|
||||
impl UTC {
|
||||
|
|
Loading…
Reference in New Issue