Skip to content

Commit

Permalink
Fix parsing of previously supported formats
Browse files Browse the repository at this point in the history
  • Loading branch information
sdispater committed Jul 18, 2023
1 parent 16b83de commit 93c29e0
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 17 deletions.
45 changes: 45 additions & 0 deletions rust/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ pub struct ParsedDateTime {
pub microsecond: u32,
pub offset: Option<i32>,
pub has_offset: bool,
pub tzname: Option<String>,
pub has_date: bool,
pub has_time: bool,
pub extended_date_format: bool,
Expand All @@ -51,6 +52,7 @@ impl<'a> ParsedDateTime {
microsecond: 0,
offset: None,
has_offset: false,
tzname: None,
has_date: false,
has_time: false,
extended_date_format: false,
Expand Down Expand Up @@ -432,6 +434,8 @@ impl<'a> Parser<'a> {
datetime: &mut ParsedDateTime,
skip_hour: bool,
) -> Result<(), ParseError> {
// TODO: Add support for decimal units

// Date/Time separator
if self.current != 'T' && self.current != ' ' && !skip_hour {
return Err(self.parse_error(format!(
Expand Down Expand Up @@ -601,6 +605,8 @@ impl<'a> Parser<'a> {
} else if !self.end() {
tzminute = self.parse_integer(2, "timezone minute")? as i32;
}
} else {
datetime.tzname = Some("UTC".to_string())
}

if tzminute > 59 {
Expand Down Expand Up @@ -652,6 +658,15 @@ impl<'a> Parser<'a> {
if got_t {
match self.current {
'H' => {
if duration.minutes != 0
|| duration.seconds != 0
|| duration.microseconds != 0
{
return Err(
self.parse_error(format!("Duration units out of order"))
);
}

duration.hours += value;

if let Some(fraction) = op_fraction {
Expand All @@ -670,6 +685,12 @@ impl<'a> Parser<'a> {
}
}
'M' => {
if duration.seconds != 0 || duration.microseconds != 0 {
return Err(
self.parse_error(format!("Duration units out of order"))
);
}

duration.minutes += value;

if let Some(fraction) = op_fraction {
Expand Down Expand Up @@ -704,6 +725,12 @@ impl<'a> Parser<'a> {
)));
}

if duration.months != 0 || duration.days != 0 {
return Err(
self.parse_error(format!("Duration units out of order"))
);
}

duration.years = value;
}
'M' => {
Expand All @@ -713,9 +740,21 @@ impl<'a> Parser<'a> {
)));
}

if duration.days != 0 {
return Err(
self.parse_error(format!("Duration units out of order"))
);
}

duration.months = value;
}
'W' => {
if duration.years != 0 || duration.months != 0 {
return Err(self.parse_error(format!(
"Basic format durations cannot have weeks"
)));
}

duration.weeks = value;

if let Some(fraction) = op_fraction {
Expand All @@ -741,6 +780,12 @@ impl<'a> Parser<'a> {
}
}
'D' => {
if duration.weeks != 0 {
return Err(self.parse_error(format!(
"Week format durations cannot have days"
)));
}

duration.days += value;
if let Some(fraction) = op_fraction {
let extra_hours = fraction * 24.0;
Expand Down
8 changes: 5 additions & 3 deletions rust/python/parsing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub fn parse_iso8601(py: Python, input: &str) -> PyResult<PyObject> {
datetime.second as u8,
datetime.microsecond as u32,
Some(
Py::new(py, FixedTimezone::new(offset, None))?
Py::new(py, FixedTimezone::new(offset, datetime.tzname))?
.to_object(py)
.extract(py)?,
),
Expand Down Expand Up @@ -69,7 +69,7 @@ pub fn parse_iso8601(py: Python, input: &str) -> PyResult<PyObject> {
datetime.second as u8,
datetime.microsecond as u32,
Some(
Py::new(py, FixedTimezone::new(offset, None))?
Py::new(py, FixedTimezone::new(offset, datetime.tzname))?
.to_object(py)
.extract(py)?,
),
Expand Down Expand Up @@ -108,7 +108,9 @@ pub fn parse_iso8601(py: Python, input: &str) -> PyResult<PyObject> {
)?
.to_object(py));
}
(_, _, _) => todo!(),
(_, _, _) => Err(exceptions::PyValueError::new_err(format!(
"Not yet implemented"
))),
},
Err(error) => Err(exceptions::PyValueError::new_err(format!("{}", error))),
}
Expand Down
15 changes: 1 addition & 14 deletions tests/parsing/test_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,19 +276,6 @@ def test_iso8601_datetime():
assert parsed.microsecond == 0
assert parsed.utcoffset().total_seconds() == 19800

text = "20161001T1430,4+0530"

parsed = parse(text)

assert parsed.year == 2016
assert parsed.month == 10
assert parsed.day == 1
assert parsed.hour == 14
assert parsed.minute == 30
assert parsed.second == 0
assert parsed.microsecond == 400000
assert parsed.utcoffset().total_seconds() == 19800

text = "2008-09-03T20:56:35.450686+01"

parsed = parse(text)
Expand Down Expand Up @@ -480,7 +467,7 @@ def test_iso8601_ordinal():
def test_iso8601_time():
now = pendulum.datetime(2015, 11, 12)

text = "201205"
text = "T201205"

parsed = parse(text, now=now)

Expand Down

0 comments on commit 93c29e0

Please sign in to comment.