Skip to content

Commit ce3edce

Browse files
committed
Merge branch 'master' into develop
2 parents abe9efe + cf8c0f2 commit ce3edce

File tree

10 files changed

+99
-28
lines changed

10 files changed

+99
-28
lines changed

CHANGELOG.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
# Change Log
22

33

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

613
### Changed
714

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

304311

305-
[Unreleased]: https://github.com/sdispater/pendulum/compare/0.8.0...develop
312+
[Unreleased]: https://github.com/sdispater/pendulum/compare/1.0.1...master
313+
[1.0.1]: https://github.com/sdispater/pendulum/releases/tag/1.0.1
314+
[1.0.0]: https://github.com/sdispater/pendulum/releases/tag/1.0.0
306315
[0.8.0]: https://github.com/sdispater/pendulum/releases/tag/0.8.0
307316
[0.7.0]: https://github.com/sdispater/pendulum/releases/tag/0.7.0
308317
[0.6.6]: https://github.com/sdispater/pendulum/releases/tag/0.6.6

docs/_docs/introduction.rst

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
Introduction
22
============
33

4-
.. warning::
5-
6-
Pendulum is still in development, so expect (not to many I hope) breaking API changes in
7-
the future.
8-
94
Pendulum is a Python package to ease datetimes manipulation.
105

116
It is heavily inspired by `Carbon <http://carbon.nesbot.com>`_ for PHP.

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@
5858
# built documents.
5959
#
6060
# The short X.Y version.
61-
version = '0.8'
61+
version = '1.0'
6262
# The full version, including alpha/beta/rc tags.
63-
release = '0.8.0'
63+
release = '1.0.1'
6464

6565
# The language for content autogenerated by Sphinx. Refer to documentation
6666
# for a list of supported languages.

pendulum/date.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,11 @@ def day_of_year(self):
137137
138138
:rtype: int
139139
"""
140-
k = 1 if self.is_leap_year else 2
140+
k = 1 if self.is_leap_year() else 2
141141

142142
return (
143143
(275 * self.month) // 9
144-
- k * (self.month + 9) // 12
144+
- k * ((self.month + 9) // 12)
145145
+ self.day - 30
146146
)
147147

pendulum/formatting/alternative_formatter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def format(self, dt, fmt, locale=None):
104104
Formats a Pendulum instance with a given format and locale.
105105
106106
:param dt: The instance to format
107-
:type dt: Pendulum
107+
:type dt: pendulum.Pendulum
108108
109109
:param fmt: The format to use
110110
:type fmt: str
@@ -131,7 +131,7 @@ def _format_token(self, dt, token, locale):
131131
Formats a Pendulum instance with a given token and locale.
132132
133133
:param dt: The instance to format
134-
:type dt: Pendulum
134+
:type dt: pendulum.Pendulum
135135
136136
:param token: The token to use
137137
:type token: str
@@ -174,7 +174,7 @@ def _format_localizable_token(self, dt, token, locale):
174174
with a given localizable token and locale.
175175
176176
:param dt: The instance to format
177-
:type dt: Pendulum
177+
:type dt: pendulum.Pendulum
178178
179179
:param token: The token to use
180180
:type token: str

pendulum/formatting/classic_formatter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def format(self, dt, fmt, locale=None):
1616
Formats a Pendulum instance with a given format and locale.
1717
1818
:param dt: The instance to format
19-
:type dt: Pendulum or Date
19+
:type dt: pendulum.Pendulum or pendulum.Date
2020
2121
:param fmt: The format to use
2222
:type fmt: str
@@ -48,7 +48,7 @@ def _localize_directive(self, dt, directive, locale):
4848
Localize a native strftime directive.
4949
5050
:param dt: The instance to format
51-
:type dt: Pendulum
51+
:type dt: pendulum.Pendulum
5252
5353
:param directive: The directive to localize
5454
:type directive: str
@@ -87,7 +87,7 @@ def _strftime(self, dt, m, locale):
8787
Handles custom formatters in format string.
8888
8989
:param dt: The instance to format
90-
:type dt: Pendulum
90+
:type dt: pendulum.Pendulum
9191
9292
:return: str
9393
"""

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

pendulum/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# -*- coding: utf-8 -*-
22

3-
VERSION = '0.8.0'
3+
VERSION = '1.0.1'

tests/date_tests/test_getters.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ def test_day_of_week(self):
2525
self.assertEqual(pendulum.MONDAY, d.day_of_week)
2626

2727
def test_day_of_year(self):
28-
d = Date(2012, 5, 7)
29-
self.assertEqual(128, d.day_of_year)
28+
d = Date(2015, 12, 31)
29+
self.assertEqual(365, d.day_of_year)
30+
d = Date(2016, 12, 31)
31+
self.assertEqual(366, d.day_of_year)
3032

3133
def test_days_in_month(self):
3234
d = Date(2012, 5, 7)

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)