use combine::*;
use combine::char::{char, digit};
use combine::combinator::{skip_count_min_max, SkipCountMinMax};
use chrono;
use combine::primitives::RangeStream;
use combine::range::{recognize, recognize_with_value};
use value;
#[inline]
pub fn repeat<P: Parser>(count: usize, parser: P) -> SkipCountMinMax<P> {
skip_count_min_max(count, count, parser)
}
parse!(date_time() -> value::DateTime, {
choice!(
recognize_with_value((
full_date(),
optional((
char('T'),
partial_time(),
optional(time_offset()),
))
))
.and_then(|(s, (_, opt))| {
match opt {
Some((_, _, Some(_))) => {
chrono::DateTime::parse_from_rfc3339(s)
.map(value::DateTime::OffsetDateTime)
}
Some(_) => {
s.parse::<chrono::NaiveDateTime>()
.map(value::DateTime::LocalDateTime)
}
None => {
s.parse::<chrono::NaiveDate>()
.map(value::DateTime::LocalDate)
}
}
}),
recognize(partial_time())
.and_then(|s: &str| s.parse::<chrono::NaiveTime>())
.message("While parsing a Time")
.map(value::DateTime::LocalTime)
)
.message("While parsing a Date-Time")
});
parse!(full_date() -> &'a str, {
recognize((
try((repeat(4, digit()), char('-'))),
repeat(2, digit()),
char('-'),
repeat(2, digit()),
))
});
parse!(partial_time() -> (), {
(
try((
repeat(2, digit()),
char(':'),
)),
repeat(2, digit()),
char(':'),
repeat(2, digit()),
optional(try(char('.')).and(skip_many1(digit()))),
).map(|_| ())
});
parse!(time_offset() -> (), {
try(char('Z')).map(|_| ())
.or(
(
try(choice([char('+'), char('-')])),
repeat(2, digit()),
char(':'),
repeat(2, digit()),
).map(|_| ())
).message("While parsing a Time Offset")
});