diff options
author | Brock Mendel <jbrockmendel@gmail.com> | 2018-04-20 20:25:29 -0700 |
---|---|---|
committer | Paul Ganssle <paul@ganssle.io> | 2018-05-07 12:44:27 -0400 |
commit | 3364cdb0abcf6be4ce15ef3b2db68b35711229f5 (patch) | |
tree | e3dff5dff645f8d4f3077b9adccc5829cafe37e0 | |
parent | eaa174d4cd7d7a58ae94b0a53f969539c687f916 (diff) | |
download | dateutil-3364cdb0abcf6be4ce15ef3b2db68b35711229f5.tar.gz |
Fix for B.Y.d format corner case #687
Add changelog file
-rw-r--r-- | changelog.d/687.bugfix.rst | 1 | ||||
-rw-r--r-- | dateutil/parser/_parser.py | 40 | ||||
-rw-r--r-- | dateutil/test/test_parser.py | 6 |
3 files changed, 43 insertions, 4 deletions
diff --git a/changelog.d/687.bugfix.rst b/changelog.d/687.bugfix.rst new file mode 100644 index 0000000..7f83add --- /dev/null +++ b/changelog.d/687.bugfix.rst @@ -0,0 +1 @@ +Fixed incorrect parsing of certain dates earlier than 100 AD when repesented in the form "%B.%Y.%d", e.g. "December.0031.30". (gh issue #687, pr #700) diff --git a/dateutil/parser/_parser.py b/dateutil/parser/_parser.py index f749bdf..04bc539 100644 --- a/dateutil/parser/_parser.py +++ b/dateutil/parser/_parser.py @@ -458,10 +458,38 @@ class _ymd(list): raise ValueError('Year is already set') self.ystridx = len(self) - 1 + def _resolve_from_stridxs(self): + """ + Try to resolve the identities of year/month/day elements using + ystridx, mstridx, and dstridx, if enough of these are specified. + """ + strids = {'y': self.ystridx, 'm': self.mstridx, 'd': self.dstridx} + strids = {key: strids[key] for key in strids if strids[key] is not None} + + if len(self) == 3 and len(strids) == 2: + # we can back out the remaining stridx value + missing = [x for x in range(3) if x not in strids.values()] + key = [x for x in ['y', 'm', 'd'] if x not in strids] + assert len(missing) == len(key) == 1 + key = key[0] + val = missing[0] + strids[key] = val + + assert len(self) == len(strids) # otherwise this should not be called + out = {'y': None, 'm': None, 'd': None} + out.update({key: self[strids[key]] for key in strids}) + return (out['y'], out['m'], out['d']) + def resolve_ymd(self, yearfirst, dayfirst): len_ymd = len(self) year, month, day = (None, None, None) + strids = {'y': self.ystridx, 'm': self.mstridx, 'd': self.dstridx} + strids = {key: strids[key] for key in strids if strids[key] is not None} + if (len(self) == len(strids) > 0 or + (len(self) == 3 and len(strids) == 2)): + return self._resolve_from_stridxs() + mstridx = self.mstridx if len_ymd > 3: @@ -470,13 +498,17 @@ class _ymd(list): # One member, or two members with a month string if mstridx is not None: month = self[mstridx] - del self[mstridx] + # since mstridx is 0 or 1, self[mstridx-1] always + # looks up the other element + other = self[mstridx - 1] + else: + other = self[0] if len_ymd > 1 or mstridx is None: - if self[0] > 31: - year = self[0] + if other > 31: + year = other else: - day = self[0] + day = other elif len_ymd == 2: # Two members with numbers diff --git a/dateutil/test/test_parser.py b/dateutil/test/test_parser.py index 029f672..f8c2072 100644 --- a/dateutil/test/test_parser.py +++ b/dateutil/test/test_parser.py @@ -1106,3 +1106,9 @@ def test_decimal_error(value): # constructed with an invalid value with pytest.raises(ValueError): parse(value) + + +def test_BYd_corner_case(): + # GH#687 + res = parse('December.0031.30') + assert res == datetime(31, 12, 30) |