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