From 1f0ecc4de5a94cd2e97f171cdf514a9500909277 Mon Sep 17 00:00:00 2001 From: Christopher Field <chris.field@theiascientific.com> Date: Wed, 30 Mar 2022 14:40:39 -0400 Subject: [PATCH 1/3] Add support for alternative separator An interval is split on either a `/` or a `--`. According to the Wikipedia entry on ISO8601 Intervals: >Section 3.2.6 of ISO 8601-1:2019 notes that "A solidus may be replaced >by a double hyphen ["--"] by mutual agreement of the communicating >partners", and previous versions used notations like "2000--2002".[39] >Use of a double hyphen instead of a solidus allows inclusion in computer >filenames;[40] in common operating systems, a solidus is a reserved >character and is not allowed in a filename. --- pendulum/parsing/__init__.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pendulum/parsing/__init__.py b/pendulum/parsing/__init__.py index 1d15023b..26c76a38 100644 --- a/pendulum/parsing/__init__.py +++ b/pendulum/parsing/__init__.py @@ -212,10 +212,11 @@ def __init__(self, start=None, end=None, duration=None): def _parse_iso8601_interval(text): - if "/" not in text: + if "/" not in text and "--" not in text: raise ParserError("Invalid interval") - first, last = text.split("/") + # first, last = text.split("/") + first, last = re.split("/|--", text) start = end = duration = None if first[0] == "P": From 3d1660e915f65fd0cc9baa02d7be0b974b39c1ba Mon Sep 17 00:00:00 2001 From: Christopher Field <chris.field@theiascientific.com> Date: Wed, 30 Mar 2022 14:41:58 -0400 Subject: [PATCH 2/3] Add tests for new interval separator Tests that parse the compact ISO8601 datetime format are added along with copies of the same tests using the `--` instead of the `/` separator. This ensures parity between parsing regardless of separator. However, no test has been added if _both_ `--` and `/` appear in the text. --- tests/test_parsing.py | 90 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/tests/test_parsing.py b/tests/test_parsing.py index 3dcf050b..5f685145 100644 --- a/tests/test_parsing.py +++ b/tests/test_parsing.py @@ -101,6 +101,16 @@ def test_parse_interval(): assert_datetime(period.end, 2009, 7, 21, 18, 0, 0, 0) assert period.end.offset == 0 + text = "20080511T153000Z/P1Y2M10DT2H30M" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Period) + assert_datetime(period.start, 2008, 5, 11, 15, 30, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2009, 7, 21, 18, 0, 0, 0) + assert period.end.offset == 0 + text = "P1Y2M10DT2H30M/2008-05-11T15:30:00Z" period = pendulum.parse(text) @@ -111,6 +121,16 @@ def test_parse_interval(): assert_datetime(period.end, 2008, 5, 11, 15, 30, 0, 0) assert period.end.offset == 0 + text = "P1Y2M10DT2H30M/20080511T153000Z" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Period) + assert_datetime(period.start, 2007, 3, 1, 13, 0, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2008, 5, 11, 15, 30, 0, 0) + assert period.end.offset == 0 + text = "2007-03-01T13:00:00Z/2008-05-11T15:30:00Z" period = pendulum.parse(text) @@ -121,6 +141,76 @@ def test_parse_interval(): assert_datetime(period.end, 2008, 5, 11, 15, 30, 0, 0) assert period.end.offset == 0 + text = "20070301T130000Z/20080511T153000Z" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Period) + assert_datetime(period.start, 2007, 3, 1, 13, 0, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2008, 5, 11, 15, 30, 0, 0) + assert period.end.offset == 0 + + text = "2008-05-11T15:30:00Z--P1Y2M10DT2H30M" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Period) + assert_datetime(period.start, 2008, 5, 11, 15, 30, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2009, 7, 21, 18, 0, 0, 0) + assert period.end.offset == 0 + + text = "20080511T153000Z--P1Y2M10DT2H30M" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Period) + assert_datetime(period.start, 2008, 5, 11, 15, 30, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2009, 7, 21, 18, 0, 0, 0) + assert period.end.offset == 0 + + text = "P1Y2M10DT2H30M--2008-05-11T15:30:00Z" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Period) + assert_datetime(period.start, 2007, 3, 1, 13, 0, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2008, 5, 11, 15, 30, 0, 0) + assert period.end.offset == 0 + + text = "P1Y2M10DT2H30M--20080511T153000Z" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Period) + assert_datetime(period.start, 2007, 3, 1, 13, 0, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2008, 5, 11, 15, 30, 0, 0) + assert period.end.offset == 0 + + text = "2007-03-01T13:00:00Z--2008-05-11T15:30:00Z" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Period) + assert_datetime(period.start, 2007, 3, 1, 13, 0, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2008, 5, 11, 15, 30, 0, 0) + assert period.end.offset == 0 + + text = "20070301T130000Z--20080511T153000Z" + + period = pendulum.parse(text) + + assert isinstance(period, pendulum.Period) + assert_datetime(period.start, 2007, 3, 1, 13, 0, 0, 0) + assert period.start.offset == 0 + assert_datetime(period.end, 2008, 5, 11, 15, 30, 0, 0) + assert period.end.offset == 0 + def test_parse_now(): dt = pendulum.parse("now") From 15bc53f0e04c4908512089135ac776302918a991 Mon Sep 17 00:00:00 2001 From: Christopher Field <chris.field@theiascientific.com> Date: Thu, 31 Mar 2022 13:29:48 -0400 Subject: [PATCH 3/3] Add more examples of interval parsing to docs --- docs/docs/parsing.md | 80 ++++++++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/docs/docs/parsing.md b/docs/docs/parsing.md index dd78fd45..719dbce6 100644 --- a/docs/docs/parsing.md +++ b/docs/docs/parsing.md @@ -37,66 +37,74 @@ ParserError: Unable to parse string [31-01-01] '2031-01-01T00:00:00+00:00' ``` - ## RFC 3339 -| String | Output | -| --------------------------------- | ------------------------------------------| -| 1996-12-19T16:39:57-08:00 | 1996-12-19T16:39:57-08:00 | -| 1990-12-31T23:59:59Z | 1990-12-31T23:59:59+00:00 | +| String | Output | +| ------------------------- | ------------------------- | +| 1996-12-19T16:39:57-08:00 | 1996-12-19T16:39:57-08:00 | +| 1990-12-31T23:59:59Z | 1990-12-31T23:59:59+00:00 | ## ISO 8601 ### Datetime -| String | Output | -| --------------------------------- | ----------------------------------------- | -| 20161001T143028+0530 | 2016-10-01T14:30:28+05:30 | -| 20161001T14 | 2016-10-01T14:00:00+00:00 | +| String | Output | +| -------------------- | ------------------------- | +| 20161001T143028+0530 | 2016-10-01T14:30:28+05:30 | +| 20161001T14 | 2016-10-01T14:00:00+00:00 | ### Date -| String | Output | -| --------------------------------- | ----------------------------------------- | -| 2012 | 2012-01-01T00:00:00+00:00 | -| 2012-05-03 | 2012-05-03T00:00:00+00:00 | -| 20120503 | 2012-05-03T00:00:00+00:00 | -| 2012-05 | 2012-05-01T00:00:00+00:00 | +| String | Output | +| ---------- | ------------------------- | +| 2012 | 2012-01-01T00:00:00+00:00 | +| 2012-05-03 | 2012-05-03T00:00:00+00:00 | +| 20120503 | 2012-05-03T00:00:00+00:00 | +| 2012-05 | 2012-05-01T00:00:00+00:00 | ### Ordinal day -| String | Output | -| ---------------------------------- | ----------------------------------------- | -| 2012-007 | 2012-01-07T00:00:00+00:00 | -| 2012007 | 2012-01-07T00:00:00+00:00 | +| String | Output | +| -------- | ------------------------- | +| 2012-007 | 2012-01-07T00:00:00+00:00 | +| 2012007 | 2012-01-07T00:00:00+00:00 | ### Week number -| String | Output | -| --------------------------------- | ----------------------------------------- | -| 2012-W05 | 2012-01-30T00:00:00+00:00 | -| 2012W05 | 2012-01-30T00:00:00+00:00 | -| 2012-W05-5 | 2012-02-03T00:00:00+00:00 | -| 2012W055 | 2012-02-03T00:00:00+00:00 | +| String | Output | +| ---------- | ------------------------- | +| 2012-W05 | 2012-01-30T00:00:00+00:00 | +| 2012W05 | 2012-01-30T00:00:00+00:00 | +| 2012-W05-5 | 2012-02-03T00:00:00+00:00 | +| 2012W055 | 2012-02-03T00:00:00+00:00 | ### Time When passing only time information the date will default to today. -| String | Output | -| --------------------------------- | ------------------------------------------ | -| 00:00 | 2016-12-17T00:00:00+00:00 | -| 12:04:23 | 2016-12-17T12:04:23+00:00 | -| 120423 | 2016-12-17T12:04:23+00:00 | -| 12:04:23.45 | 2016-12-17T12:04:23.450000+00:00 | +| String | Output | +| ----------- | -------------------------------- | +| 00:00 | 2016-12-17T00:00:00+00:00 | +| 12:04:23 | 2016-12-17T12:04:23+00:00 | +| 120423 | 2016-12-17T12:04:23+00:00 | +| 12:04:23.45 | 2016-12-17T12:04:23.450000+00:00 | ### Intervals -| String | Output | -| ----------------------------------------- | ------------------------------------------------------ | -| 2007-03-01T13:00:00Z/2008-05-11T15:30:00Z | 2007-03-01T13:00:00+00:00 -> 2008-05-11T15:30:00+00:00 | -| 2008-05-11T15:30:00Z/P1Y2M10DT2H30M | 2008-05-11T15:30:00+00:00 -> 2009-07-21T18:00:00+00:00 | -| P1Y2M10DT2H30M/2008-05-11T15:30:00Z | 2007-03-01T13:00:00+00:00 -> 2008-05-11T15:30:00+00:00 | +| String | Output | +| ------------------------------------------ | ------------------------------------------------------ | +| 2007-03-01T13:00:00Z/2008-05-11T15:30:00Z | 2007-03-01T13:00:00+00:00 -> 2008-05-11T15:30:00+00:00 | +| 2008-05-11T15:30:00Z/P1Y2M10DT2H30M | 2008-05-11T15:30:00+00:00 -> 2009-07-21T18:00:00+00:00 | +| P1Y2M10DT2H30M/2008-05-11T15:30:00Z | 2007-03-01T13:00:00+00:00 -> 2008-05-11T15:30:00+00:00 | +| 20070301T130000Z/20080511T153000Z | 2007-03-01T13:00:00+00:00 -> 2008-05-11T15:30:00+00:00 | +| 20080511T153000Z/P1Y2M10DT2H30M | 2008-05-11T15:30:00+00:00 -> 2009-07-21T18:00:00+00:00 | +| P1Y2M10DT2H30M/20080511T153000Z | 2007-03-01T13:00:00+00:00 -> 2008-05-11T15:30:00+00:00 | +| 2007-03-01T13:00:00Z--2008-05-11T15:30:00Z | 2007-03-01T13:00:00+00:00 -> 2008-05-11T15:30:00+00:00 | +| 2008-05-11T15:30:00Z--P1Y2M10DT2H30M | 2008-05-11T15:30:00+00:00 -> 2009-07-21T18:00:00+00:00 | +| P1Y2M10DT2H30M--2008-05-11T15:30:00Z | 2007-03-01T13:00:00+00:00 -> 2008-05-11T15:30:00+00:00 | +| 20070301T130000Z--20080511T153000Z | 2007-03-01T13:00:00+00:00 -> 2008-05-11T15:30:00+00:00 | +| 20080511T153000Z--P1Y2M10DT2H30M | 2008-05-11T15:30:00+00:00 -> 2009-07-21T18:00:00+00:00 | +| P1Y2M10DT2H30M--20080511T153000Z | 2007-03-01T13:00:00+00:00 -> 2008-05-11T15:30:00+00:00 | !!!note