mirror of
https://github.com/bspeice/dtparse
synced 2024-12-22 12:28:08 -05:00
Fix yearfirst/dayfirst support
This commit is contained in:
parent
d49a12d947
commit
451aa2aeb5
36
src/lib.rs
36
src/lib.rs
@ -745,14 +745,22 @@ pub struct ParsingResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Parser {
|
pub struct Parser {
|
||||||
info: ParserInfo,
|
info: ParserInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parser {
|
impl Parser {
|
||||||
|
pub fn new(info: ParserInfo) -> Self {
|
||||||
|
Parser { info }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn parse(
|
pub fn parse(
|
||||||
&mut self,
|
&mut self,
|
||||||
timestr: &str,
|
timestr: &str,
|
||||||
|
dayfirst: Option<bool>,
|
||||||
|
yearfirst: Option<bool>,
|
||||||
|
fuzzy: bool,
|
||||||
|
fuzzy_with_tokens: bool,
|
||||||
default: Option<&NaiveDateTime>,
|
default: Option<&NaiveDateTime>,
|
||||||
ignoretz: bool,
|
ignoretz: bool,
|
||||||
tzinfos: Vec<String>,
|
tzinfos: Vec<String>,
|
||||||
@ -762,7 +770,8 @@ impl Parser {
|
|||||||
let default_ts = NaiveDateTime::new(default_date, NaiveTime::from_hms(0, 0, 0));
|
let default_ts = NaiveDateTime::new(default_date, NaiveTime::from_hms(0, 0, 0));
|
||||||
|
|
||||||
// TODO: What should be done with the tokens?
|
// TODO: What should be done with the tokens?
|
||||||
let (res, tokens) = self.parse_with_tokens(timestr, None, None, false, false)?;
|
let (res, tokens) =
|
||||||
|
self.parse_with_tokens(timestr, dayfirst, yearfirst, fuzzy, fuzzy_with_tokens)?;
|
||||||
|
|
||||||
let naive = self.build_naive(&res, &default_ts);
|
let naive = self.build_naive(&res, &default_ts);
|
||||||
|
|
||||||
@ -1273,25 +1282,8 @@ fn ljust(s: &str, chars: usize, replace: char) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_with_info(
|
|
||||||
timestr: &str,
|
|
||||||
info: ParserInfo,
|
|
||||||
default: Option<&NaiveDateTime>,
|
|
||||||
) -> ParseResult<(NaiveDateTime, Option<FixedOffset>, Option<Vec<String>>)> {
|
|
||||||
// TODO: Is `::new()` more stylistic?
|
|
||||||
let mut parser = Parser { info: info };
|
|
||||||
parser.parse(timestr, default, false, vec![])
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse_with_default(
|
|
||||||
timestr: &str,
|
|
||||||
default: &NaiveDateTime,
|
|
||||||
) -> ParseResult<(NaiveDateTime, Option<FixedOffset>)> {
|
|
||||||
let parse_result = parse_with_info(timestr, ParserInfo::default(), Some(default))?;
|
|
||||||
Ok((parse_result.0, parse_result.1))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(timestr: &str) -> ParseResult<(NaiveDateTime, Option<FixedOffset>)> {
|
pub fn parse(timestr: &str) -> ParseResult<(NaiveDateTime, Option<FixedOffset>)> {
|
||||||
let parse_result = parse_with_info(timestr, ParserInfo::default(), None)?;
|
let res = Parser::default().parse(timestr, None, None, false, false, None, false, vec![])?;
|
||||||
Ok((parse_result.0, parse_result.1))
|
|
||||||
|
Ok((res.0, res.1))
|
||||||
}
|
}
|
||||||
|
183
tests/compat.rs
183
tests/compat.rs
@ -5,6 +5,7 @@ use chrono::Datelike;
|
|||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
use chrono::Timelike;
|
use chrono::Timelike;
|
||||||
use pyo3::ObjectProtocol;
|
use pyo3::ObjectProtocol;
|
||||||
|
use pyo3::PyBool;
|
||||||
use pyo3::PyDict;
|
use pyo3::PyDict;
|
||||||
use pyo3::PyList;
|
use pyo3::PyList;
|
||||||
use pyo3::PyObject;
|
use pyo3::PyObject;
|
||||||
@ -13,7 +14,8 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
extern crate dtparse;
|
extern crate dtparse;
|
||||||
|
|
||||||
use dtparse::parse_with_default;
|
use dtparse::Parser;
|
||||||
|
use dtparse::ParserInfo;
|
||||||
use dtparse::tokenize;
|
use dtparse::tokenize;
|
||||||
|
|
||||||
macro_rules! test_split {
|
macro_rules! test_split {
|
||||||
@ -44,7 +46,21 @@ fn test_split() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! test_parse {
|
macro_rules! test_parse {
|
||||||
($py:ident, $parser:ident, $datetime:ident, $s:expr) => {
|
// Full parsing options
|
||||||
|
(
|
||||||
|
$py:ident,
|
||||||
|
$parser:ident,
|
||||||
|
$datetime:ident,
|
||||||
|
$info:expr,
|
||||||
|
$s:expr,
|
||||||
|
$dayfirst:expr,
|
||||||
|
$yearfirst:expr,
|
||||||
|
$fuzzy:expr,
|
||||||
|
$fuzzy_with_tokens:expr,
|
||||||
|
$default:expr,
|
||||||
|
$ignoretz:expr,
|
||||||
|
$tzinfos:expr
|
||||||
|
) => {
|
||||||
let default_pydate = $datetime
|
let default_pydate = $datetime
|
||||||
.call_method1("datetime", (2003, 9, 25))
|
.call_method1("datetime", (2003, 9, 25))
|
||||||
.expect("Unable to create default datetime");
|
.expect("Unable to create default datetime");
|
||||||
@ -55,15 +71,30 @@ macro_rules! test_parse {
|
|||||||
kwargs.insert("default", default_pydate);
|
kwargs.insert("default", default_pydate);
|
||||||
kwargs.insert("tzinfos", default_tzinfos.into());
|
kwargs.insert("tzinfos", default_tzinfos.into());
|
||||||
|
|
||||||
|
let py_true = PyBool::new($py, true);
|
||||||
|
if $dayfirst == Some(true) {
|
||||||
|
kwargs.insert("dayfirst", py_true.into());
|
||||||
|
}
|
||||||
|
if $yearfirst == Some(true) {
|
||||||
|
kwargs.insert("yearfirst", py_true.into());
|
||||||
|
}
|
||||||
|
|
||||||
let py_parsed: PyObject = $parser
|
let py_parsed: PyObject = $parser
|
||||||
.call_method("parse", $s, kwargs)
|
.call_method("parse", $s, kwargs)
|
||||||
.expect("Unable to call method `parse`")
|
.expect("Unable to call method `parse`")
|
||||||
.extract()
|
.extract()
|
||||||
.expect("Unable to extract result of `parse` call");
|
.expect("Unable to extract result of `parse` call");
|
||||||
|
|
||||||
let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0);
|
let mut parser = Parser::new($info);
|
||||||
let rs_parsed =
|
let rs_parsed = parser.parse(
|
||||||
parse_with_default($s, default_rsdate).expect("Unable to parse date in Rust");
|
$s,
|
||||||
|
$dayfirst,
|
||||||
|
$yearfirst,
|
||||||
|
$fuzzy,
|
||||||
|
$fuzzy_with_tokens,
|
||||||
|
$default,
|
||||||
|
$ignoretz,
|
||||||
|
$tzinfos).expect("Unable to parse date in Rust");
|
||||||
|
|
||||||
if let Some(_offset) = rs_parsed.1 {
|
if let Some(_offset) = rs_parsed.1 {
|
||||||
// TODO: Handle tests involving timezones
|
// TODO: Handle tests involving timezones
|
||||||
@ -125,9 +156,83 @@ macro_rules! test_parse {
|
|||||||
.expect("Unable to get `microsecond` value")
|
.expect("Unable to get `microsecond` value")
|
||||||
.extract($py)
|
.extract($py)
|
||||||
.expect("Unable to convert `microsecond` to u32");
|
.expect("Unable to convert `microsecond` to u32");
|
||||||
assert_eq!(py_microsecond, rs_dt.nanosecond() / 1000, "Mismatched microsecond for '{}'", $s);
|
assert_eq!(
|
||||||
|
py_microsecond,
|
||||||
|
rs_dt.nanosecond() / 1000,
|
||||||
|
"Mismatched microsecond for '{}'",
|
||||||
|
$s
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(
|
||||||
|
$py:ident,
|
||||||
|
$parser:ident,
|
||||||
|
$datetime:ident,
|
||||||
|
$s:expr
|
||||||
|
) => {
|
||||||
|
let info = ParserInfo::default();
|
||||||
|
let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0);
|
||||||
|
|
||||||
|
test_parse!(
|
||||||
|
$py,
|
||||||
|
$parser,
|
||||||
|
$datetime,
|
||||||
|
info,
|
||||||
|
$s,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
Some(default_rsdate),
|
||||||
|
false,
|
||||||
|
vec![]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! test_parse_yearfirst {
|
||||||
|
($py:ident, $parser:ident, $datetime:ident, $s:expr) => {
|
||||||
|
let info = ParserInfo::default();
|
||||||
|
let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0);
|
||||||
|
|
||||||
|
test_parse!(
|
||||||
|
$py,
|
||||||
|
$parser,
|
||||||
|
$datetime,
|
||||||
|
info,
|
||||||
|
$s,
|
||||||
|
None,
|
||||||
|
Some(true),
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
Some(default_rsdate),
|
||||||
|
false,
|
||||||
|
vec![]
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! test_parse_dayfirst {
|
||||||
|
($py:ident, $parser:ident, $datetime:ident,$s:expr) => {
|
||||||
|
let info = ParserInfo::default();
|
||||||
|
let default_rsdate = &NaiveDate::from_ymd(2003, 9, 25).and_hms(0, 0, 0);
|
||||||
|
|
||||||
|
test_parse!(
|
||||||
|
$py,
|
||||||
|
$parser,
|
||||||
|
$datetime,
|
||||||
|
info,
|
||||||
|
$s,
|
||||||
|
Some(true),
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
Some(default_rsdate),
|
||||||
|
false,
|
||||||
|
vec![]
|
||||||
|
);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -204,56 +309,56 @@ fn test_dateutil_compat() {
|
|||||||
test_parse!(py, parser, datetime, "09-25-2003");
|
test_parse!(py, parser, datetime, "09-25-2003");
|
||||||
// testDateWithDash7
|
// testDateWithDash7
|
||||||
test_parse!(py, parser, datetime, "25-09-2003");
|
test_parse!(py, parser, datetime, "25-09-2003");
|
||||||
// testDateWithDash8 - Needs `dayfirst` support
|
// testDateWithDash8
|
||||||
// test_parse!(py, parser, datetime, "10-09-2003");
|
test_parse_dayfirst!(py, parser, datetime, "10-09-2003");
|
||||||
// testDateWithDash9
|
// testDateWithDash9
|
||||||
test_parse!(py, parser, datetime, "10-09-2003");
|
test_parse!(py, parser, datetime, "10-09-2003");
|
||||||
// testDateWithDash10
|
// testDateWithDash10
|
||||||
test_parse!(py, parser, datetime, "10-09-03");
|
test_parse!(py, parser, datetime, "10-09-03");
|
||||||
// testDateWithDash11 - Needs `yearfirst` support
|
// testDateWithDash11
|
||||||
// test_parse!(py, parser, datetime, "10-09-03")
|
test_parse_yearfirst!(py, parser, datetime, "10-09-03");
|
||||||
// testDateWithDot1
|
// testDateWithDot1
|
||||||
test_parse!(py, parser, datetime, "2003.09.25");
|
test_parse!(py, parser, datetime, "2003.09.25");
|
||||||
// testDateWithDot6
|
// testDateWithDot6
|
||||||
test_parse!(py, parser, datetime, "09.25.2003");
|
test_parse!(py, parser, datetime, "09.25.2003");
|
||||||
// testDateWithDot7
|
// testDateWithDot7
|
||||||
test_parse!(py, parser, datetime, "25.09.2003");
|
test_parse!(py, parser, datetime, "25.09.2003");
|
||||||
// testDateWithDot8 - Needs `dayfirst` support
|
// testDateWithDot8
|
||||||
// test_parse!(py, parser, datetime, "10.09.2003");
|
test_parse_dayfirst!(py, parser, datetime, "10.09.2003");
|
||||||
// testDateWithDot9
|
// testDateWithDot9
|
||||||
test_parse!(py, parser, datetime, "10.09.2003");
|
test_parse!(py, parser, datetime, "10.09.2003");
|
||||||
// testDateWithDot10
|
// testDateWithDot10
|
||||||
test_parse!(py, parser, datetime, "10.09.03");
|
test_parse!(py, parser, datetime, "10.09.03");
|
||||||
// testDateWithDot11 - Needs `yearfirst` support
|
// testDateWithDot11
|
||||||
// test_parse!(py, parser, datetime, "10.09.03");
|
test_parse_yearfirst!(py, parser, datetime, "10.09.03");
|
||||||
// testDateWithSlash1
|
// testDateWithSlash1
|
||||||
test_parse!(py, parser, datetime, "2003/09/25");
|
test_parse!(py, parser, datetime, "2003/09/25");
|
||||||
// testDateWithSlash6
|
// testDateWithSlash6
|
||||||
test_parse!(py, parser, datetime, "09/25/2003");
|
test_parse!(py, parser, datetime, "09/25/2003");
|
||||||
// testDateWithSlash7
|
// testDateWithSlash7
|
||||||
test_parse!(py, parser, datetime, "25/09/2003");
|
test_parse!(py, parser, datetime, "25/09/2003");
|
||||||
// testDateWithSlash8 - Needs `dayfirst` support
|
// testDateWithSlash8
|
||||||
// test_parse!(py, parser, datetime, "10/09/2003");
|
test_parse_dayfirst!(py, parser, datetime, "10/09/2003");
|
||||||
// testDateWithSlash9
|
// testDateWithSlash9
|
||||||
test_parse!(py, parser, datetime, "10/09/2003");
|
test_parse!(py, parser, datetime, "10/09/2003");
|
||||||
// testDateWithSlash10
|
// testDateWithSlash10
|
||||||
test_parse!(py, parser, datetime, "10/09/03");
|
test_parse!(py, parser, datetime, "10/09/03");
|
||||||
// testDateWithSlash11 - Needs `yearfirst` support
|
// testDateWithSlash11
|
||||||
// test_parse!(py, parser, datetime, "10/09/03");
|
test_parse_yearfirst!(py, parser, datetime, "10/09/03");
|
||||||
// testDateWithSpace1
|
// testDateWithSpace1
|
||||||
test_parse!(py, parser, datetime, "2003 09 25");
|
test_parse!(py, parser, datetime, "2003 09 25");
|
||||||
// testDateWithSpace6
|
// testDateWithSpace6
|
||||||
test_parse!(py, parser, datetime, "09 25 2003");
|
test_parse!(py, parser, datetime, "09 25 2003");
|
||||||
// testDateWithSpace7
|
// testDateWithSpace7
|
||||||
test_parse!(py, parser, datetime, "25 09 2003");
|
test_parse!(py, parser, datetime, "25 09 2003");
|
||||||
// testDateWithSpace8 - Needs `dayfirst` support
|
// testDateWithSpace8
|
||||||
// test_parse!(py, parser, datetime, "10 09 2003");
|
test_parse_dayfirst!(py, parser, datetime, "10 09 2003");
|
||||||
// testDateWithSpace9
|
// testDateWithSpace9
|
||||||
test_parse!(py, parser, datetime, "10 09 2003");
|
test_parse!(py, parser, datetime, "10 09 2003");
|
||||||
// testDateWithSpace10
|
// testDateWithSpace10
|
||||||
test_parse!(py, parser, datetime, "10 09 03");
|
test_parse!(py, parser, datetime, "10 09 03");
|
||||||
// testDateWithSpace11 - Needs `yearfirst` support
|
// testDateWithSpace11
|
||||||
// test_parse!(py, parser, datetime, "10 09 03");
|
test_parse_yearfirst!(py, parser, datetime, "10 09 03");
|
||||||
// testDateWithSpace12
|
// testDateWithSpace12
|
||||||
test_parse!(py, parser, datetime, "25 09 03");
|
test_parse!(py, parser, datetime, "25 09 03");
|
||||||
// testStrangelyOrderedDate1
|
// testStrangelyOrderedDate1
|
||||||
@ -273,8 +378,8 @@ fn test_dateutil_compat() {
|
|||||||
|
|
||||||
// TODO: Fix half a minute being 30 seconds
|
// TODO: Fix half a minute being 30 seconds
|
||||||
// testHourWithLettersStrip5
|
// testHourWithLettersStrip5
|
||||||
|
|
||||||
// test_parse!(py, parser, datetime, "10 h 36.5");
|
// test_parse!(py, parser, datetime, "10 h 36.5");
|
||||||
|
|
||||||
// testMinuteWithLettersSpaces1
|
// testMinuteWithLettersSpaces1
|
||||||
test_parse!(py, parser, datetime, "36 m 5");
|
test_parse!(py, parser, datetime, "36 m 5");
|
||||||
// testMinuteWithLettersSpaces2
|
// testMinuteWithLettersSpaces2
|
||||||
@ -335,20 +440,20 @@ fn test_dateutil_compat() {
|
|||||||
|
|
||||||
// testRandomFormat1
|
// testRandomFormat1
|
||||||
test_parse!(py, parser, datetime, "Wed, July 10, '96");
|
test_parse!(py, parser, datetime, "Wed, July 10, '96");
|
||||||
// testRandomFormat2 - Needs `ignoretz`
|
// testRandomFormat2 - Needs ignoretz
|
||||||
// test_parse!(py, parser, datetime, "1996.07.10 AD at 15:08:56 PDT");
|
// test_parse_ignoretz!(py, parser, datetime, "1996.07.10 AD at 15:08:56 PDT");
|
||||||
|
|
||||||
// testRandomFormat3
|
// testRandomFormat3
|
||||||
test_parse!(py, parser, datetime, "1996.July.10 AD 12:08 PM");
|
test_parse!(py, parser, datetime, "1996.July.10 AD 12:08 PM");
|
||||||
|
|
||||||
// testRandomFormat4 - Needs `ignoretz`
|
// testRandomFormat4 - Needs ignoretz
|
||||||
// test_parse!(py, parser, datetime, "Tuesday, April 12, 1952 AD 3:30:42pm PST");
|
// test_parse_ignoretz!(py, parser, datetime, "Tuesday, April 12, 1952 AD 3:30:42pm PST");
|
||||||
// testRandomFormat5 - Needs `ignoretz`
|
// testRandomFormat5 - Needs ignoretz
|
||||||
// test_parse!(py, parser, datetime, "November 5, 1994, 8:15:30 am EST");
|
// test_parse_ignoretz!(py, parser, datetime, "November 5, 1994, 8:15:30 am EST");
|
||||||
// testRandomFormat6 - Needs `ignoretz`
|
// testRandomFormat6 - Needs ignoretz
|
||||||
// test_parse!(py, parser, datetime, "1994-11-05T08:15:30-05:00");
|
// test_parse_ignoretz!(py, parser, datetime, "1994-11-05T08:15:30-05:00");
|
||||||
// testRandomFormat7 - Needs `ignoretz`
|
// testRandomFormat7 - Needs ignoretz
|
||||||
// test_parse!(py, parser, datetime, "1994-11-05T08:15:30Z");
|
// test_parse_ignoretz!(py, parser, datetime, "1994-11-05T08:15:30Z");
|
||||||
// testRandomFormat8
|
// testRandomFormat8
|
||||||
test_parse!(py, parser, datetime, "July 4, 1976");
|
test_parse!(py, parser, datetime, "July 4, 1976");
|
||||||
// testRandomFormat9
|
// testRandomFormat9
|
||||||
@ -365,22 +470,22 @@ fn test_dateutil_compat() {
|
|||||||
test_parse!(py, parser, datetime, "12h 01m02s am");
|
test_parse!(py, parser, datetime, "12h 01m02s am");
|
||||||
// testRandomFormat15; NB: testRandomFormat16 is exactly the same
|
// testRandomFormat15; NB: testRandomFormat16 is exactly the same
|
||||||
test_parse!(py, parser, datetime, "0:01:02 on July 4, 1976");
|
test_parse!(py, parser, datetime, "0:01:02 on July 4, 1976");
|
||||||
// testRandomFormat17 - Needs `ignoretz`
|
// testRandomFormat17 - Needs ignoretz
|
||||||
// test_parse!(py, parser, datetime, "1976-07-04T00:01:02Z");
|
// test_parse_ignoretz!(py, parser, datetime, "1976-07-04T00:01:02Z");
|
||||||
// testRandomFormat18
|
// testRandomFormat18
|
||||||
test_parse!(py, parser, datetime, "July 4, 1976 12:01:02 am");
|
test_parse!(py, parser, datetime, "July 4, 1976 12:01:02 am");
|
||||||
// testRandomFormat19
|
// testRandomFormat19
|
||||||
test_parse!(py, parser, datetime, "Mon Jan 2 04:24:27 1995");
|
test_parse!(py, parser, datetime, "Mon Jan 2 04:24:27 1995");
|
||||||
// testRandomFormat20 - Needs `ignoretz`
|
// testRandomFormat20 - Needs ignoretz
|
||||||
// test_parse!(py, parser, datetime, "Tue Apr 4 00:22:12 PDT 1995");
|
// test_parse_ignoretz!(py, parser, datetime, "Tue Apr 4 00:22:12 PDT 1995");
|
||||||
// testRandomFormat21
|
// testRandomFormat21
|
||||||
test_parse!(py, parser, datetime, "04.04.95 00:22");
|
test_parse!(py, parser, datetime, "04.04.95 00:22");
|
||||||
// testRandomFormat22
|
// testRandomFormat22
|
||||||
test_parse!(py, parser, datetime, "Jan 1 1999 11:23:34.578");
|
test_parse!(py, parser, datetime, "Jan 1 1999 11:23:34.578");
|
||||||
// testRandomFormat23
|
// testRandomFormat23
|
||||||
test_parse!(py, parser, datetime, "950404 122212");
|
test_parse!(py, parser, datetime, "950404 122212");
|
||||||
// testRandomFormat24 - Needs `ignoretz`
|
// testRandomFormat24 - Needs ignoretz
|
||||||
// test_parse!(py, parser, datetime, "0:00 PM, PST");
|
// test_parse_ignoretz!(py, parser, datetime, "0:00 PM, PST");
|
||||||
// testRandomFormat25
|
// testRandomFormat25
|
||||||
test_parse!(py, parser, datetime, "12:08 PM");
|
test_parse!(py, parser, datetime, "12:08 PM");
|
||||||
// testRandomFormat26
|
// testRandomFormat26
|
||||||
|
Loading…
Reference in New Issue
Block a user