Skip to content

Commit

Permalink
Merge pull request #63 from dateutil/parser-fixes
Browse files Browse the repository at this point in the history
Fix AM/PM flag issue with fuzzy parser
  • Loading branch information
pganssle committed Mar 22, 2015
2 parents 4e17b7f + d707d78 commit b913315
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 12 deletions.
50 changes: 38 additions & 12 deletions dateutil/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,9 +370,14 @@ def parse(self, timestr, default=None, ignoretz=False, tzinfos=None,
`datetime.datetime` object, the second a tuple containing the
fuzzy tokens.
:raises ValueError: Raised for invalid or unknown string format.
:raises ValueError: Raised if provided `tzinfos` are not in a valid
format.
:raises ValueError:
Raised for invalid or unknown string format, if the provided
`tzinfo` is not in a valid format, or if an invalid date would
be created.
:raises OverFlowError:
Raised if the parsed date exceeds the largest valid C integer on
your system.
"""

default_specified = default is not None
Expand Down Expand Up @@ -435,7 +440,7 @@ def parse(self, timestr, default=None, ignoretz=False, tzinfos=None,
class _result(_resultbase):
__slots__ = ["year", "month", "day", "weekday",
"hour", "minute", "second", "microsecond",
"tzname", "tzoffset"]
"tzname", "tzoffset", "ampm"]

def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False,
fuzzy_with_tokens=False):
Expand Down Expand Up @@ -750,18 +755,39 @@ def _parse(self, timestr, dayfirst=None, yearfirst=None, fuzzy=False,
# Check am/pm
value = info.ampm(l[i])
if value is not None:
# For fuzzy parsing, 'a' or 'am' (both valid English words)
# may erroneously trigger the AM/PM flag. Deal with that
# here.
val_is_ampm = True

# If there's already an AM/PM flag, this one isn't one.
if fuzzy and res.ampm is not None:
val_is_ampm = False

# If AM/PM is found and hour is not, raise a ValueError
if res.hour is None:
raise ValueError('No hour specified with AM or PM flag.')
if fuzzy:
val_is_ampm = False
else:
raise ValueError('No hour specified with ' +
'AM or PM flag.')
elif not 0 <= res.hour <= 12:
# If AM/PM is found, it's a 12 hour clock, so raise
# an error for invalid range
if fuzzy:
val_is_ampm = False
else:
raise ValueError('Invalid hour specified for ' +
'12-hour clock.')

if val_is_ampm:
if value == 1 and res.hour < 12:
res.hour += 12
elif value == 0 and res.hour == 12:
res.hour = 0

# If AM/PM is found, it's a 12 hour clock, so raise an error for invalid range
if not 0 <= res.hour <= 12:
raise ValueError('Invalid hour specified for 12-hour clock.')
res.ampm = value

if value == 1 and res.hour < 12:
res.hour += 12
elif value == 0 and res.hour == 12:
res.hour = 0
i += 1
continue

Expand Down
15 changes: 15 additions & 0 deletions dateutil/test/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3612,6 +3612,21 @@ def testFuzzyWithTokens(self):
('Today is ', 'of ', ', exactly at ',
' with timezone ', '.')))

def testFuzzyAMPMProblem(self):
# Sometimes fuzzy parsing results in AM/PM flag being set without
# hours - if it's fuzzy it should ignore that.
s1 = "I have a meeting on March 1, 1974."
s2 = "On June 8th, 2020, I am going to be the first man on Mars"

# Also don't want any erroneous AM or PMs changing the parsed time
s3 = "Meet me at the AM/PM on Sunset at 3:00 AM on December 3rd, 2003"
s4 = "Meet me at 3:00AM on December 3rd, 2003 at the AM/PM on Sunset"

self.assertEqual(parse(s1, fuzzy=True), datetime(1974, 3, 1))
self.assertEqual(parse(s2, fuzzy=True), datetime(2020, 6, 8))
self.assertEqual(parse(s3, fuzzy=True), datetime(2003, 12, 3, 3))
self.assertEqual(parse(s4, fuzzy=True), datetime(2003, 12, 3, 3))

def testExtraSpace(self):
self.assertEqual(parse(" July 4 , 1976 12:01:02 am "),
datetime(1976, 7, 4, 0, 1, 2))
Expand Down

0 comments on commit b913315

Please sign in to comment.