implemented `FromStr` for `DateTime<FixedOffset/UTC>`.
This commit is contained in:
parent
76b0873722
commit
46996e35e1
|
@ -6,17 +6,18 @@
|
||||||
* ISO 8601 date and time.
|
* ISO 8601 date and time.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::{fmt, hash};
|
use std::{str, fmt, hash};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::ops::{Add, Sub};
|
use std::ops::{Add, Sub};
|
||||||
|
|
||||||
use {Weekday, Timelike, Datelike};
|
use {Weekday, Timelike, Datelike};
|
||||||
use offset::{Offset, FixedOffset};
|
use offset::{Offset, FixedOffset, UTC};
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use naive::datetime::NaiveDateTime;
|
use naive::datetime::NaiveDateTime;
|
||||||
use time::Time;
|
use time::Time;
|
||||||
use date::Date;
|
use date::Date;
|
||||||
use format::{parse, Item, Parsed, ParseResult, DelayedFormat, StrftimeItems};
|
use format::{Item, Numeric, Pad, Fixed};
|
||||||
|
use format::{parse, Parsed, ParseError, ParseResult, DelayedFormat, StrftimeItems};
|
||||||
|
|
||||||
/// ISO 8601 combined date and time with timezone.
|
/// ISO 8601 combined date and time with timezone.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -261,6 +262,45 @@ impl<Off: Offset + fmt::Display> fmt::Display for DateTime<Off> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl str::FromStr for DateTime<FixedOffset> {
|
||||||
|
type Err = ParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||||
|
const ITEMS: &'static [Item<'static>] = &[
|
||||||
|
Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero),
|
||||||
|
Item::Space(""), Item::Literal("-"),
|
||||||
|
Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero),
|
||||||
|
Item::Space(""), Item::Literal("-"),
|
||||||
|
Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero),
|
||||||
|
Item::Space(""), Item::Literal("T"), // XXX shouldn't this be case-insensitive?
|
||||||
|
Item::Space(""), Item::Numeric(Numeric::Hour, Pad::Zero),
|
||||||
|
Item::Space(""), Item::Literal(":"),
|
||||||
|
Item::Space(""), Item::Numeric(Numeric::Minute, Pad::Zero),
|
||||||
|
Item::Space(""), Item::Literal(":"),
|
||||||
|
Item::Space(""), Item::Numeric(Numeric::Second, Pad::Zero),
|
||||||
|
Item::Fixed(Fixed::Nanosecond),
|
||||||
|
Item::Space(""), Item::Fixed(Fixed::TimezoneOffsetZ),
|
||||||
|
Item::Space(""),
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut parsed = Parsed::new();
|
||||||
|
try!(parse(&mut parsed, s, ITEMS.iter().cloned()));
|
||||||
|
parsed.to_datetime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl str::FromStr for DateTime<UTC> {
|
||||||
|
type Err = ParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> ParseResult<DateTime<UTC>> {
|
||||||
|
// we parse non-UTC time zones then convert them into UTC
|
||||||
|
let dt: DateTime<FixedOffset> = try!(s.parse());
|
||||||
|
Ok(dt.with_offset(UTC))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: FromStr for DateTime<Local> is quite hard without a new offset design
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::DateTime;
|
use super::DateTime;
|
||||||
|
@ -294,6 +334,21 @@ mod tests {
|
||||||
assert!(*EDT.ymd(2014, 5, 6).and_hms(7, 8, 9).offset() != EST);
|
assert!(*EDT.ymd(2014, 5, 6).and_hms(7, 8, 9).offset() != EST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_datetime_from_str() {
|
||||||
|
assert_eq!("2015-2-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),
|
||||||
|
Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)));
|
||||||
|
assert_eq!("2015-2-18T13:16:9.15-10:00".parse::<DateTime<FixedOffset>>(),
|
||||||
|
Ok(FixedOffset::west(10 * 3600).ymd(2015, 2, 18).and_hms_milli(13, 16, 9, 150)));
|
||||||
|
assert!("2015-2-18T23:16:9.15".parse::<DateTime<FixedOffset>>().is_err());
|
||||||
|
|
||||||
|
assert_eq!("2015-2-18T23:16:9.15Z".parse::<DateTime<UTC>>(),
|
||||||
|
Ok(UTC.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)));
|
||||||
|
assert_eq!("2015-2-18T13:16:9.15-10:00".parse::<DateTime<UTC>>(),
|
||||||
|
Ok(UTC.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150)));
|
||||||
|
assert!("2015-2-18T23:16:9.15".parse::<DateTime<UTC>>().is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_parse_from_str() {
|
fn test_datetime_parse_from_str() {
|
||||||
let ymdhms = |&: y,m,d,h,n,s,off| FixedOffset::east(off).ymd(y,m,d).and_hms(h,n,s);
|
let ymdhms = |&: y,m,d,h,n,s,off| FixedOffset::east(off).ymd(y,m,d).and_hms(h,n,s);
|
||||||
|
|
29
src/lib.rs
29
src/lib.rs
|
@ -146,16 +146,21 @@ assert_eq!(dt.to_string(), "2014-11-28 12:00:09 UTC");
|
||||||
assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z");
|
assert_eq!(format!("{:?}", dt), "2014-11-28T12:00:09Z");
|
||||||
~~~~
|
~~~~
|
||||||
|
|
||||||
Parsing can be done with two methods:
|
Parsing can be done with three methods:
|
||||||
|
|
||||||
- `DateTime::parse_from_str` parses a date and time with offsets and
|
1. The standard `FromStr` trait (and `parse` method on a string) can be used for
|
||||||
returns `DateTime<FixedOffset>`.
|
parsing `DateTime<FixedOffset>` and `DateTime<UTC>` values.
|
||||||
This should be used when the offset is a part of input and the caller cannot guess that.
|
This parses what the `{:?}` (`std::fmt::Debug`) format specifier prints,
|
||||||
It *cannot* be used when the offset can be missing.
|
and requires the offset to be present.
|
||||||
|
|
||||||
- `Offset::datetime_from_str` is similar but returns `DateTime` of given offset.
|
2. `DateTime::parse_from_str` parses a date and time with offsets and
|
||||||
When the explicit offset is missing from the input, it simply uses given offset.
|
returns `DateTime<FixedOffset>`.
|
||||||
It issues an error when the input contains an explicit offset different from the current offset.
|
This should be used when the offset is a part of input and the caller cannot guess that.
|
||||||
|
It *cannot* be used when the offset can be missing.
|
||||||
|
|
||||||
|
3. `Offset::datetime_from_str` is similar but returns `DateTime` of given offset.
|
||||||
|
When the explicit offset is missing from the input, it simply uses given offset.
|
||||||
|
It issues an error when the input contains an explicit offset different from the current offset.
|
||||||
|
|
||||||
More detailed control over the parsing process is available via `format` module.
|
More detailed control over the parsing process is available via `format` module.
|
||||||
|
|
||||||
|
@ -163,8 +168,16 @@ More detailed control over the parsing process is available via `format` module.
|
||||||
use chrono::{UTC, Offset, DateTime};
|
use chrono::{UTC, Offset, DateTime};
|
||||||
|
|
||||||
let dt = UTC.ymd(2014, 11, 28).and_hms(12, 0, 9);
|
let dt = UTC.ymd(2014, 11, 28).and_hms(12, 0, 9);
|
||||||
|
|
||||||
|
// method 1
|
||||||
|
assert_eq!("2014-11-28T12:00:09Z".parse::<DateTime<UTC>>(), Ok(dt.clone()));
|
||||||
|
assert_eq!("2014-11-28T21:00:09+09:00".parse::<DateTime<UTC>>(), Ok(dt.clone()));
|
||||||
|
|
||||||
|
// method 2
|
||||||
assert_eq!(UTC.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone()));
|
assert_eq!(UTC.datetime_from_str("2014-11-28 12:00:09", "%Y-%m-%d %H:%M:%S"), Ok(dt.clone()));
|
||||||
assert_eq!(UTC.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone()));
|
assert_eq!(UTC.datetime_from_str("Fri Nov 28 12:00:09 2014", "%a %b %e %T %Y"), Ok(dt.clone()));
|
||||||
|
|
||||||
|
// method 3
|
||||||
assert_eq!(DateTime::parse_from_str("2014-11-28 21:00:09 +09:00",
|
assert_eq!(DateTime::parse_from_str("2014-11-28 21:00:09 +09:00",
|
||||||
"%Y-%m-%d %H:%M:%S %z").map(|dt| dt.with_offset(UTC)), Ok(dt));
|
"%Y-%m-%d %H:%M:%S %z").map(|dt| dt.with_offset(UTC)), Ok(dt));
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue