Don't panic on bad date strings (#1051)
* Don't panic on bad date strings Instead, show a helpful error message explaining only RFC3339 is supported. Fixes #993. * Try to parse the full range of TOML date formats
This commit is contained in:
parent
6708f7637c
commit
c4154bb8c4
|
@ -57,6 +57,18 @@ pub struct PageFrontMatter {
|
||||||
pub extra: Map<String, Value>,
|
pub extra: Map<String, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Parse a TOML datetime from a string.
|
||||||
|
/// There are three alternatives: an offset datetime (plain RFC3339), a local datetime
|
||||||
|
/// (RFC3339 with timezone omitted) and a local date (YYYY-MM-DD). This tries each in
|
||||||
|
/// order.
|
||||||
|
fn parse_datetime(d: &String) -> Option<NaiveDateTime> {
|
||||||
|
DateTime::parse_from_rfc3339(d)
|
||||||
|
.or(DateTime::parse_from_rfc3339(format!("{}Z", d).as_ref()))
|
||||||
|
.map(|s| s.naive_local())
|
||||||
|
.or(NaiveDate::parse_from_str(d, "%Y-%m-%d").map(|s| s.and_hms(0, 0, 0)))
|
||||||
|
.ok()
|
||||||
|
}
|
||||||
|
|
||||||
impl PageFrontMatter {
|
impl PageFrontMatter {
|
||||||
pub fn parse(toml: &str) -> Result<PageFrontMatter> {
|
pub fn parse(toml: &str) -> Result<PageFrontMatter> {
|
||||||
let mut f: PageFrontMatter = match toml::from_str(toml) {
|
let mut f: PageFrontMatter = match toml::from_str(toml) {
|
||||||
|
@ -83,27 +95,20 @@ impl PageFrontMatter {
|
||||||
|
|
||||||
f.date_to_datetime();
|
f.date_to_datetime();
|
||||||
|
|
||||||
|
if let Some(ref date) = f.date {
|
||||||
|
if f.datetime.is_none() {
|
||||||
|
bail!("`date` could not be parsed: {}.", date);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(f)
|
Ok(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts the TOML datetime to a Chrono naive datetime
|
/// Converts the TOML datetime to a Chrono naive datetime
|
||||||
/// Also grabs the year/month/day tuple that will be used in serialization
|
/// Also grabs the year/month/day tuple that will be used in serialization
|
||||||
pub fn date_to_datetime(&mut self) {
|
pub fn date_to_datetime(&mut self) {
|
||||||
self.datetime = if let Some(ref d) = self.date {
|
self.datetime = self.date.as_ref().and_then(parse_datetime);
|
||||||
if d.contains('T') {
|
self.datetime_tuple = self.datetime.map(|dt| (dt.year(), dt.month(), dt.day()));
|
||||||
DateTime::parse_from_rfc3339(&d).ok().map(|s| s.naive_local())
|
|
||||||
} else {
|
|
||||||
NaiveDate::parse_from_str(&d, "%Y-%m-%d").ok().map(|s| s.and_hms(0, 0, 0))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
self.datetime_tuple = if let Some(ref dt) = self.datetime {
|
|
||||||
Some((dt.year(), dt.month(), dt.day()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn order(&self) -> usize {
|
pub fn order(&self) -> usize {
|
||||||
|
@ -198,7 +203,7 @@ mod tests {
|
||||||
date = 2016-10-10
|
date = 2016-10-10
|
||||||
"#;
|
"#;
|
||||||
let res = PageFrontMatter::parse(content).unwrap();
|
let res = PageFrontMatter::parse(content).unwrap();
|
||||||
assert!(res.date.is_some());
|
assert!(res.datetime.is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -209,7 +214,51 @@ mod tests {
|
||||||
date = 2002-10-02T15:00:00Z
|
date = 2002-10-02T15:00:00Z
|
||||||
"#;
|
"#;
|
||||||
let res = PageFrontMatter::parse(content).unwrap();
|
let res = PageFrontMatter::parse(content).unwrap();
|
||||||
assert!(res.date.is_some());
|
assert!(res.datetime.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_parse_date_rfc3339_without_timezone() {
|
||||||
|
let content = r#"
|
||||||
|
title = "Hello"
|
||||||
|
description = "hey there"
|
||||||
|
date = 2002-10-02T15:00:00
|
||||||
|
"#;
|
||||||
|
let res = PageFrontMatter::parse(content).unwrap();
|
||||||
|
assert!(res.datetime.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_parse_date_rfc3339_with_space() {
|
||||||
|
let content = r#"
|
||||||
|
title = "Hello"
|
||||||
|
description = "hey there"
|
||||||
|
date = 2002-10-02 15:00:00+02:00
|
||||||
|
"#;
|
||||||
|
let res = PageFrontMatter::parse(content).unwrap();
|
||||||
|
assert!(res.datetime.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_parse_date_rfc3339_with_space_without_timezone() {
|
||||||
|
let content = r#"
|
||||||
|
title = "Hello"
|
||||||
|
description = "hey there"
|
||||||
|
date = 2002-10-02 15:00:00
|
||||||
|
"#;
|
||||||
|
let res = PageFrontMatter::parse(content).unwrap();
|
||||||
|
assert!(res.datetime.is_some());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_parse_date_rfc3339_with_microseconds() {
|
||||||
|
let content = r#"
|
||||||
|
title = "Hello"
|
||||||
|
description = "hey there"
|
||||||
|
date = 2002-10-02T15:00:00.123456Z
|
||||||
|
"#;
|
||||||
|
let res = PageFrontMatter::parse(content).unwrap();
|
||||||
|
assert!(res.datetime.is_some());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Reference in a new issue