Merge pull request #358 from michalsrb/optimize-parsing
Optimize parsing
This commit is contained in:
commit
46f8267c61
|
@ -8,6 +8,14 @@ Chrono obeys the principle of [Semantic Versioning](http://semver.org/).
|
||||||
There were/are numerous minor versions before 1.0 due to the language changes.
|
There were/are numerous minor versions before 1.0 due to the language changes.
|
||||||
Versions with only mechanical changes will be omitted from the following list.
|
Versions with only mechanical changes will be omitted from the following list.
|
||||||
|
|
||||||
|
## next
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Functions that were accepting `Iterator` of `Item`s (for example
|
||||||
|
`format_with_items`) now accept `Iterator` of `Borrow<Item>`, so one can
|
||||||
|
use values or references.
|
||||||
|
|
||||||
## 0.4.9
|
## 0.4.9
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
|
|
@ -29,6 +29,7 @@ alloc = []
|
||||||
std = []
|
std = []
|
||||||
clock = ["time", "std"]
|
clock = ["time", "std"]
|
||||||
wasmbind = ["wasm-bindgen", "js-sys"]
|
wasmbind = ["wasm-bindgen", "js-sys"]
|
||||||
|
bench = ["std"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
time = { version = "0.1.39", optional = true }
|
time = { version = "0.1.39", optional = true }
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
//! ISO 8601 calendar date with time zone.
|
//! ISO 8601 calendar date with time zone.
|
||||||
|
|
||||||
|
use core::borrow::Borrow;
|
||||||
use core::{fmt, hash};
|
use core::{fmt, hash};
|
||||||
use core::cmp::Ordering;
|
use core::cmp::Ordering;
|
||||||
use core::ops::{Add, Sub};
|
use core::ops::{Add, Sub};
|
||||||
|
@ -258,8 +259,8 @@ impl<Tz: TimeZone> Date<Tz> where Tz::Offset: fmt::Display {
|
||||||
/// Formats the date with the specified formatting items.
|
/// Formats the date with the specified formatting items.
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
|
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
|
||||||
where I: Iterator<Item=Item<'a>> + Clone {
|
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
|
||||||
DelayedFormat::new_with_offset(Some(self.naive_local()), None, &self.offset, items)
|
DelayedFormat::new_with_offset(Some(self.naive_local()), None, &self.offset, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ use format::{Item, Numeric, Pad, Fixed};
|
||||||
use format::{parse, Parsed, ParseError, ParseResult, StrftimeItems};
|
use format::{parse, Parsed, ParseError, ParseResult, StrftimeItems};
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
use format::DelayedFormat;
|
use format::DelayedFormat;
|
||||||
|
use core::borrow::Borrow;
|
||||||
|
|
||||||
/// Specific formatting options for seconds. This may be extended in the
|
/// Specific formatting options for seconds. This may be extended in the
|
||||||
/// future, so exhaustive matching in external code is not recommended.
|
/// future, so exhaustive matching in external code is not recommended.
|
||||||
|
@ -326,7 +327,7 @@ impl DateTime<FixedOffset> {
|
||||||
pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
|
pub fn parse_from_rfc2822(s: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||||
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
|
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
|
||||||
let mut parsed = Parsed::new();
|
let mut parsed = Parsed::new();
|
||||||
try!(parse(&mut parsed, s, ITEMS.iter().cloned()));
|
try!(parse(&mut parsed, s, ITEMS.iter()));
|
||||||
parsed.to_datetime()
|
parsed.to_datetime()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +339,7 @@ impl DateTime<FixedOffset> {
|
||||||
pub fn parse_from_rfc3339(s: &str) -> ParseResult<DateTime<FixedOffset>> {
|
pub fn parse_from_rfc3339(s: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||||
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
|
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
|
||||||
let mut parsed = Parsed::new();
|
let mut parsed = Parsed::new();
|
||||||
try!(parse(&mut parsed, s, ITEMS.iter().cloned()));
|
try!(parse(&mut parsed, s, ITEMS.iter()));
|
||||||
parsed.to_datetime()
|
parsed.to_datetime()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,14 +375,14 @@ impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display {
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
pub fn to_rfc2822(&self) -> String {
|
pub fn to_rfc2822(&self) -> String {
|
||||||
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
|
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC2822)];
|
||||||
self.format_with_items(ITEMS.iter().cloned()).to_string()
|
self.format_with_items(ITEMS.iter()).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
|
/// Returns an RFC 3339 and ISO 8601 date and time string such as `1996-12-19T16:39:57-08:00`.
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
pub fn to_rfc3339(&self) -> String {
|
pub fn to_rfc3339(&self) -> String {
|
||||||
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
|
const ITEMS: &'static [Item<'static>] = &[Item::Fixed(Fixed::RFC3339)];
|
||||||
self.format_with_items(ITEMS.iter().cloned()).to_string()
|
self.format_with_items(ITEMS.iter()).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return an RFC 3339 and ISO 8601 date and time string with subseconds
|
/// Return an RFC 3339 and ISO 8601 date and time string with subseconds
|
||||||
|
@ -450,11 +451,11 @@ impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display {
|
||||||
match ssitem {
|
match ssitem {
|
||||||
None =>
|
None =>
|
||||||
self.format_with_items(
|
self.format_with_items(
|
||||||
PREFIX.iter().chain([tzitem].iter()).cloned()
|
PREFIX.iter().chain([tzitem].iter())
|
||||||
).to_string(),
|
).to_string(),
|
||||||
Some(s) =>
|
Some(s) =>
|
||||||
self.format_with_items(
|
self.format_with_items(
|
||||||
PREFIX.iter().chain([s, tzitem].iter()).cloned()
|
PREFIX.iter().chain([s, tzitem].iter())
|
||||||
).to_string(),
|
).to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -462,8 +463,8 @@ impl<Tz: TimeZone> DateTime<Tz> where Tz::Offset: fmt::Display {
|
||||||
/// Formats the combined date and time with the specified formatting items.
|
/// Formats the combined date and time with the specified formatting items.
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
|
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
|
||||||
where I: Iterator<Item=Item<'a>> + Clone {
|
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
|
||||||
let local = self.naive_local();
|
let local = self.naive_local();
|
||||||
DelayedFormat::new_with_offset(Some(local.date()), Some(local.time()), &self.offset, items)
|
DelayedFormat::new_with_offset(Some(local.date()), Some(local.time()), &self.offset, items)
|
||||||
}
|
}
|
||||||
|
@ -621,24 +622,24 @@ impl str::FromStr for DateTime<FixedOffset> {
|
||||||
|
|
||||||
fn from_str(s: &str) -> ParseResult<DateTime<FixedOffset>> {
|
fn from_str(s: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||||
const ITEMS: &'static [Item<'static>] = &[
|
const ITEMS: &'static [Item<'static>] = &[
|
||||||
Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero),
|
Item::Numeric(Numeric::Year, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal("-"),
|
Item::Space(""), Item::Literal("-"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero),
|
Item::Numeric(Numeric::Month, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal("-"),
|
Item::Space(""), Item::Literal("-"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero),
|
Item::Numeric(Numeric::Day, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal("T"), // XXX shouldn't this be case-insensitive?
|
Item::Space(""), Item::Literal("T"), // XXX shouldn't this be case-insensitive?
|
||||||
Item::Space(""), Item::Numeric(Numeric::Hour, Pad::Zero),
|
Item::Numeric(Numeric::Hour, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal(":"),
|
Item::Space(""), Item::Literal(":"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Minute, Pad::Zero),
|
Item::Numeric(Numeric::Minute, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal(":"),
|
Item::Space(""), Item::Literal(":"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Second, Pad::Zero),
|
Item::Numeric(Numeric::Second, Pad::Zero),
|
||||||
Item::Fixed(Fixed::Nanosecond),
|
Item::Fixed(Fixed::Nanosecond),
|
||||||
Item::Space(""), Item::Fixed(Fixed::TimezoneOffsetZ),
|
Item::Space(""), Item::Fixed(Fixed::TimezoneOffsetZ),
|
||||||
Item::Space(""),
|
Item::Space(""),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut parsed = Parsed::new();
|
let mut parsed = Parsed::new();
|
||||||
try!(parse(&mut parsed, s, ITEMS.iter().cloned()));
|
try!(parse(&mut parsed, s, ITEMS.iter()));
|
||||||
parsed.to_datetime()
|
parsed.to_datetime()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1140,7 +1141,7 @@ pub mod serde {
|
||||||
/// # fn main() { example().unwrap(); }
|
/// # fn main() { example().unwrap(); }
|
||||||
/// ```
|
/// ```
|
||||||
pub mod ts_nanoseconds_option {
|
pub mod ts_nanoseconds_option {
|
||||||
use std::fmt;
|
use core::fmt;
|
||||||
use serdelib::{ser, de};
|
use serdelib::{ser, de};
|
||||||
|
|
||||||
use {DateTime, Utc};
|
use {DateTime, Utc};
|
||||||
|
@ -1431,7 +1432,7 @@ pub mod serde {
|
||||||
/// # fn main() { example().unwrap(); }
|
/// # fn main() { example().unwrap(); }
|
||||||
/// ```
|
/// ```
|
||||||
pub mod ts_milliseconds_option {
|
pub mod ts_milliseconds_option {
|
||||||
use std::fmt;
|
use core::fmt;
|
||||||
use serdelib::{ser, de};
|
use serdelib::{ser, de};
|
||||||
|
|
||||||
use {DateTime, Utc};
|
use {DateTime, Utc};
|
||||||
|
@ -1718,7 +1719,7 @@ pub mod serde {
|
||||||
/// # fn main() { example().unwrap(); }
|
/// # fn main() { example().unwrap(); }
|
||||||
/// ```
|
/// ```
|
||||||
pub mod ts_seconds_option {
|
pub mod ts_seconds_option {
|
||||||
use std::fmt;
|
use core::fmt;
|
||||||
use serdelib::{ser, de};
|
use serdelib::{ser, de};
|
||||||
|
|
||||||
use {DateTime, Utc};
|
use {DateTime, Utc};
|
||||||
|
@ -2213,4 +2214,53 @@ mod tests {
|
||||||
assert_eq!(format!("{} ", ymd_formatted), format!("{:<17}", ymd));
|
assert_eq!(format!("{} ", ymd_formatted), format!("{:<17}", ymd));
|
||||||
assert_eq!(format!(" {} ", ymd_formatted), format!("{:^17}", ymd));
|
assert_eq!(format!(" {} ", ymd_formatted), format!("{:^17}", ymd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "bench")]
|
||||||
|
#[bench]
|
||||||
|
fn bench_datetime_parse_from_rfc2822(bh: &mut test::Bencher) {
|
||||||
|
bh.iter(|| {
|
||||||
|
let str = test::black_box("Wed, 18 Feb 2015 23:16:09 +0000");
|
||||||
|
DateTime::parse_from_rfc2822(str).unwrap()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "bench")]
|
||||||
|
#[bench]
|
||||||
|
fn bench_datetime_parse_from_rfc3339(bh: &mut test::Bencher) {
|
||||||
|
bh.iter(|| {
|
||||||
|
let str = test::black_box("2015-02-18T23:59:60.234567+05:00");
|
||||||
|
DateTime::parse_from_rfc3339(str).unwrap()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "bench")]
|
||||||
|
#[bench]
|
||||||
|
fn bench_datetime_from_str(bh: &mut test::Bencher) {
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
bh.iter(|| {
|
||||||
|
let str = test::black_box("2019-03-30T18:46:57.193Z");
|
||||||
|
DateTime::<Utc>::from_str(str).unwrap()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "bench")]
|
||||||
|
#[bench]
|
||||||
|
fn bench_datetime_to_rfc2822(bh: &mut test::Bencher) {
|
||||||
|
let pst = FixedOffset::east(8 * 60 * 60);
|
||||||
|
let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_000);
|
||||||
|
bh.iter(|| {
|
||||||
|
test::black_box(dt).to_rfc2822()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "bench")]
|
||||||
|
#[bench]
|
||||||
|
fn bench_datetime_to_rfc3339(bh: &mut test::Bencher) {
|
||||||
|
let pst = FixedOffset::east(8 * 60 * 60);
|
||||||
|
let dt = pst.ymd(2018, 1, 11).and_hms_nano(10, 5, 13, 084_660_000);
|
||||||
|
bh.iter(|| {
|
||||||
|
test::black_box(dt).to_rfc3339()
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
#![allow(ellipsis_inclusive_range_patterns)]
|
#![allow(ellipsis_inclusive_range_patterns)]
|
||||||
|
|
||||||
|
use core::borrow::Borrow;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
#[cfg(any(feature = "std", test))]
|
#[cfg(any(feature = "std", test))]
|
||||||
|
@ -356,14 +357,14 @@ const BAD_FORMAT: ParseError = ParseError(ParseErrorKind::BadFormat);
|
||||||
/// Tries to format given arguments with given formatting items.
|
/// Tries to format given arguments with given formatting items.
|
||||||
/// Internally used by `DelayedFormat`.
|
/// Internally used by `DelayedFormat`.
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
pub fn format<'a, I>(
|
pub fn format<'a, I, B>(
|
||||||
w: &mut fmt::Formatter,
|
w: &mut fmt::Formatter,
|
||||||
date: Option<&NaiveDate>,
|
date: Option<&NaiveDate>,
|
||||||
time: Option<&NaiveTime>,
|
time: Option<&NaiveTime>,
|
||||||
off: Option<&(String, FixedOffset)>,
|
off: Option<&(String, FixedOffset)>,
|
||||||
items: I,
|
items: I,
|
||||||
) -> fmt::Result
|
) -> fmt::Result
|
||||||
where I: Iterator<Item=Item<'a>>
|
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>>
|
||||||
{
|
{
|
||||||
// full and abbreviated month and weekday names
|
// full and abbreviated month and weekday names
|
||||||
static SHORT_MONTHS: [&'static str; 12] =
|
static SHORT_MONTHS: [&'static str; 12] =
|
||||||
|
@ -380,12 +381,12 @@ pub fn format<'a, I>(
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
match item {
|
match item.borrow() {
|
||||||
Item::Literal(s) | Item::Space(s) => result.push_str(s),
|
&Item::Literal(s) | &Item::Space(s) => result.push_str(s),
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
Item::OwnedLiteral(ref s) | Item::OwnedSpace(ref s) => result.push_str(s),
|
&Item::OwnedLiteral(ref s) | &Item::OwnedSpace(ref s) => result.push_str(s),
|
||||||
|
|
||||||
Item::Numeric(spec, pad) => {
|
&Item::Numeric(ref spec, ref pad) => {
|
||||||
use self::Numeric::*;
|
use self::Numeric::*;
|
||||||
|
|
||||||
let week_from_sun = |d: &NaiveDate|
|
let week_from_sun = |d: &NaiveDate|
|
||||||
|
@ -394,31 +395,31 @@ pub fn format<'a, I>(
|
||||||
(d.ordinal() as i32 - d.weekday().num_days_from_monday() as i32 + 7) / 7;
|
(d.ordinal() as i32 - d.weekday().num_days_from_monday() as i32 + 7) / 7;
|
||||||
|
|
||||||
let (width, v) = match spec {
|
let (width, v) = match spec {
|
||||||
Year => (4, date.map(|d| i64::from(d.year()))),
|
&Year => (4, date.map(|d| i64::from(d.year()))),
|
||||||
YearDiv100 => (2, date.map(|d| div_floor(i64::from(d.year()), 100))),
|
&YearDiv100 => (2, date.map(|d| div_floor(i64::from(d.year()), 100))),
|
||||||
YearMod100 => (2, date.map(|d| mod_floor(i64::from(d.year()), 100))),
|
&YearMod100 => (2, date.map(|d| mod_floor(i64::from(d.year()), 100))),
|
||||||
IsoYear => (4, date.map(|d| i64::from(d.iso_week().year()))),
|
&IsoYear => (4, date.map(|d| i64::from(d.iso_week().year()))),
|
||||||
IsoYearDiv100 => (2, date.map(|d| div_floor(
|
&IsoYearDiv100 => (2, date.map(|d| div_floor(
|
||||||
i64::from(d.iso_week().year()), 100))),
|
i64::from(d.iso_week().year()), 100))),
|
||||||
IsoYearMod100 => (2, date.map(|d| mod_floor(
|
&IsoYearMod100 => (2, date.map(|d| mod_floor(
|
||||||
i64::from(d.iso_week().year()), 100))),
|
i64::from(d.iso_week().year()), 100))),
|
||||||
Month => (2, date.map(|d| i64::from(d.month()))),
|
&Month => (2, date.map(|d| i64::from(d.month()))),
|
||||||
Day => (2, date.map(|d| i64::from(d.day()))),
|
&Day => (2, date.map(|d| i64::from(d.day()))),
|
||||||
WeekFromSun => (2, date.map(|d| i64::from(week_from_sun(d)))),
|
&WeekFromSun => (2, date.map(|d| i64::from(week_from_sun(d)))),
|
||||||
WeekFromMon => (2, date.map(|d| i64::from(week_from_mon(d)))),
|
&WeekFromMon => (2, date.map(|d| i64::from(week_from_mon(d)))),
|
||||||
IsoWeek => (2, date.map(|d| i64::from(d.iso_week().week()))),
|
&IsoWeek => (2, date.map(|d| i64::from(d.iso_week().week()))),
|
||||||
NumDaysFromSun => (1, date.map(|d| i64::from(d.weekday()
|
&NumDaysFromSun => (1, date.map(|d| i64::from(d.weekday()
|
||||||
.num_days_from_sunday()))),
|
.num_days_from_sunday()))),
|
||||||
WeekdayFromMon => (1, date.map(|d| i64::from(d.weekday()
|
&WeekdayFromMon => (1, date.map(|d| i64::from(d.weekday()
|
||||||
.number_from_monday()))),
|
.number_from_monday()))),
|
||||||
Ordinal => (3, date.map(|d| i64::from(d.ordinal()))),
|
&Ordinal => (3, date.map(|d| i64::from(d.ordinal()))),
|
||||||
Hour => (2, time.map(|t| i64::from(t.hour()))),
|
&Hour => (2, time.map(|t| i64::from(t.hour()))),
|
||||||
Hour12 => (2, time.map(|t| i64::from(t.hour12().1))),
|
&Hour12 => (2, time.map(|t| i64::from(t.hour12().1))),
|
||||||
Minute => (2, time.map(|t| i64::from(t.minute()))),
|
&Minute => (2, time.map(|t| i64::from(t.minute()))),
|
||||||
Second => (2, time.map(|t| i64::from(t.second() +
|
&Second => (2, time.map(|t| i64::from(t.second() +
|
||||||
t.nanosecond() / 1_000_000_000))),
|
t.nanosecond() / 1_000_000_000))),
|
||||||
Nanosecond => (9, time.map(|t| i64::from(t.nanosecond() % 1_000_000_000))),
|
&Nanosecond => (9, time.map(|t| i64::from(t.nanosecond() % 1_000_000_000))),
|
||||||
Timestamp => (1, match (date, time, off) {
|
&Timestamp => (1, match (date, time, off) {
|
||||||
(Some(d), Some(t), None) =>
|
(Some(d), Some(t), None) =>
|
||||||
Some(d.and_time(*t).timestamp()),
|
Some(d.and_time(*t).timestamp()),
|
||||||
(Some(d), Some(t), Some(&(_, off))) =>
|
(Some(d), Some(t), Some(&(_, off))) =>
|
||||||
|
@ -427,24 +428,24 @@ pub fn format<'a, I>(
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// for the future expansion
|
// for the future expansion
|
||||||
Internal(ref int) => match int._dummy {},
|
&Internal(ref int) => match int._dummy {},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
if let Some(v) = v {
|
if let Some(v) = v {
|
||||||
try!(
|
try!(
|
||||||
if (spec == Year || spec == IsoYear) && !(0 <= v && v < 10_000) {
|
if (spec == &Year || spec == &IsoYear) && !(0 <= v && v < 10_000) {
|
||||||
// non-four-digit years require an explicit sign as per ISO 8601
|
// non-four-digit years require an explicit sign as per ISO 8601
|
||||||
match pad {
|
match pad {
|
||||||
Pad::None => write!(result, "{:+}", v),
|
&Pad::None => write!(result, "{:+}", v),
|
||||||
Pad::Zero => write!(result, "{:+01$}", v, width + 1),
|
&Pad::Zero => write!(result, "{:+01$}", v, width + 1),
|
||||||
Pad::Space => write!(result, "{:+1$}", v, width + 1),
|
&Pad::Space => write!(result, "{:+1$}", v, width + 1),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match pad {
|
match pad {
|
||||||
Pad::None => write!(result, "{}", v),
|
&Pad::None => write!(result, "{}", v),
|
||||||
Pad::Zero => write!(result, "{:01$}", v, width),
|
&Pad::Zero => write!(result, "{:01$}", v, width),
|
||||||
Pad::Space => write!(result, "{:1$}", v, width),
|
&Pad::Space => write!(result, "{:1$}", v, width),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -453,7 +454,7 @@ pub fn format<'a, I>(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Item::Fixed(spec) => {
|
&Item::Fixed(ref spec) => {
|
||||||
use self::Fixed::*;
|
use self::Fixed::*;
|
||||||
|
|
||||||
/// Prints an offset from UTC in the format of `+HHMM` or `+HH:MM`.
|
/// Prints an offset from UTC in the format of `+HHMM` or `+HH:MM`.
|
||||||
|
@ -479,41 +480,41 @@ pub fn format<'a, I>(
|
||||||
}
|
}
|
||||||
|
|
||||||
let ret = match spec {
|
let ret = match spec {
|
||||||
ShortMonthName =>
|
&ShortMonthName =>
|
||||||
date.map(|d| {
|
date.map(|d| {
|
||||||
result.push_str(SHORT_MONTHS[d.month0() as usize]);
|
result.push_str(SHORT_MONTHS[d.month0() as usize]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
LongMonthName =>
|
&LongMonthName =>
|
||||||
date.map(|d| {
|
date.map(|d| {
|
||||||
result.push_str(LONG_MONTHS[d.month0() as usize]);
|
result.push_str(LONG_MONTHS[d.month0() as usize]);
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
ShortWeekdayName =>
|
&ShortWeekdayName =>
|
||||||
date.map(|d| {
|
date.map(|d| {
|
||||||
result.push_str(
|
result.push_str(
|
||||||
SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as usize]
|
SHORT_WEEKDAYS[d.weekday().num_days_from_monday() as usize]
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
LongWeekdayName =>
|
&LongWeekdayName =>
|
||||||
date.map(|d| {
|
date.map(|d| {
|
||||||
result.push_str(
|
result.push_str(
|
||||||
LONG_WEEKDAYS[d.weekday().num_days_from_monday() as usize]
|
LONG_WEEKDAYS[d.weekday().num_days_from_monday() as usize]
|
||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
LowerAmPm =>
|
&LowerAmPm =>
|
||||||
time.map(|t| {
|
time.map(|t| {
|
||||||
result.push_str(if t.hour12().0 {"pm"} else {"am"});
|
result.push_str(if t.hour12().0 {"pm"} else {"am"});
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
UpperAmPm =>
|
&UpperAmPm =>
|
||||||
time.map(|t| {
|
time.map(|t| {
|
||||||
result.push_str(if t.hour12().0 {"PM"} else {"AM"});
|
result.push_str(if t.hour12().0 {"PM"} else {"AM"});
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
Nanosecond =>
|
&Nanosecond =>
|
||||||
time.map(|t| {
|
time.map(|t| {
|
||||||
let nano = t.nanosecond() % 1_000_000_000;
|
let nano = t.nanosecond() % 1_000_000_000;
|
||||||
if nano == 0 {
|
if nano == 0 {
|
||||||
|
@ -526,52 +527,52 @@ pub fn format<'a, I>(
|
||||||
write!(result, ".{:09}", nano)
|
write!(result, ".{:09}", nano)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
Nanosecond3 =>
|
&Nanosecond3 =>
|
||||||
time.map(|t| {
|
time.map(|t| {
|
||||||
let nano = t.nanosecond() % 1_000_000_000;
|
let nano = t.nanosecond() % 1_000_000_000;
|
||||||
write!(result, ".{:03}", nano / 1_000_000)
|
write!(result, ".{:03}", nano / 1_000_000)
|
||||||
}),
|
}),
|
||||||
Nanosecond6 =>
|
&Nanosecond6 =>
|
||||||
time.map(|t| {
|
time.map(|t| {
|
||||||
let nano = t.nanosecond() % 1_000_000_000;
|
let nano = t.nanosecond() % 1_000_000_000;
|
||||||
write!(result, ".{:06}", nano / 1_000)
|
write!(result, ".{:06}", nano / 1_000)
|
||||||
}),
|
}),
|
||||||
Nanosecond9 =>
|
&Nanosecond9 =>
|
||||||
time.map(|t| {
|
time.map(|t| {
|
||||||
let nano = t.nanosecond() % 1_000_000_000;
|
let nano = t.nanosecond() % 1_000_000_000;
|
||||||
write!(result, ".{:09}", nano)
|
write!(result, ".{:09}", nano)
|
||||||
}),
|
}),
|
||||||
Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) =>
|
&Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) =>
|
||||||
time.map(|t| {
|
time.map(|t| {
|
||||||
let nano = t.nanosecond() % 1_000_000_000;
|
let nano = t.nanosecond() % 1_000_000_000;
|
||||||
write!(result, "{:03}", nano / 1_000_000)
|
write!(result, "{:03}", nano / 1_000_000)
|
||||||
}),
|
}),
|
||||||
Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) =>
|
&Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) =>
|
||||||
time.map(|t| {
|
time.map(|t| {
|
||||||
let nano = t.nanosecond() % 1_000_000_000;
|
let nano = t.nanosecond() % 1_000_000_000;
|
||||||
write!(result, "{:06}", nano / 1_000)
|
write!(result, "{:06}", nano / 1_000)
|
||||||
}),
|
}),
|
||||||
Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) =>
|
&Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) =>
|
||||||
time.map(|t| {
|
time.map(|t| {
|
||||||
let nano = t.nanosecond() % 1_000_000_000;
|
let nano = t.nanosecond() % 1_000_000_000;
|
||||||
write!(result, "{:09}", nano)
|
write!(result, "{:09}", nano)
|
||||||
}),
|
}),
|
||||||
TimezoneName =>
|
&TimezoneName =>
|
||||||
off.map(|&(ref name, _)| {
|
off.map(|&(ref name, _)| {
|
||||||
result.push_str(name);
|
result.push_str(name);
|
||||||
Ok(())
|
Ok(())
|
||||||
}),
|
}),
|
||||||
TimezoneOffsetColon =>
|
&TimezoneOffsetColon =>
|
||||||
off.map(|&(_, off)| write_local_minus_utc(&mut result, off, false, true)),
|
off.map(|&(_, off)| write_local_minus_utc(&mut result, off, false, true)),
|
||||||
TimezoneOffsetColonZ =>
|
&TimezoneOffsetColonZ =>
|
||||||
off.map(|&(_, off)| write_local_minus_utc(&mut result, off, true, true)),
|
off.map(|&(_, off)| write_local_minus_utc(&mut result, off, true, true)),
|
||||||
TimezoneOffset =>
|
&TimezoneOffset =>
|
||||||
off.map(|&(_, off)| write_local_minus_utc(&mut result, off, false, false)),
|
off.map(|&(_, off)| write_local_minus_utc(&mut result, off, false, false)),
|
||||||
TimezoneOffsetZ =>
|
&TimezoneOffsetZ =>
|
||||||
off.map(|&(_, off)| write_local_minus_utc(&mut result, off, true, false)),
|
off.map(|&(_, off)| write_local_minus_utc(&mut result, off, true, false)),
|
||||||
Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) =>
|
&Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) =>
|
||||||
panic!("Do not try to write %#z it is undefined"),
|
panic!("Do not try to write %#z it is undefined"),
|
||||||
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;
|
let sec = t.second() + t.nanosecond() / 1_000_000_000;
|
||||||
try!(write!(
|
try!(write!(
|
||||||
|
@ -585,7 +586,7 @@ pub fn format<'a, I>(
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
RFC3339 => // same to `%Y-%m-%dT%H:%M:%S%.f%:z`
|
&RFC3339 => // same to `%Y-%m-%dT%H:%M:%S%.f%:z`
|
||||||
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
|
if let (Some(d), Some(t), Some(&(_, off))) = (date, time, off) {
|
||||||
// reuse `Debug` impls which already print ISO 8601 format.
|
// reuse `Debug` impls which already print ISO 8601 format.
|
||||||
// this is faster in this way.
|
// this is faster in this way.
|
||||||
|
@ -602,7 +603,7 @@ pub fn format<'a, I>(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
Item::Error => return Err(fmt::Error),
|
&Item::Error => return Err(fmt::Error),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,7 +634,7 @@ pub struct DelayedFormat<I> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
impl<'a, I: Iterator<Item=Item<'a>> + Clone> DelayedFormat<I> {
|
impl<'a, I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>>> DelayedFormat<I> {
|
||||||
/// Makes a new `DelayedFormat` value out of local date and time.
|
/// Makes a new `DelayedFormat` value out of local date and time.
|
||||||
pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> {
|
pub fn new(date: Option<NaiveDate>, time: Option<NaiveTime>, items: I) -> DelayedFormat<I> {
|
||||||
DelayedFormat { date: date, time: time, off: None, items: items }
|
DelayedFormat { date: date, time: time, off: None, items: items }
|
||||||
|
@ -649,7 +650,7 @@ impl<'a, I: Iterator<Item=Item<'a>> + Clone> DelayedFormat<I> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
impl<'a, I: Iterator<Item=Item<'a>> + Clone> fmt::Display for DelayedFormat<I> {
|
impl<'a, I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>>> fmt::Display for DelayedFormat<I> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
format(f, self.date.as_ref(), self.time.as_ref(), self.off.as_ref(), self.items.clone())
|
format(f, self.date.as_ref(), self.time.as_ref(), self.off.as_ref(), self.items.clone())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#![allow(deprecated)]
|
#![allow(deprecated)]
|
||||||
|
|
||||||
|
use core::borrow::Borrow;
|
||||||
use core::usize;
|
use core::usize;
|
||||||
|
|
||||||
use Weekday;
|
use Weekday;
|
||||||
|
@ -204,64 +205,64 @@ fn parse_rfc3339<'a>(parsed: &mut Parsed, mut s: &'a str) -> ParseResult<(&'a st
|
||||||
/// so one can prepend any number of whitespace then any number of zeroes before numbers.
|
/// so one can prepend any number of whitespace then any number of zeroes before numbers.
|
||||||
///
|
///
|
||||||
/// - (Still) obeying the intrinsic parsing width. This allows, for example, parsing `HHMMSS`.
|
/// - (Still) obeying the intrinsic parsing width. This allows, for example, parsing `HHMMSS`.
|
||||||
pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<()>
|
pub fn parse<'a, I, B>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<()>
|
||||||
where I: Iterator<Item=Item<'a>> {
|
where I: Iterator<Item=B>, B: Borrow<Item<'a>> {
|
||||||
macro_rules! try_consume {
|
macro_rules! try_consume {
|
||||||
($e:expr) => ({ let (s_, v) = try!($e); s = s_; v })
|
($e:expr) => ({ let (s_, v) = try!($e); s = s_; v })
|
||||||
}
|
}
|
||||||
|
|
||||||
for item in items {
|
for item in items {
|
||||||
match item {
|
match item.borrow() {
|
||||||
Item::Literal(prefix) => {
|
&Item::Literal(prefix) => {
|
||||||
if s.len() < prefix.len() { return Err(TOO_SHORT); }
|
if s.len() < prefix.len() { return Err(TOO_SHORT); }
|
||||||
if !s.starts_with(prefix) { return Err(INVALID); }
|
if !s.starts_with(prefix) { return Err(INVALID); }
|
||||||
s = &s[prefix.len()..];
|
s = &s[prefix.len()..];
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
Item::OwnedLiteral(ref prefix) => {
|
&Item::OwnedLiteral(ref prefix) => {
|
||||||
if s.len() < prefix.len() { return Err(TOO_SHORT); }
|
if s.len() < prefix.len() { return Err(TOO_SHORT); }
|
||||||
if !s.starts_with(&prefix[..]) { return Err(INVALID); }
|
if !s.starts_with(&prefix[..]) { return Err(INVALID); }
|
||||||
s = &s[prefix.len()..];
|
s = &s[prefix.len()..];
|
||||||
}
|
}
|
||||||
|
|
||||||
Item::Space(_) => {
|
&Item::Space(_) => {
|
||||||
s = s.trim_left();
|
s = s.trim_left();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
Item::OwnedSpace(_) => {
|
&Item::OwnedSpace(_) => {
|
||||||
s = s.trim_left();
|
s = s.trim_left();
|
||||||
}
|
}
|
||||||
|
|
||||||
Item::Numeric(spec, _pad) => {
|
&Item::Numeric(ref spec, ref _pad) => {
|
||||||
use super::Numeric::*;
|
use super::Numeric::*;
|
||||||
type Setter = fn(&mut Parsed, i64) -> ParseResult<()>;
|
type Setter = fn(&mut Parsed, i64) -> ParseResult<()>;
|
||||||
|
|
||||||
let (width, signed, set): (usize, bool, Setter) = match spec {
|
let (width, signed, set): (usize, bool, Setter) = match spec {
|
||||||
Year => (4, true, Parsed::set_year),
|
&Year => (4, true, Parsed::set_year),
|
||||||
YearDiv100 => (2, false, Parsed::set_year_div_100),
|
&YearDiv100 => (2, false, Parsed::set_year_div_100),
|
||||||
YearMod100 => (2, false, Parsed::set_year_mod_100),
|
&YearMod100 => (2, false, Parsed::set_year_mod_100),
|
||||||
IsoYear => (4, true, Parsed::set_isoyear),
|
&IsoYear => (4, true, Parsed::set_isoyear),
|
||||||
IsoYearDiv100 => (2, false, Parsed::set_isoyear_div_100),
|
&IsoYearDiv100 => (2, false, Parsed::set_isoyear_div_100),
|
||||||
IsoYearMod100 => (2, false, Parsed::set_isoyear_mod_100),
|
&IsoYearMod100 => (2, false, Parsed::set_isoyear_mod_100),
|
||||||
Month => (2, false, Parsed::set_month),
|
&Month => (2, false, Parsed::set_month),
|
||||||
Day => (2, false, Parsed::set_day),
|
&Day => (2, false, Parsed::set_day),
|
||||||
WeekFromSun => (2, false, Parsed::set_week_from_sun),
|
&WeekFromSun => (2, false, Parsed::set_week_from_sun),
|
||||||
WeekFromMon => (2, false, Parsed::set_week_from_mon),
|
&WeekFromMon => (2, false, Parsed::set_week_from_mon),
|
||||||
IsoWeek => (2, false, Parsed::set_isoweek),
|
&IsoWeek => (2, false, Parsed::set_isoweek),
|
||||||
NumDaysFromSun => (1, false, set_weekday_with_num_days_from_sunday),
|
&NumDaysFromSun => (1, false, set_weekday_with_num_days_from_sunday),
|
||||||
WeekdayFromMon => (1, false, set_weekday_with_number_from_monday),
|
&WeekdayFromMon => (1, false, set_weekday_with_number_from_monday),
|
||||||
Ordinal => (3, false, Parsed::set_ordinal),
|
&Ordinal => (3, false, Parsed::set_ordinal),
|
||||||
Hour => (2, false, Parsed::set_hour),
|
&Hour => (2, false, Parsed::set_hour),
|
||||||
Hour12 => (2, false, Parsed::set_hour12),
|
&Hour12 => (2, false, Parsed::set_hour12),
|
||||||
Minute => (2, false, Parsed::set_minute),
|
&Minute => (2, false, Parsed::set_minute),
|
||||||
Second => (2, false, Parsed::set_second),
|
&Second => (2, false, Parsed::set_second),
|
||||||
Nanosecond => (9, false, Parsed::set_nanosecond),
|
&Nanosecond => (9, false, Parsed::set_nanosecond),
|
||||||
Timestamp => (usize::MAX, false, Parsed::set_timestamp),
|
&Timestamp => (usize::MAX, false, Parsed::set_timestamp),
|
||||||
|
|
||||||
// for the future expansion
|
// for the future expansion
|
||||||
Internal(ref int) => match int._dummy {},
|
&Internal(ref int) => match int._dummy {},
|
||||||
};
|
};
|
||||||
|
|
||||||
s = s.trim_left();
|
s = s.trim_left();
|
||||||
|
@ -281,31 +282,31 @@ pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<(
|
||||||
try!(set(parsed, v));
|
try!(set(parsed, v));
|
||||||
}
|
}
|
||||||
|
|
||||||
Item::Fixed(spec) => {
|
&Item::Fixed(ref spec) => {
|
||||||
use super::Fixed::*;
|
use super::Fixed::*;
|
||||||
|
|
||||||
match spec {
|
match spec {
|
||||||
ShortMonthName => {
|
&ShortMonthName => {
|
||||||
let month0 = try_consume!(scan::short_month0(s));
|
let month0 = try_consume!(scan::short_month0(s));
|
||||||
try!(parsed.set_month(i64::from(month0) + 1));
|
try!(parsed.set_month(i64::from(month0) + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
LongMonthName => {
|
&LongMonthName => {
|
||||||
let month0 = try_consume!(scan::short_or_long_month0(s));
|
let month0 = try_consume!(scan::short_or_long_month0(s));
|
||||||
try!(parsed.set_month(i64::from(month0) + 1));
|
try!(parsed.set_month(i64::from(month0) + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
ShortWeekdayName => {
|
&ShortWeekdayName => {
|
||||||
let weekday = try_consume!(scan::short_weekday(s));
|
let weekday = try_consume!(scan::short_weekday(s));
|
||||||
try!(parsed.set_weekday(weekday));
|
try!(parsed.set_weekday(weekday));
|
||||||
}
|
}
|
||||||
|
|
||||||
LongWeekdayName => {
|
&LongWeekdayName => {
|
||||||
let weekday = try_consume!(scan::short_or_long_weekday(s));
|
let weekday = try_consume!(scan::short_or_long_weekday(s));
|
||||||
try!(parsed.set_weekday(weekday));
|
try!(parsed.set_weekday(weekday));
|
||||||
}
|
}
|
||||||
|
|
||||||
LowerAmPm | UpperAmPm => {
|
&LowerAmPm | &UpperAmPm => {
|
||||||
if s.len() < 2 { return Err(TOO_SHORT); }
|
if s.len() < 2 { return Err(TOO_SHORT); }
|
||||||
let ampm = match (s.as_bytes()[0] | 32, s.as_bytes()[1] | 32) {
|
let ampm = match (s.as_bytes()[0] | 32, s.as_bytes()[1] | 32) {
|
||||||
(b'a',b'm') => false,
|
(b'a',b'm') => false,
|
||||||
|
@ -316,56 +317,56 @@ pub fn parse<'a, I>(parsed: &mut Parsed, mut s: &str, items: I) -> ParseResult<(
|
||||||
s = &s[2..];
|
s = &s[2..];
|
||||||
}
|
}
|
||||||
|
|
||||||
Nanosecond | Nanosecond3 | Nanosecond6 | Nanosecond9 => {
|
&Nanosecond | &Nanosecond3 | &Nanosecond6 | &Nanosecond9 => {
|
||||||
if s.starts_with('.') {
|
if s.starts_with('.') {
|
||||||
let nano = try_consume!(scan::nanosecond(&s[1..]));
|
let nano = try_consume!(scan::nanosecond(&s[1..]));
|
||||||
try!(parsed.set_nanosecond(nano));
|
try!(parsed.set_nanosecond(nano));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => {
|
&Internal(InternalFixed { val: InternalInternal::Nanosecond3NoDot }) => {
|
||||||
if s.len() < 3 { return Err(TOO_SHORT); }
|
if s.len() < 3 { return Err(TOO_SHORT); }
|
||||||
let nano = try_consume!(scan::nanosecond_fixed(s, 3));
|
let nano = try_consume!(scan::nanosecond_fixed(s, 3));
|
||||||
try!(parsed.set_nanosecond(nano));
|
try!(parsed.set_nanosecond(nano));
|
||||||
}
|
}
|
||||||
|
|
||||||
Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => {
|
&Internal(InternalFixed { val: InternalInternal::Nanosecond6NoDot }) => {
|
||||||
if s.len() < 6 { return Err(TOO_SHORT); }
|
if s.len() < 6 { return Err(TOO_SHORT); }
|
||||||
let nano = try_consume!(scan::nanosecond_fixed(s, 6));
|
let nano = try_consume!(scan::nanosecond_fixed(s, 6));
|
||||||
try!(parsed.set_nanosecond(nano));
|
try!(parsed.set_nanosecond(nano));
|
||||||
}
|
}
|
||||||
|
|
||||||
Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => {
|
&Internal(InternalFixed { val: InternalInternal::Nanosecond9NoDot }) => {
|
||||||
if s.len() < 9 { return Err(TOO_SHORT); }
|
if s.len() < 9 { return Err(TOO_SHORT); }
|
||||||
let nano = try_consume!(scan::nanosecond_fixed(s, 9));
|
let nano = try_consume!(scan::nanosecond_fixed(s, 9));
|
||||||
try!(parsed.set_nanosecond(nano));
|
try!(parsed.set_nanosecond(nano));
|
||||||
}
|
}
|
||||||
|
|
||||||
TimezoneName => return Err(BAD_FORMAT),
|
&TimezoneName => return Err(BAD_FORMAT),
|
||||||
|
|
||||||
TimezoneOffsetColon | TimezoneOffset => {
|
&TimezoneOffsetColon | &TimezoneOffset => {
|
||||||
let offset = try_consume!(scan::timezone_offset(s.trim_left(),
|
let offset = try_consume!(scan::timezone_offset(s.trim_left(),
|
||||||
scan::colon_or_space));
|
scan::colon_or_space));
|
||||||
try!(parsed.set_offset(i64::from(offset)));
|
try!(parsed.set_offset(i64::from(offset)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TimezoneOffsetColonZ | TimezoneOffsetZ => {
|
&TimezoneOffsetColonZ | &TimezoneOffsetZ => {
|
||||||
let offset = try_consume!(scan::timezone_offset_zulu(s.trim_left(),
|
let offset = try_consume!(scan::timezone_offset_zulu(s.trim_left(),
|
||||||
scan::colon_or_space));
|
scan::colon_or_space));
|
||||||
try!(parsed.set_offset(i64::from(offset)));
|
try!(parsed.set_offset(i64::from(offset)));
|
||||||
}
|
}
|
||||||
Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => {
|
&Internal(InternalFixed { val: InternalInternal::TimezoneOffsetPermissive }) => {
|
||||||
let offset = try_consume!(scan::timezone_offset_permissive(
|
let offset = try_consume!(scan::timezone_offset_permissive(
|
||||||
s.trim_left(), scan::colon_or_space));
|
s.trim_left(), scan::colon_or_space));
|
||||||
try!(parsed.set_offset(i64::from(offset)));
|
try!(parsed.set_offset(i64::from(offset)));
|
||||||
}
|
}
|
||||||
|
|
||||||
RFC2822 => try_consume!(parse_rfc2822(parsed, s)),
|
&RFC2822 => try_consume!(parse_rfc2822(parsed, s)),
|
||||||
RFC3339 => try_consume!(parse_rfc3339(parsed, s)),
|
&RFC3339 => try_consume!(parse_rfc3339(parsed, s)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item::Error => {
|
&Item::Error => {
|
||||||
return Err(BAD_FORMAT);
|
return Err(BAD_FORMAT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,7 +389,7 @@ fn test_parse() {
|
||||||
// workaround for Rust issue #22255
|
// workaround for Rust issue #22255
|
||||||
fn parse_all(s: &str, items: &[Item]) -> ParseResult<Parsed> {
|
fn parse_all(s: &str, items: &[Item]) -> ParseResult<Parsed> {
|
||||||
let mut parsed = Parsed::new();
|
let mut parsed = Parsed::new();
|
||||||
try!(parse(&mut parsed, s, items.iter().cloned()));
|
try!(parse(&mut parsed, s, items.iter()));
|
||||||
Ok(parsed)
|
Ok(parsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,12 +700,12 @@ fn test_rfc2822() {
|
||||||
|
|
||||||
fn rfc2822_to_datetime(date: &str) -> ParseResult<DateTime<FixedOffset>> {
|
fn rfc2822_to_datetime(date: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||||
let mut parsed = Parsed::new();
|
let mut parsed = Parsed::new();
|
||||||
try!(parse(&mut parsed, date, [Item::Fixed(Fixed::RFC2822)].iter().cloned()));
|
try!(parse(&mut parsed, date, [Item::Fixed(Fixed::RFC2822)].iter()));
|
||||||
parsed.to_datetime()
|
parsed.to_datetime()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_rfc2822_datetime(dt: DateTime<FixedOffset>) -> String {
|
fn fmt_rfc2822_datetime(dt: DateTime<FixedOffset>) -> String {
|
||||||
dt.format_with_items([Item::Fixed(Fixed::RFC2822)].iter().cloned()).to_string()
|
dt.format_with_items([Item::Fixed(Fixed::RFC2822)].iter()).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test against test data above
|
// Test against test data above
|
||||||
|
@ -780,12 +781,12 @@ fn test_rfc3339() {
|
||||||
|
|
||||||
fn rfc3339_to_datetime(date: &str) -> ParseResult<DateTime<FixedOffset>> {
|
fn rfc3339_to_datetime(date: &str) -> ParseResult<DateTime<FixedOffset>> {
|
||||||
let mut parsed = Parsed::new();
|
let mut parsed = Parsed::new();
|
||||||
try!(parse(&mut parsed, date, [Item::Fixed(Fixed::RFC3339)].iter().cloned()));
|
try!(parse(&mut parsed, date, [Item::Fixed(Fixed::RFC3339)].iter()));
|
||||||
parsed.to_datetime()
|
parsed.to_datetime()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_rfc3339_datetime(dt: DateTime<FixedOffset>) -> String {
|
fn fmt_rfc3339_datetime(dt: DateTime<FixedOffset>) -> String {
|
||||||
dt.format_with_items([Item::Fixed(Fixed::RFC3339)].iter().cloned()).to_string()
|
dt.format_with_items([Item::Fixed(Fixed::RFC3339)].iter()).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test against test data above
|
// Test against test data above
|
||||||
|
|
|
@ -112,6 +112,7 @@ pub struct Parsed {
|
||||||
|
|
||||||
/// Checks if `old` is either empty or has the same value to `new` (i.e. "consistent"),
|
/// Checks if `old` is either empty or has the same value to `new` (i.e. "consistent"),
|
||||||
/// and if it is empty, set `old` to `new` as well.
|
/// and if it is empty, set `old` to `new` as well.
|
||||||
|
#[inline]
|
||||||
fn set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<()> {
|
fn set_if_consistent<T: PartialEq>(old: &mut Option<T>, new: T) -> ParseResult<()> {
|
||||||
if let Some(ref old) = *old {
|
if let Some(ref old) = *old {
|
||||||
if *old == new {Ok(())} else {Err(IMPOSSIBLE)}
|
if *old == new {Ok(())} else {Err(IMPOSSIBLE)}
|
||||||
|
@ -141,82 +142,97 @@ impl Parsed {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`year`](#structfield.year) field from given value.
|
/// Tries to set the [`year`](#structfield.year) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_year(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_year(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.year, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.year, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value.
|
/// Tries to set the [`year_div_100`](#structfield.year_div_100) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_year_div_100(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_year_div_100(&mut self, value: i64) -> ParseResult<()> {
|
||||||
if value < 0 { return Err(OUT_OF_RANGE); }
|
if value < 0 { return Err(OUT_OF_RANGE); }
|
||||||
set_if_consistent(&mut self.year_div_100, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.year_div_100, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value.
|
/// Tries to set the [`year_mod_100`](#structfield.year_mod_100) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_year_mod_100(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_year_mod_100(&mut self, value: i64) -> ParseResult<()> {
|
||||||
if value < 0 { return Err(OUT_OF_RANGE); }
|
if value < 0 { return Err(OUT_OF_RANGE); }
|
||||||
set_if_consistent(&mut self.year_mod_100, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.year_mod_100, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`isoyear`](#structfield.isoyear) field from given value.
|
/// Tries to set the [`isoyear`](#structfield.isoyear) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_isoyear(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.isoyear, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.isoyear, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value.
|
/// Tries to set the [`isoyear_div_100`](#structfield.isoyear_div_100) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_isoyear_div_100(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_isoyear_div_100(&mut self, value: i64) -> ParseResult<()> {
|
||||||
if value < 0 { return Err(OUT_OF_RANGE); }
|
if value < 0 { return Err(OUT_OF_RANGE); }
|
||||||
set_if_consistent(&mut self.isoyear_div_100, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.isoyear_div_100, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value.
|
/// Tries to set the [`isoyear_mod_100`](#structfield.isoyear_mod_100) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_isoyear_mod_100(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_isoyear_mod_100(&mut self, value: i64) -> ParseResult<()> {
|
||||||
if value < 0 { return Err(OUT_OF_RANGE); }
|
if value < 0 { return Err(OUT_OF_RANGE); }
|
||||||
set_if_consistent(&mut self.isoyear_mod_100, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.isoyear_mod_100, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`month`](#structfield.month) field from given value.
|
/// Tries to set the [`month`](#structfield.month) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_month(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_month(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.month, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.month, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value.
|
/// Tries to set the [`week_from_sun`](#structfield.week_from_sun) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_week_from_sun(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.week_from_sun, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.week_from_sun, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value.
|
/// Tries to set the [`week_from_mon`](#structfield.week_from_mon) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_week_from_mon(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.week_from_mon, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.week_from_mon, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`isoweek`](#structfield.isoweek) field from given value.
|
/// Tries to set the [`isoweek`](#structfield.isoweek) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_isoweek(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.isoweek, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.isoweek, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`weekday`](#structfield.weekday) field from given value.
|
/// Tries to set the [`weekday`](#structfield.weekday) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_weekday(&mut self, value: Weekday) -> ParseResult<()> {
|
pub fn set_weekday(&mut self, value: Weekday) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.weekday, value)
|
set_if_consistent(&mut self.weekday, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`ordinal`](#structfield.ordinal) field from given value.
|
/// Tries to set the [`ordinal`](#structfield.ordinal) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_ordinal(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.ordinal, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.ordinal, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`day`](#structfield.day) field from given value.
|
/// Tries to set the [`day`](#structfield.day) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_day(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_day(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.day, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.day, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value.
|
/// Tries to set the [`hour_div_12`](#structfield.hour_div_12) field from given value.
|
||||||
/// (`false` for AM, `true` for PM)
|
/// (`false` for AM, `true` for PM)
|
||||||
|
#[inline]
|
||||||
pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> {
|
pub fn set_ampm(&mut self, value: bool) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.hour_div_12, if value {1} else {0})
|
set_if_consistent(&mut self.hour_div_12, if value {1} else {0})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from
|
/// Tries to set the [`hour_mod_12`](#structfield.hour_mod_12) field from
|
||||||
/// given hour number in 12-hour clocks.
|
/// given hour number in 12-hour clocks.
|
||||||
|
#[inline]
|
||||||
pub fn set_hour12(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_hour12(&mut self, value: i64) -> ParseResult<()> {
|
||||||
if value < 1 || value > 12 { return Err(OUT_OF_RANGE); }
|
if value < 1 || value > 12 { return Err(OUT_OF_RANGE); }
|
||||||
set_if_consistent(&mut self.hour_mod_12, value as u32 % 12)
|
set_if_consistent(&mut self.hour_mod_12, value as u32 % 12)
|
||||||
|
@ -224,6 +240,7 @@ impl Parsed {
|
||||||
|
|
||||||
/// Tries to set both [`hour_div_12`](#structfield.hour_div_12) and
|
/// Tries to set both [`hour_div_12`](#structfield.hour_div_12) and
|
||||||
/// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value.
|
/// [`hour_mod_12`](#structfield.hour_mod_12) fields from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_hour(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_hour(&mut self, value: i64) -> ParseResult<()> {
|
||||||
let v = try!(value.to_u32().ok_or(OUT_OF_RANGE));
|
let v = try!(value.to_u32().ok_or(OUT_OF_RANGE));
|
||||||
try!(set_if_consistent(&mut self.hour_div_12, v / 12));
|
try!(set_if_consistent(&mut self.hour_div_12, v / 12));
|
||||||
|
@ -232,26 +249,31 @@ impl Parsed {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`minute`](#structfield.minute) field from given value.
|
/// Tries to set the [`minute`](#structfield.minute) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_minute(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_minute(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.minute, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.minute, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`second`](#structfield.second) field from given value.
|
/// Tries to set the [`second`](#structfield.second) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_second(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_second(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.second, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.second, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value.
|
/// Tries to set the [`nanosecond`](#structfield.nanosecond) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_nanosecond(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.nanosecond, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.nanosecond, try!(value.to_u32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`timestamp`](#structfield.timestamp) field from given value.
|
/// Tries to set the [`timestamp`](#structfield.timestamp) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_timestamp(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_timestamp(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.timestamp, value)
|
set_if_consistent(&mut self.timestamp, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to set the [`offset`](#structfield.offset) field from given value.
|
/// Tries to set the [`offset`](#structfield.offset) field from given value.
|
||||||
|
#[inline]
|
||||||
pub fn set_offset(&mut self, value: i64) -> ParseResult<()> {
|
pub fn set_offset(&mut self, value: i64) -> ParseResult<()> {
|
||||||
set_if_consistent(&mut self.offset, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
set_if_consistent(&mut self.offset, try!(value.to_i32().ok_or(OUT_OF_RANGE)))
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,23 +30,35 @@ fn equals(s: &str, pattern: &str) -> bool {
|
||||||
/// The absence of digits at all is an unconditional error.
|
/// The absence of digits at all is an unconditional error.
|
||||||
/// More than `max` digits are consumed up to the first `max` digits.
|
/// More than `max` digits are consumed up to the first `max` digits.
|
||||||
/// Any number that does not fit in `i64` is an error.
|
/// Any number that does not fit in `i64` is an error.
|
||||||
|
#[inline]
|
||||||
pub fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> {
|
pub fn number(s: &str, min: usize, max: usize) -> ParseResult<(&str, i64)> {
|
||||||
assert!(min <= max);
|
assert!(min <= max);
|
||||||
|
|
||||||
// limit `s` to given number of digits
|
// We are only interested in ascii numbers, so we can work with the `str` as bytes. We stop on
|
||||||
let mut window = s.as_bytes();
|
// the first non-numeric byte, which may be another ascii character or beginning of multi-byte
|
||||||
if window.len() > max { window = &window[..max]; }
|
// UTF-8 character.
|
||||||
|
let bytes = s.as_bytes();
|
||||||
// scan digits
|
if bytes.len() < min {
|
||||||
let upto = window.iter().position(|&c| c < b'0' || b'9' < c)
|
return Err(TOO_SHORT);
|
||||||
.unwrap_or_else(|| window.len());
|
|
||||||
if upto < min {
|
|
||||||
return Err(if window.is_empty() {TOO_SHORT} else {INVALID});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// we can overflow here, which is the only possible cause of error from `parse`.
|
let mut n = 0i64;
|
||||||
let v: i64 = try!(s[..upto].parse().map_err(|_| OUT_OF_RANGE));
|
for (i, c) in bytes.iter().take(max).cloned().enumerate() { // cloned() = copied()
|
||||||
Ok((&s[upto..], v))
|
if c < b'0' || b'9' < c {
|
||||||
|
if i < min {
|
||||||
|
return Err(INVALID);
|
||||||
|
} else {
|
||||||
|
return Ok((&s[i..], n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n = match n.checked_mul(10).and_then(|n| n.checked_add((c - b'0') as i64)) {
|
||||||
|
Some(n) => n,
|
||||||
|
None => return Err(OUT_OF_RANGE),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((&s[::core::cmp::min(max, bytes.len())..], n))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to consume at least one digits as a fractional second.
|
/// Tries to consume at least one digits as a fractional second.
|
||||||
|
|
|
@ -383,9 +383,10 @@
|
||||||
|
|
||||||
#![doc(html_root_url = "https://docs.rs/chrono/latest/")]
|
#![doc(html_root_url = "https://docs.rs/chrono/latest/")]
|
||||||
|
|
||||||
#![cfg_attr(bench, feature(test))] // lib stability features as per RFC #507
|
#![cfg_attr(feature = "bench", feature(test))] // lib stability features as per RFC #507
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
#![deny(missing_debug_implementations)]
|
#![deny(missing_debug_implementations)]
|
||||||
|
#![allow(deprecated)]
|
||||||
|
|
||||||
#![cfg_attr(not(any(feature = "std", test)), no_std)]
|
#![cfg_attr(not(any(feature = "std", test)), no_std)]
|
||||||
|
|
||||||
|
@ -427,6 +428,8 @@ extern crate doc_comment;
|
||||||
extern crate wasm_bindgen;
|
extern crate wasm_bindgen;
|
||||||
#[cfg(all(target_arch = "wasm32", feature="wasmbind"))]
|
#[cfg(all(target_arch = "wasm32", feature="wasmbind"))]
|
||||||
extern crate js_sys;
|
extern crate js_sys;
|
||||||
|
#[cfg(feature = "bench")]
|
||||||
|
extern crate test;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
doctest!("../README.md");
|
doctest!("../README.md");
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
//! ISO 8601 calendar date without timezone.
|
//! ISO 8601 calendar date without timezone.
|
||||||
|
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
use core::borrow::Borrow;
|
||||||
use core::{str, fmt};
|
use core::{str, fmt};
|
||||||
use core::ops::{Add, Sub, AddAssign, SubAssign};
|
use core::ops::{Add, Sub, AddAssign, SubAssign};
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
@ -920,8 +922,8 @@ impl NaiveDate {
|
||||||
/// ~~~~
|
/// ~~~~
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
|
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
|
||||||
where I: Iterator<Item=Item<'a>> + Clone {
|
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
|
||||||
DelayedFormat::new(Some(*self), None, items)
|
DelayedFormat::new(Some(*self), None, items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1507,16 +1509,16 @@ impl str::FromStr for NaiveDate {
|
||||||
|
|
||||||
fn from_str(s: &str) -> ParseResult<NaiveDate> {
|
fn from_str(s: &str) -> ParseResult<NaiveDate> {
|
||||||
const ITEMS: &'static [Item<'static>] = &[
|
const ITEMS: &'static [Item<'static>] = &[
|
||||||
Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero),
|
Item::Numeric(Numeric::Year, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal("-"),
|
Item::Space(""), Item::Literal("-"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero),
|
Item::Numeric(Numeric::Month, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal("-"),
|
Item::Space(""), Item::Literal("-"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero),
|
Item::Numeric(Numeric::Day, Pad::Zero),
|
||||||
Item::Space(""),
|
Item::Space(""),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut parsed = Parsed::new();
|
let mut parsed = Parsed::new();
|
||||||
try!(parse(&mut parsed, s, ITEMS.iter().cloned()));
|
try!(parse(&mut parsed, s, ITEMS.iter()));
|
||||||
parsed.to_naive_date()
|
parsed.to_naive_date()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
//! ISO 8601 date and time without timezone.
|
//! ISO 8601 date and time without timezone.
|
||||||
|
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
use core::borrow::Borrow;
|
||||||
use core::{str, fmt, hash};
|
use core::{str, fmt, hash};
|
||||||
use core::ops::{Add, Sub, AddAssign, SubAssign};
|
use core::ops::{Add, Sub, AddAssign, SubAssign};
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
@ -649,8 +651,8 @@ impl NaiveDateTime {
|
||||||
/// ~~~~
|
/// ~~~~
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
|
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
|
||||||
where I: Iterator<Item=Item<'a>> + Clone {
|
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
|
||||||
DelayedFormat::new(Some(self.date), Some(self.time), items)
|
DelayedFormat::new(Some(self.date), Some(self.time), items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1472,22 +1474,22 @@ impl str::FromStr for NaiveDateTime {
|
||||||
|
|
||||||
fn from_str(s: &str) -> ParseResult<NaiveDateTime> {
|
fn from_str(s: &str) -> ParseResult<NaiveDateTime> {
|
||||||
const ITEMS: &'static [Item<'static>] = &[
|
const ITEMS: &'static [Item<'static>] = &[
|
||||||
Item::Space(""), Item::Numeric(Numeric::Year, Pad::Zero),
|
Item::Numeric(Numeric::Year, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal("-"),
|
Item::Space(""), Item::Literal("-"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Month, Pad::Zero),
|
Item::Numeric(Numeric::Month, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal("-"),
|
Item::Space(""), Item::Literal("-"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Day, Pad::Zero),
|
Item::Numeric(Numeric::Day, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal("T"), // XXX shouldn't this be case-insensitive?
|
Item::Space(""), Item::Literal("T"), // XXX shouldn't this be case-insensitive?
|
||||||
Item::Space(""), Item::Numeric(Numeric::Hour, Pad::Zero),
|
Item::Numeric(Numeric::Hour, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal(":"),
|
Item::Space(""), Item::Literal(":"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Minute, Pad::Zero),
|
Item::Numeric(Numeric::Minute, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal(":"),
|
Item::Space(""), Item::Literal(":"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Second, Pad::Zero),
|
Item::Numeric(Numeric::Second, Pad::Zero),
|
||||||
Item::Fixed(Fixed::Nanosecond), Item::Space(""),
|
Item::Fixed(Fixed::Nanosecond), Item::Space(""),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut parsed = Parsed::new();
|
let mut parsed = Parsed::new();
|
||||||
try!(parse(&mut parsed, s, ITEMS.iter().cloned()));
|
try!(parse(&mut parsed, s, ITEMS.iter()));
|
||||||
parsed.to_naive_datetime_with_offset(0)
|
parsed.to_naive_datetime_with_offset(0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -470,7 +470,6 @@ impl fmt::Debug for Mdf {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
#[cfg(test)] extern crate num_iter;
|
#[cfg(test)] extern crate num_iter;
|
||||||
#[cfg(bench)] extern crate test;
|
|
||||||
|
|
||||||
use Weekday;
|
use Weekday;
|
||||||
use super::{Of, Mdf};
|
use super::{Of, Mdf};
|
||||||
|
@ -517,7 +516,7 @@ mod tests {
|
||||||
assert_eq!(GF.nisoweeks(), 52);
|
assert_eq!(GF.nisoweeks(), 52);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(bench)]
|
#[cfg(feature = "bench")]
|
||||||
#[bench]
|
#[bench]
|
||||||
fn bench_year_flags_from_year(bh: &mut test::Bencher) {
|
fn bench_year_flags_from_year(bh: &mut test::Bencher) {
|
||||||
bh.iter(|| {
|
bh.iter(|| {
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
//! ISO 8601 time without timezone.
|
//! ISO 8601 time without timezone.
|
||||||
|
|
||||||
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
|
use core::borrow::Borrow;
|
||||||
use core::{str, fmt, hash};
|
use core::{str, fmt, hash};
|
||||||
use core::ops::{Add, Sub, AddAssign, SubAssign};
|
use core::ops::{Add, Sub, AddAssign, SubAssign};
|
||||||
use oldtime::Duration as OldDuration;
|
use oldtime::Duration as OldDuration;
|
||||||
|
@ -727,8 +729,8 @@ impl NaiveTime {
|
||||||
/// ~~~~
|
/// ~~~~
|
||||||
#[cfg(any(feature = "alloc", feature = "std", test))]
|
#[cfg(any(feature = "alloc", feature = "std", test))]
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn format_with_items<'a, I>(&self, items: I) -> DelayedFormat<I>
|
pub fn format_with_items<'a, I, B>(&self, items: I) -> DelayedFormat<I>
|
||||||
where I: Iterator<Item=Item<'a>> + Clone {
|
where I: Iterator<Item=B> + Clone, B: Borrow<Item<'a>> {
|
||||||
DelayedFormat::new(None, Some(*self), items)
|
DelayedFormat::new(None, Some(*self), items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1303,16 +1305,16 @@ impl str::FromStr for NaiveTime {
|
||||||
|
|
||||||
fn from_str(s: &str) -> ParseResult<NaiveTime> {
|
fn from_str(s: &str) -> ParseResult<NaiveTime> {
|
||||||
const ITEMS: &'static [Item<'static>] = &[
|
const ITEMS: &'static [Item<'static>] = &[
|
||||||
Item::Space(""), Item::Numeric(Numeric::Hour, Pad::Zero),
|
Item::Numeric(Numeric::Hour, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal(":"),
|
Item::Space(""), Item::Literal(":"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Minute, Pad::Zero),
|
Item::Numeric(Numeric::Minute, Pad::Zero),
|
||||||
Item::Space(""), Item::Literal(":"),
|
Item::Space(""), Item::Literal(":"),
|
||||||
Item::Space(""), Item::Numeric(Numeric::Second, Pad::Zero),
|
Item::Numeric(Numeric::Second, Pad::Zero),
|
||||||
Item::Fixed(Fixed::Nanosecond), Item::Space(""),
|
Item::Fixed(Fixed::Nanosecond), Item::Space(""),
|
||||||
];
|
];
|
||||||
|
|
||||||
let mut parsed = Parsed::new();
|
let mut parsed = Parsed::new();
|
||||||
try!(parse(&mut parsed, s, ITEMS.iter().cloned()));
|
try!(parse(&mut parsed, s, ITEMS.iter()));
|
||||||
parsed.to_naive_time()
|
parsed.to_naive_time()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue