added `parse_from_rfc{2822,3339}`/`to_rfc{2822,3339}` methods to DateTime.

This commit is contained in:
Kang Seonghoon 2015-02-19 04:57:21 +09:00
parent 82c9345a4d
commit 30322bbc89
2 changed files with 62 additions and 1 deletions

View File

@ -123,6 +123,27 @@ fn map_local<Tz: TimeZone, F>(dt: &DateTime<Tz>, mut f: F) -> Option<DateTime<Tz
} }
impl DateTime<FixedOffset> { impl DateTime<FixedOffset> {
/// Parses an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`,
/// then returns a new `DateTime` with a parsed `FixedOffset`.
pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
let mut parsed = Parsed::new();
try!(parse(&mut parsed, s, ITEMS.iter().cloned()));
parsed.to_datetime()
}
/// Parses an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`,
/// then returns a new `DateTime` with a parsed `FixedOffset`.
///
/// Why isn't this named `parse_from_iso8601`? That's because ISO 8601 allows some freedom
/// over the syntax and RFC 3339 exercises that freedom to rigidly define a fixed format.
pub fn parse_from_rfc3339(s: &str) -> ParseResult<DateTime<FixedOffset>> {
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
let mut parsed = Parsed::new();
try!(parse(&mut parsed, s, ITEMS.iter().cloned()));
parsed.to_datetime()
}
/// Parses a string with the specified format string and /// Parses a string with the specified format string and
/// returns a new `DateTime` with a parsed `FixedOffset`. /// returns a new `DateTime` with a parsed `FixedOffset`.
/// See the `format::strftime` module on the supported escape sequences. /// See the `format::strftime` module on the supported escape sequences.
@ -136,6 +157,18 @@ impl DateTime<FixedOffset> {
} }
impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display { impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display {
/// Returns an RFC 2822 date and time string such as `Tue, 1 Jul 2003 10:52:37 +0200`.
pub fn to_rfc2822(&self) -> String {
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
self.format_with_items(ITEMS.iter().cloned()).to_string()
}
/// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
pub fn to_rfc3339(&self) -> String {
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
self.format_with_items(ITEMS.iter().cloned()).to_string()
}
/// Formats the combined date and time with the specified formatting items. /// Formats the combined date and time with the specified formatting items.
#[inline] #[inline]
pub fn format_with_items<'a, I>(&'a self, items: I) -> DelayedFormat<'a, I> pub fn format_with_items<'a, I>(&'a self, items: I) -> DelayedFormat<'a, I>
@ -370,6 +403,33 @@ mod tests {
NaiveTime::from_hms(7, 8, 9)); NaiveTime::from_hms(7, 8, 9));
} }
#[test]
#[allow(non_snake_case)]
fn test_datetime_rfc2822_and_rfc3339() {
let EDT = FixedOffset::east(5*60*60);
assert_eq!(UTC.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc2822(),
"Wed, 18 Feb 2015 23:16:09 +0000");
assert_eq!(UTC.ymd(2015, 2, 18).and_hms(23, 16, 9).to_rfc3339(),
"2015-02-18T23:16:09+00:00");
assert_eq!(EDT.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc2822(),
"Wed, 18 Feb 2015 23:16:09 +0500");
assert_eq!(EDT.ymd(2015, 2, 18).and_hms_milli(23, 16, 9, 150).to_rfc3339(),
"2015-02-18T23:16:09.150+05:00");
assert_eq!(EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc2822(),
"Wed, 18 Feb 2015 23:59:60 +0500");
assert_eq!(EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567).to_rfc3339(),
"2015-02-18T23:59:60.234567+05:00");
assert_eq!(DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:16:09 +0000"),
Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)));
assert_eq!(DateTime::parse_from_rfc3339("2015-02-18T23:16:09Z"),
Ok(FixedOffset::east(0).ymd(2015, 2, 18).and_hms(23, 16, 9)));
assert_eq!(DateTime::parse_from_rfc2822("Wed, 18 Feb 2015 23:59:60 +0500"),
Ok(EDT.ymd(2015, 2, 18).and_hms_milli(23, 59, 59, 1_000)));
assert_eq!(DateTime::parse_from_rfc3339("2015-02-18T23:59:60.234567+05:00"),
Ok(EDT.ymd(2015, 2, 18).and_hms_micro(23, 59, 59, 1_234_567)));
}
#[test] #[test]
fn test_datetime_from_str() { fn test_datetime_from_str() {
assert_eq!("2015-2-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(), assert_eq!("2015-2-18T23:16:9.15Z".parse::<DateTime<FixedOffset>>(),

View File

@ -366,10 +366,11 @@ pub fn format<'a, I>(w: &mut fmt::Formatter, date: Option<&NaiveDate>, time: Opt
off.map(|&(_, off)| write_local_minus_utc(w, off, true, false)), off.map(|&(_, off)| write_local_minus_utc(w, off, true, false)),
RFC2822 => // same to `%a, %e %b %Y %H:%M:%S %z` RFC2822 => // same to `%a, %e %b %Y %H:%M:%S %z`
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) { if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
let sec = t.second() + t.nanosecond() / 1_000_000_000;
try!(write!(w, "{}, {:2} {} {:04} {:02}:{:02}:{:02} ", try!(write!(w, "{}, {:2} {} {:04} {:02}:{:02}:{:02} ",
SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as usize], SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as usize],
d.day(), SHORT_MONTHS[d.month0() as usize], d.year(), d.day(), SHORT_MONTHS[d.month0() as usize], d.year(),
t.hour(), t.minute(), t.second())); t.hour(), t.minute(), sec));
Some(write_local_minus_utc(w, off, false, false)) Some(write_local_minus_utc(w, off, false, false))
} else { } else {
None None