Skip to content

Commit 5b0d508

Browse files
committed
Fixed parsing.
Fixes #88
1 parent b18a35e commit 5b0d508

File tree

3 files changed

+81
-8
lines changed

3 files changed

+81
-8
lines changed

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
# Change Log
22

33

4+
## [Unreleased]
5+
6+
### Fixed
7+
8+
- Fixed parsing, especially for strings in the form `31-01-01`.
9+
10+
411
## [1.0.0]
512

613
### Changed
@@ -302,6 +309,7 @@ This version causes major breaking API changes to simplify it and making it more
302309
Initial release
303310

304311

312+
[Unreleased]: https://github.com/sdispater/pendulum/compare/1.0.0...master
305313
[1.0.0]: https://github.com/sdispater/pendulum/releases/tag/1.0.0
306314
[0.8.0]: https://github.com/sdispater/pendulum/releases/tag/0.8.0
307315
[0.7.0]: https://github.com/sdispater/pendulum/releases/tag/0.7.0

pendulum/parsing/parser.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class Parser(object):
2222
' (?P<year>\d{4})' # Year
2323
' (?P<monthday>'
2424
' (?P<monthsep>-|/)?(?P<month>\d{2})' # Month (optional)
25-
' ((?:-|/)?(?P<day>\d{1,2}))?' # Day (optional)
25+
' ((?P<daysep>-|/)?(?P<day>\d{1,2}))?' # Day (optional)
2626
' )?'
2727
' )'
2828
' |'
@@ -56,6 +56,7 @@ class Parser(object):
5656

5757
DEFAULT_OPTIONS = {
5858
'day_first': False,
59+
'year_first': True,
5960
'strict': False,
6061
'now': None
6162
}
@@ -92,11 +93,14 @@ def parse_common(self, text):
9293
if m.group('isocalendar'):
9394
# We have a ISO 8601 string defined
9495
# by week number
95-
date = self._get_iso_8601_week(
96-
m.group('isoyear'),
97-
m.group('isoweek'),
98-
m.group('isoweekday')
99-
)
96+
try:
97+
date = self._get_iso_8601_week(
98+
m.group('isoyear'),
99+
m.group('isoweek'),
100+
m.group('isoweekday')
101+
)
102+
except ValueError:
103+
raise ParserError('Invalid date string: {}'.format(text))
100104

101105
year = date['year']
102106
month = date['month']
@@ -112,7 +116,7 @@ def parse_common(self, text):
112116
else:
113117
if m.group('month') and m.group('day'):
114118
# Month and day
115-
if len(m.group('day')) == 1:
119+
if not m.group('daysep') and len(m.group('day')) == 1:
116120
# Ordinal day
117121
dt = datetime.strptime(
118122
'{}-{}'.format(year, m.group('month') + m.group('day')),
@@ -277,7 +281,11 @@ def _parse(self, text):
277281
# We couldn't parse the string
278282
# so we fallback on the dateutil parser
279283
try:
280-
dt = parser.parse(text, dayfirst=self._options['day_first'])
284+
dt = parser.parse(
285+
text,
286+
dayfirst=self._options['day_first'],
287+
yearfirst=self._options['year_first']
288+
)
281289
except ValueError:
282290
raise ParserError('Invalid date string: {}'.format(text))
283291

tests/parsing_test/test_parser.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,64 @@ def test_strict(self):
500500
self.assertEqual(5, parsed['second'])
501501
self.assertEqual(0, parsed['subsecond'])
502502

503+
def test_edge_cases(self):
504+
text = '2013-11-1'
505+
506+
parsed = Parser().parse(text)
507+
self.assertEqual(2013, parsed['year'])
508+
self.assertEqual(11, parsed['month'])
509+
self.assertEqual(1, parsed['day'])
510+
self.assertEqual(0, parsed['hour'])
511+
self.assertEqual(0, parsed['minute'])
512+
self.assertEqual(0, parsed['second'])
513+
self.assertEqual(0, parsed['subsecond'])
514+
self.assertEqual(None, parsed['offset'])
515+
516+
text = '10-01-01'
517+
518+
parsed = Parser().parse(text)
519+
self.assertEqual(2010, parsed['year'])
520+
self.assertEqual(1, parsed['month'])
521+
self.assertEqual(1, parsed['day'])
522+
self.assertEqual(0, parsed['hour'])
523+
self.assertEqual(0, parsed['minute'])
524+
self.assertEqual(0, parsed['second'])
525+
self.assertEqual(0, parsed['subsecond'])
526+
self.assertEqual(None, parsed['offset'])
527+
528+
text = '31-01-01'
529+
530+
parsed = Parser().parse(text)
531+
self.assertEqual(2031, parsed['year'])
532+
self.assertEqual(1, parsed['month'])
533+
self.assertEqual(1, parsed['day'])
534+
self.assertEqual(0, parsed['hour'])
535+
self.assertEqual(0, parsed['minute'])
536+
self.assertEqual(0, parsed['second'])
537+
self.assertEqual(0, parsed['subsecond'])
538+
self.assertEqual(None, parsed['offset'])
539+
540+
text = '32-01-01'
541+
542+
parsed = Parser().parse(text)
543+
self.assertEqual(2032, parsed['year'])
544+
self.assertEqual(1, parsed['month'])
545+
self.assertEqual(1, parsed['day'])
546+
self.assertEqual(0, parsed['hour'])
547+
self.assertEqual(0, parsed['minute'])
548+
self.assertEqual(0, parsed['second'])
549+
self.assertEqual(0, parsed['subsecond'])
550+
self.assertEqual(None, parsed['offset'])
551+
503552
def test_invalid(self):
504553
text = '201610T'
505554

506555
self.assertRaises(ParserError, Parser().parse, text)
556+
557+
text = '2012-W54'
558+
559+
self.assertRaises(ParserError, Parser().parse, text)
560+
561+
text = '2012-W13-8'
562+
563+
self.assertRaises(ParserError, Parser().parse, text)

0 commit comments

Comments
 (0)