public interfaces for parser are now available.
This commit is contained in:
parent
9768b57494
commit
7eb9a1a983
|
@ -11,12 +11,12 @@ 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;
|
use offset::{Offset, FixedOffset};
|
||||||
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::{DelayedFormat, StrftimeItems};
|
use format::{parse, Parsed, ParseResult, DelayedFormat, StrftimeItems};
|
||||||
|
|
||||||
/// ISO 8601 combined date and time with timezone.
|
/// ISO 8601 combined date and time with timezone.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -88,6 +88,19 @@ impl<Off:Offset> DateTime<Off> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DateTime<FixedOffset> {
|
||||||
|
/// Parses a string with the specified format string and
|
||||||
|
/// returns a new `DateTime` with a parsed `FixedOffset`.
|
||||||
|
/// See the `format::strftime` module on the supported escape sequences.
|
||||||
|
///
|
||||||
|
/// See also `Offset::datetime_from_str` which gives a local `DateTime` on specific time zone.
|
||||||
|
pub fn from_str(s: &str, fmt: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||||
|
let mut parsed = Parsed::new();
|
||||||
|
try!(parse(&mut parsed, s, StrftimeItems::new(fmt)));
|
||||||
|
parsed.to_datetime()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<Off: Offset + fmt::Display> DateTime<Off> {
|
impl<Off: Offset + fmt::Display> DateTime<Off> {
|
||||||
/// Formats the combined date and time in the specified format string.
|
/// Formats the combined date and time in the specified format string.
|
||||||
/// See the `format::strftime` module on the supported escape sequences.
|
/// See the `format::strftime` module on the supported escape sequences.
|
||||||
|
@ -244,7 +257,8 @@ impl<Off: Offset + fmt::Display> fmt::Display for DateTime<Off> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use {Datelike};
|
use super::DateTime;
|
||||||
|
use Datelike;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use offset::{Offset, UTC, Local, FixedOffset};
|
use offset::{Offset, UTC, Local, FixedOffset};
|
||||||
|
|
||||||
|
@ -275,7 +289,20 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_fmt_with_local() {
|
fn test_datetime_from_str() {
|
||||||
|
let ymdhms = |&: y,m,d,h,n,s,off| FixedOffset::east(off).ymd(y,m,d).and_hms(h,n,s);
|
||||||
|
assert_eq!(DateTime::from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
|
||||||
|
Ok(ymdhms(2014, 5, 7, 12, 34, 56, 570*60))); // ignore offset
|
||||||
|
assert!(DateTime::from_str("20140507000000", "%Y%m%d%H%M%S").is_err()); // no offset
|
||||||
|
assert!(DateTime::from_str("Fri, 09 Aug 2013 23:54:35 GMT",
|
||||||
|
"%a, %d %b %Y %H:%M:%S GMT").is_err());
|
||||||
|
assert_eq!(UTC.datetime_from_str("Fri, 09 Aug 2013 23:54:35 GMT",
|
||||||
|
"%a, %d %b %Y %H:%M:%S GMT"),
|
||||||
|
Ok(UTC.ymd(2013, 8, 9).and_hms(23, 54, 35)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_datetime_format_with_local() {
|
||||||
// if we are not around the year boundary, local and UTC date should have the same year
|
// if we are not around the year boundary, local and UTC date should have the same year
|
||||||
let dt = Local::now().with_month(5).unwrap();
|
let dt = Local::now().with_month(5).unwrap();
|
||||||
assert_eq!(dt.format("%Y").to_string(), dt.with_offset(UTC).format("%Y").to_string());
|
assert_eq!(dt.format("%Y").to_string(), dt.with_offset(UTC).format("%Y").to_string());
|
||||||
|
|
|
@ -19,7 +19,7 @@ use offset::Offset;
|
||||||
use naive::date::NaiveDate;
|
use naive::date::NaiveDate;
|
||||||
use naive::time::NaiveTime;
|
use naive::time::NaiveTime;
|
||||||
|
|
||||||
use self::parsed::Parsed;
|
pub use self::parsed::Parsed;
|
||||||
pub use self::strftime::StrftimeItems;
|
pub use self::strftime::StrftimeItems;
|
||||||
|
|
||||||
/// Padding characters for numeric items.
|
/// Padding characters for numeric items.
|
||||||
|
|
|
@ -491,6 +491,25 @@ impl Parsed {
|
||||||
LocalResult::Ambiguous(..) => Err(NOT_ENOUGH),
|
LocalResult::Ambiguous(..) => Err(NOT_ENOUGH),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a parsed timezone-aware date and time out of given fields,
|
||||||
|
/// with an additional `Offset` used to interpret and validate the local date.
|
||||||
|
///
|
||||||
|
/// This method is able to determine the combined date and time
|
||||||
|
/// from date and time fields or a single `timestamp` field, plus a time zone offset.
|
||||||
|
/// Either way those fields have to be consistent to each other.
|
||||||
|
/// If parsed fields include an UTC offset, it also has to be consistent to `offset`.
|
||||||
|
pub fn to_datetime_with_offset<Off: Offset>(&self, offset: Off) -> ParseResult<DateTime<Off>> {
|
||||||
|
let delta = offset.local_minus_utc().num_seconds();
|
||||||
|
let delta = try!(delta.to_i32().ok_or(OUT_OF_RANGE));
|
||||||
|
if self.offset.unwrap_or(delta) != delta { return Err(IMPOSSIBLE); }
|
||||||
|
let datetime = try!(self.to_naive_datetime_with_offset(delta));
|
||||||
|
match offset.from_local_datetime(&datetime) {
|
||||||
|
LocalResult::None => Err(IMPOSSIBLE),
|
||||||
|
LocalResult::Single(t) => Ok(t),
|
||||||
|
LocalResult::Ambiguous(..) => Err(NOT_ENOUGH),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -200,6 +200,7 @@ pub use naive::datetime::NaiveDateTime;
|
||||||
pub use date::Date;
|
pub use date::Date;
|
||||||
pub use time::Time;
|
pub use time::Time;
|
||||||
pub use datetime::DateTime;
|
pub use datetime::DateTime;
|
||||||
|
pub use format::{ParseError, ParseResult};
|
||||||
|
|
||||||
// useful throughout the codebase
|
// useful throughout the codebase
|
||||||
macro_rules! try_opt {
|
macro_rules! try_opt {
|
||||||
|
|
|
@ -15,7 +15,7 @@ use div::div_mod_floor;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use naive::time::NaiveTime;
|
use naive::time::NaiveTime;
|
||||||
use naive::datetime::NaiveDateTime;
|
use naive::datetime::NaiveDateTime;
|
||||||
use format::{DelayedFormat, StrftimeItems};
|
use format::{parse, Parsed, ParseResult, DelayedFormat, StrftimeItems};
|
||||||
|
|
||||||
use self::internals::{DateImpl, Of, Mdf, YearFlags};
|
use self::internals::{DateImpl, Of, Mdf, YearFlags};
|
||||||
|
|
||||||
|
@ -180,6 +180,14 @@ impl NaiveDate {
|
||||||
Of::new(ordinal, flags))
|
Of::new(ordinal, flags))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a string with the specified format string and returns a new `NaiveDate`.
|
||||||
|
/// See the `format::strftime` module on the supported escape sequences.
|
||||||
|
pub fn from_str(s: &str, fmt: &str) -> ParseResult<NaiveDate> {
|
||||||
|
let mut parsed = Parsed::new();
|
||||||
|
try!(parse(&mut parsed, s, StrftimeItems::new(fmt)));
|
||||||
|
parsed.to_naive_date()
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes a new `NaiveDateTime` from the current date and given `NaiveTime`.
|
/// Makes a new `NaiveDateTime` from the current date and given `NaiveTime`.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn and_time(&self, time: NaiveTime) -> NaiveDateTime {
|
pub fn and_time(&self, time: NaiveTime) -> NaiveDateTime {
|
||||||
|
@ -830,6 +838,20 @@ mod tests {
|
||||||
assert_eq!(format!("{:30?}", NaiveDate::from_ymd(12345, 6, 7)), "+12345-06-07");
|
assert_eq!(format!("{:30?}", NaiveDate::from_ymd(12345, 6, 7)), "+12345-06-07");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_date_from_str() {
|
||||||
|
let ymd = |&: y,m,d| NaiveDate::from_ymd(y,m,d);
|
||||||
|
assert_eq!(NaiveDate::from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
|
||||||
|
Ok(ymd(2014, 5, 7))); // ignore time and offset
|
||||||
|
assert_eq!(NaiveDate::from_str("2015-W06-1=2015-033", "%G-W%V-%u = %Y-%j"),
|
||||||
|
Ok(ymd(2015, 2, 2)));
|
||||||
|
assert_eq!(NaiveDate::from_str("Fri, 09 Aug 13", "%a, %d %b %y"),
|
||||||
|
Ok(ymd(2013, 8, 9)));
|
||||||
|
assert!(NaiveDate::from_str("Sat, 09 Aug 2013", "%a, %d %b %Y").is_err());
|
||||||
|
assert!(NaiveDate::from_str("2014-57", "%Y-%m-%d").is_err());
|
||||||
|
assert!(NaiveDate::from_str("2014", "%Y").is_err()); // insufficient
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_date_format() {
|
fn test_date_format() {
|
||||||
let d = NaiveDate::from_ymd(2012, 3, 4);
|
let d = NaiveDate::from_ymd(2012, 3, 4);
|
||||||
|
|
|
@ -15,7 +15,7 @@ use div::div_mod_floor;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use naive::time::NaiveTime;
|
use naive::time::NaiveTime;
|
||||||
use naive::date::NaiveDate;
|
use naive::date::NaiveDate;
|
||||||
use format::{DelayedFormat, StrftimeItems};
|
use format::{parse, Parsed, ParseResult, DelayedFormat, StrftimeItems};
|
||||||
|
|
||||||
/// ISO 8601 combined date and time without timezone.
|
/// ISO 8601 combined date and time without timezone.
|
||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
|
#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone)]
|
||||||
|
@ -60,6 +60,14 @@ impl NaiveDateTime {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a string with the specified format string and returns a new `NaiveDateTime`.
|
||||||
|
/// See the `format::strftime` module on the supported escape sequences.
|
||||||
|
pub fn from_str(s: &str, fmt: &str) -> ParseResult<NaiveDateTime> {
|
||||||
|
let mut parsed = Parsed::new();
|
||||||
|
try!(parse(&mut parsed, s, StrftimeItems::new(fmt)));
|
||||||
|
parsed.to_naive_datetime_with_offset(0) // no offset adjustment
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieves a date component.
|
/// Retrieves a date component.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn date(&self) -> NaiveDate {
|
pub fn date(&self) -> NaiveDate {
|
||||||
|
@ -330,6 +338,22 @@ mod tests {
|
||||||
assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7), 0x7fffffff);
|
assert_eq!(to_timestamp(2038, 1, 19, 3, 14, 7), 0x7fffffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_datetime_from_str() {
|
||||||
|
let ymdhms = |&: y,m,d,h,n,s| NaiveDate::from_ymd(y,m,d).and_hms(h,n,s);
|
||||||
|
assert_eq!(NaiveDateTime::from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
|
||||||
|
Ok(ymdhms(2014, 5, 7, 12, 34, 56))); // ignore offset
|
||||||
|
assert_eq!(NaiveDateTime::from_str("2015-W06-1 000000", "%G-W%V-%u%H%M%S"),
|
||||||
|
Ok(ymdhms(2015, 2, 2, 0, 0, 0)));
|
||||||
|
assert_eq!(NaiveDateTime::from_str("Fri, 09 Aug 2013 23:54:35 GMT",
|
||||||
|
"%a, %d %b %Y %H:%M:%S GMT"),
|
||||||
|
Ok(ymdhms(2013, 8, 9, 23, 54, 35)));
|
||||||
|
assert!(NaiveDateTime::from_str("Sat, 09 Aug 2013 23:54:35 GMT",
|
||||||
|
"%a, %d %b %Y %H:%M:%S GMT").is_err());
|
||||||
|
assert!(NaiveDateTime::from_str("2014-5-7 12:3456", "%Y-%m-%d %H:%M:%S").is_err());
|
||||||
|
assert!(NaiveDateTime::from_str("12:34:56", "%H:%M:%S").is_err()); // insufficient
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_datetime_format() {
|
fn test_datetime_format() {
|
||||||
let dt = NaiveDate::from_ymd(2010, 9, 8).and_hms_milli(7, 6, 54, 321);
|
let dt = NaiveDate::from_ymd(2010, 9, 8).and_hms_milli(7, 6, 54, 321);
|
||||||
|
|
|
@ -14,7 +14,7 @@ use Timelike;
|
||||||
use div::div_mod_floor;
|
use div::div_mod_floor;
|
||||||
use offset::Offset;
|
use offset::Offset;
|
||||||
use duration::Duration;
|
use duration::Duration;
|
||||||
use format::{DelayedFormat, StrftimeItems};
|
use format::{parse, Parsed, ParseResult, DelayedFormat, StrftimeItems};
|
||||||
|
|
||||||
/// ISO 8601 time without timezone.
|
/// ISO 8601 time without timezone.
|
||||||
/// Allows for the nanosecond precision and optional leap second representation.
|
/// Allows for the nanosecond precision and optional leap second representation.
|
||||||
|
@ -118,6 +118,14 @@ impl NaiveTime {
|
||||||
Some(NaiveTime { secs: secs, frac: nano })
|
Some(NaiveTime { secs: secs, frac: nano })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a string with the specified format string and returns a new `NaiveTime`.
|
||||||
|
/// See the `format::strftime` module on the supported escape sequences.
|
||||||
|
pub fn from_str(s: &str, fmt: &str) -> ParseResult<NaiveTime> {
|
||||||
|
let mut parsed = Parsed::new();
|
||||||
|
try!(parse(&mut parsed, s, StrftimeItems::new(fmt)));
|
||||||
|
parsed.to_naive_time()
|
||||||
|
}
|
||||||
|
|
||||||
/// Formats the time in the specified format string.
|
/// Formats the time in the specified format string.
|
||||||
/// See the `format::strftime` module on the supported escape sequences.
|
/// See the `format::strftime` module on the supported escape sequences.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -368,6 +376,16 @@ mod tests {
|
||||||
assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)), "03:05:07.009");
|
assert_eq!(format!("{:30}", NaiveTime::from_hms_milli(3, 5, 7, 9)), "03:05:07.009");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_time_from_str() {
|
||||||
|
let hms = |&: h,m,s| NaiveTime::from_hms(h,m,s);
|
||||||
|
assert_eq!(NaiveTime::from_str("2014-5-7T12:34:56+09:30", "%Y-%m-%dT%H:%M:%S%z"),
|
||||||
|
Ok(hms(12, 34, 56))); // ignore date and offset
|
||||||
|
assert_eq!(NaiveTime::from_str("PM 12:59", "%P %H:%M"),
|
||||||
|
Ok(hms(12, 59, 0)));
|
||||||
|
assert!(NaiveTime::from_str("12:3456", "%H:%M:%S").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_time_format() {
|
fn test_time_format() {
|
||||||
let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432);
|
let t = NaiveTime::from_hms_nano(3, 5, 7, 98765432);
|
||||||
|
|
|
@ -18,6 +18,7 @@ use naive::datetime::NaiveDateTime;
|
||||||
use date::Date;
|
use date::Date;
|
||||||
use time::Time;
|
use time::Time;
|
||||||
use datetime::DateTime;
|
use datetime::DateTime;
|
||||||
|
use format::{parse, Parsed, ParseResult, StrftimeItems};
|
||||||
|
|
||||||
/// The conversion result from the local time to the timezone-aware datetime types.
|
/// The conversion result from the local time to the timezone-aware datetime types.
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
@ -291,6 +292,20 @@ pub trait Offset: Clone + fmt::Debug {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parses a string with the specified format string and
|
||||||
|
/// returns a `DateTime` with the current offset.
|
||||||
|
/// See the `format::strftime` module on the supported escape sequences.
|
||||||
|
///
|
||||||
|
/// If the format does not include offsets, the current offset is assumed;
|
||||||
|
/// otherwise the input should have a matching UTC offset.
|
||||||
|
///
|
||||||
|
/// See also `DateTime::from_str` which gives a local `DateTime` with parsed `FixedOffset`.
|
||||||
|
fn datetime_from_str(&self, s: &str, fmt: &str) -> ParseResult<DateTime<Self>> {
|
||||||
|
let mut parsed = Parsed::new();
|
||||||
|
try!(parse(&mut parsed, s, StrftimeItems::new(fmt)));
|
||||||
|
parsed.to_datetime_with_offset(self.clone())
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the *current* offset from UTC to the local time.
|
/// Returns the *current* offset from UTC to the local time.
|
||||||
fn local_minus_utc(&self) -> Duration;
|
fn local_minus_utc(&self) -> Duration;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue