From f434f7a6b54e41106d20991a176994c6a62ad9e9 Mon Sep 17 00:00:00 2001 From: andrewchouman Date: Sun, 24 Nov 2019 21:27:08 -0500 Subject: [PATCH] Fixed issue #701 --- arrow/parser.py | 17 +++++++++++------ docs/index.rst | 12 ++++++++++++ tests/parser_tests.py | 29 ++++++++++++++++++++++++++++- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/arrow/parser.py b/arrow/parser.py index a13b7152e..2b7ef812f 100644 --- a/arrow/parser.py +++ b/arrow/parser.py @@ -218,6 +218,7 @@ def parse(self, datetime_string, fmt): fmt_tokens, fmt_pattern_re = self._generate_pattern_re(fmt) match = fmt_pattern_re.search(datetime_string) + if match is None: raise ParserMatchError( "Failed to match '{}' when parsing '{}'".format(fmt, datetime_string) @@ -292,12 +293,16 @@ def _generate_pattern_re(self, fmt): # and time string in a natural language sentence. Therefore, searching # for a string of the form YYYY-MM-DD in "blah 1998-09-12 blah" will # work properly. - # Reference: https://stackoverflow.com/q/14232931/3820660 - starting_word_boundary = r"(?\s])(\b|^)" + ending_punctuation_bound = r"(?=[,.;:?!\"'`\[\]{}()<>]?(?!\S))" + bounded_fmt_pattern = r"{}{}{}".format(starting_punctuation_bound, + final_fmt_pattern, + ending_punctuation_bound) return tokens, re.compile(bounded_fmt_pattern, flags=re.IGNORECASE) diff --git a/docs/index.rst b/docs/index.rst index 16ffb347d..d066f7862 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -212,6 +212,7 @@ Support for a growing number of locales (see ``locales.py`` for supported langua .. code-block:: python + >>> future = arrow.utcnow().shift(hours=1) >>> future.humanize(a, locale='ru') 'через 2 час(а,ов)' @@ -427,6 +428,17 @@ You can also escape regular expressions by enclosing them within square brackets >>> arrow.get("Mon Sep 08 16:41:45 2014", fmt) +Punctuation +~~~~~~~~~~~ + +You're date formats can be precede and/or be preceded by one character of +punctuation from the list: :code:`, . ; : ? ! " ' ` [ ] { } ( ) < >` + +.. code-block:: python + + >>> arrow.get("Tomorrow (2019-10-31) is Halloween!", "YYYY-MM-DD") + + API Guide --------- diff --git a/tests/parser_tests.py b/tests/parser_tests.py index 93eefc5c5..93a5e7956 100644 --- a/tests/parser_tests.py +++ b/tests/parser_tests.py @@ -472,7 +472,10 @@ def test_parse_with_extra_words_at_start_and_end_invalid(self): def test_parse_with_extra_words_at_start_and_end_valid(self): # Spaces surrounding the parsable date are ok because we - # allow the parsing of natural language input + # allow the parsing of natural language input. Additionally, a single + # character of specific punctuation before or after the date is okay. + # See docs for full list of valid punctuation. + self.assertEqual( self.parser.parse("blah 2016 blah", "YYYY"), datetime(2016, 1, 1) ) @@ -527,6 +530,30 @@ def test_parse_with_extra_words_at_start_and_end_valid(self): datetime(2016, 5, 16, 4, 5, 6, 789120), ) + self.assertEqual( + self.parser.parse( + "Meet me at my house on the my birthday (2019-24-11)", + "YYYY-DD-MM" + ), + datetime(2019, 11, 24) + ) + + self.assertEqual( + self.parser.parse( + "Monday, 9. September 2019, 16:15-20:00", + "dddd, D. MMMM YYYY" + ), + datetime(2019, 9, 9) + ) + + self.assertEqual( + self.parser.parse( + "A date is 11.11.2011.", + "DD.MM.YYYY" + ), + datetime(2011, 11, 11) + ) + def test_parse_with_leading_and_trailing_whitespace(self): self.assertEqual(self.parser.parse(" 2016", "YYYY"), datetime(2016, 1, 1))