Skip to content

Commit

Permalink
Merge pull request #700 from jbrockmendel/687
Browse files Browse the repository at this point in the history
Fix for B.Y.d format corner case #687
  • Loading branch information
pganssle committed May 7, 2018
2 parents 65b59f0 + 16561fc commit 99d0b76
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 4 deletions.
1 change: 1 addition & 0 deletions changelog.d/687.bugfix.rst
Original file line number Diff line number Diff line change
@@ -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)
39 changes: 35 additions & 4 deletions dateutil/parser/_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,10 +458,37 @@ def append(self, val, label=None):
raise ValueError('Year is already set')
self.ystridx = len(self) - 1

def _resolve_from_stridxs(self, strids):
"""
Try to resolve the identities of year/month/day elements using
ystridx, mstridx, and dstridx, if enough of these are specified.
"""
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 = {key: self[strids[key]] for key in strids}
return (out.get('y'), out.get('m'), out.get('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: val for key, val in strids if val is not None}
if (len(self) == len(strids) > 0 or
(len(self) == 3 and len(strids) == 2)):
return self._resolve_from_stridxs(strids)

mstridx = self.mstridx

if len_ymd > 3:
Expand All @@ -470,13 +497,17 @@ def resolve_ymd(self, yearfirst, dayfirst):
# 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
Expand Down
6 changes: 6 additions & 0 deletions dateutil/test/test_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit 99d0b76

Please sign in to comment.