implemented `FromStr` for `DateTime<FixedOffset/UTC>`.

This commit is contained in:
Kang Seonghoon 2015-02-19 00:00:33 +09:00
parent 76b0873722
commit 46996e35e1
2 changed files with 79 additions and 11 deletions

View File

@ -6,17 +6,18 @@
* ISO 8601 date and time.
*/
use std::{fmt, hash};
use std::{str, fmt, hash};
use std::cmp::Ordering;
use std::ops::{Add, Sub};
use {Weekday, Timelike, Datelike};
use offset::{Offset, FixedOffset};
use offset::{Offset, FixedOffset, UTC};
use duration::Duration;
use naive::datetime::NaiveDateTime;
use time::Time;
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.
#[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)]
mod tests {
use super::DateTime;
@ -294,6 +334,21 @@ mod tests {
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]
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);

View File

@ -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");
~~~~
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
returns `DateTime<FixedOffset>`.
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.
1. The standard `FromStr` trait (and `parse` method on a string) can be used for
parsing `DateTime<FixedOffset>` and `DateTime<UTC>` values.
This parses what the `{:?}` (`std::fmt::Debug`) format specifier prints,
and requires the offset to be present.
- `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.
2. `DateTime::parse_from_str` parses a date and time with offsets and
returns `DateTime<FixedOffset>`.
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.
@ -163,8 +168,16 @@ More detailed control over the parsing process is available via `format` module.
use chrono::{UTC, Offset, DateTime};
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("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",
"%Y-%m-%d %H:%M:%S %z").map(|dt| dt.with_offset(UTC)), Ok(dt));