Skip to content

Commit 32c877e

Browse files
committed
Merge branch 'develop'
2 parents 7d5da81 + 5ba2ddd commit 32c877e

25 files changed

+1131
-132
lines changed

CHANGELOG.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,21 @@
22

33
## [Unreleased]
44

5-
### Fixed
5+
### Added
6+
7+
- Added `on()` and `at()` methods which replace `with_date()` and `with_time()`.
8+
- Added a `strict` keyword argument to `parse()` to get the type matching the parsed string.
9+
- Added the ability to pass an amount to the `range()` method to control the length of the gap.
10+
- Added a `datetime()` helper method to the `Timezone` class.
11+
12+
### Changed
13+
14+
- Improved parsing of ISO 8601 strings.
15+
16+
### Deprecated
617

7-
- Fixed parsing of some ISO 8601 strings.
18+
- `with_date()` and `with_time()` are deprecated. Use `on()` and `at()` instead.
19+
- `create_from_date()` and `create_from_time()` are deprecated. Use `create()` instead.
820

921

1022
## [0.7.0] - 2016-12-07

README.rst

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,53 @@ Those are a few examples showing that Arrow cannot always be trusted to have a c
120120
behavior with the data you are passing to it.
121121

122122

123+
Limitations
124+
===========
125+
126+
Even though the ``Pendulum`` class is a subclass of ``datetime`` there are some rare cases where
127+
it can't replace the native class directly. Here is a list (non-exhaustive) of the reported cases with
128+
a possible solution, if any:
129+
130+
* ``sqlite3`` will use the the ``type()`` function to determine the type of the object by default. To work around it you can register a new adapter:
131+
132+
.. code-block:: python
133+
134+
from pendulum import Pendulum
135+
from sqlite3 import register_adapter
136+
137+
register_adapter(Pendulum, lambda val: val.isoformat(' '))
138+
139+
* ``mysqlclient`` (former ``MySQLdb``) and ``PyMySQL`` will use the the ``type()`` function to determine the type of the object by default. To work around it you can register a new adapter:
140+
141+
.. code-block:: python
142+
143+
import MySQLdb.converters
144+
import pymysql.converters
145+
146+
from pendulum import Pendulum
147+
148+
MySQLdb.converters.conversions[Pendulum] = MySQLdb.converters.DateTime2literal
149+
pymysql.converters.conversions[Pendulum] = pymysql.converters.escape_datetime
150+
151+
* ``django`` will use the ``isoformat()`` method to store datetimes in the database. However since ``pendulum`` is always timezone aware the offset information will always be returned by ``isoformat()`` raising an error, at least for MySQL databases. To work around it you can either create your own ``DateTimeField`` or use the previous workaround for ``MySQLdb``:
152+
153+
.. code-block:: python
154+
155+
from django.db.models import DateTimeField as BaseDateTimeField
156+
from pendulum import Pendulum
157+
158+
159+
class DateTimeField(BaseDateTimeField):
160+
161+
def value_to_string(self, obj):
162+
val = self.value_from_object(obj)
163+
164+
if isinstance(value, Pendulum):
165+
return value.to_datetime_string()
166+
167+
return '' if val is None else val.isoformat()
168+
169+
123170
Resources
124171
=========
125172

docs/_docs/attributes_properties.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Pendulum gives access to more attributes and properties than the default ``datet
4141
dt.int_timestamp
4242
1346887571
4343
44-
pendulum.from_date(1975, 5, 21).age
44+
pendulum.create(1975, 5, 21).age
4545
41 # calculated vs now in the same tz
4646
dt.quarter
4747
3
@@ -59,9 +59,9 @@ Pendulum gives access to more attributes and properties than the default ``datet
5959
9.5
6060
6161
# Indicates if day light savings time is on
62-
pendulum.from_date(2012, 1, 1, 'America/Toronto').is_dst
62+
pendulum.create(2012, 1, 1, tz='America/Toronto').is_dst
6363
False
64-
pendulum.from_date(2012, 9, 1, 'America/Toronto').is_dst
64+
pendulum.create(2012, 9, 1, tz='America/Toronto').is_dst
6565
True
6666
6767
# Indicates if the instance is in the same timezone as the local timezone

docs/_docs/comparison.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ the ``now()`` is created in the same timezone as the instance.
114114
dt.is_leap_year()
115115
dt.is_same_day(Pendulum.now())
116116
117-
born = pendulum.from_date(1987, 4, 23)
118-
not_birthday = pendulum.from_date(2014, 9, 26)
119-
birthday = pendulum.from_date(2014, 2, 23)
117+
born = pendulum.create(1987, 4, 23)
118+
not_birthday = pendulum.create(2014, 9, 26)
119+
birthday = pendulum.create(2014, 2, 23)
120120
past_birthday = pendulum.now().subtract(years=50)
121121
122122
born.is_birthday(not_birthday)

docs/_docs/difference.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ This will default to ``True``, return the absolute value. The comparisons are do
1717
1818
import pendulum
1919
20-
dt_ottawa = pendulum.from_date(2000, 1, 1, 'America/Toronto')
21-
dt_vancouver = pendulum.from_date(200, 1, 1, 'America/Vancouver')
20+
dt_ottawa = pendulum.create(2000, 1, 1, tz='America/Toronto')
21+
dt_vancouver = pendulum.create(2000, 1, 1, tz='America/Vancouver')
2222
2323
dt_ottawa.diff(dt_vancouver).in_hours()
2424
3
@@ -89,7 +89,7 @@ You may also pass ``True`` as a 2nd parameter to remove the modifiers `ago`, `fr
8989
pendulum.now().diff_for_humans(Pendulum.now().subtract(years=1))
9090
'1 year after'
9191
92-
dt = pendulum.from_date(2011, 8, 1)
92+
dt = pendulum.create(2011, 8, 1)
9393
dt.diff_for_humans(dt.add(months=1))
9494
'1 month before'
9595
dt.diff_for_humans(dt.subtract(months=1))

docs/_docs/fluent_helpers.rst

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@ setting the timestamp will not set the corresponding timezone to UTC.
1010
.. code-block:: python
1111
1212
import pendulum
13+
from datetime import time, date
1314
1415
dt = pendulum.now()
1516
16-
dt.year_(1975).month_(5).day_(21).hour_(22).minute_(32).second_(5).to_datetime_string()
17-
'1975-05-21 22:32:05'
17+
dt = dt.year_(1975).month_(5).day_(21).to_datetime_string()
18+
'1975-05-21 13:45:18'
19+
20+
dt.hour_(22).minute_(32).second_(5).to_datetime_string()
21+
'2016-11-16 22:32:05'
1822
19-
dt.with_date(1975, 5, 21).with_time(22, 32, 5).to_datetime_string()
23+
dt.on(1975, 5, 21).at(22, 32, 5).to_datetime_string()
2024
'1975-05-21 22:32:05'
2125
2226
dt.timestamp_(169957925).timezone_('Europe/London')

docs/_docs/instantiation.rst

Lines changed: 117 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -61,29 +61,17 @@ besides behaving as expected, all accept a timezone parameter and each has their
6161
print(yesterday)
6262
'2016-06-27T00:00:00-05:00'
6363
64-
The next group of static helpers are the ``from_xxx()`` and ``create()`` helpers.
65-
Most of the static ``create`` functions allow you to provide
64+
The next helper is ``create()`` which allows you to provide
6665
as many or as few arguments as you want and will provide default values for all others.
67-
Generally default values are the current date, time set to ``00:00:00`` and ``UTC`` timezone.
6866

6967
.. code-block:: python
7068
71-
pendulum.from_date(year, month, day, tz)
72-
pendulum.from_time(hour, minute, second, microsecond, tz)
7369
pendulum.create(year, month, day, hour, minute, second, microsecond, tz)
7470
75-
``from_date()`` will default the time to ``00:00:00``. ``from_time()`` will default the date to today.
7671
``create()`` will default any null parameter to the current date for the date part and to ``00:00:00`` for time.
77-
As before, the ``tz`` defaults to the ``UTC`` timezone and otherwise can be a ``TimezoneInfo`` instance
72+
As before, the ``tz`` defaults to the ``UTC`` timezone and otherwise can be a ``Timezone`` instance
7873
or simply a string timezone value.
7974

80-
.. code-block:: python
81-
82-
xmas_this_year = pendulum.from_date(None, 12, 25)
83-
# Year defaults to current year
84-
y2k = pendulum.create(2000, 1, 1, 0, 0, 0)
85-
noon_london_tz = pendulum.from_time(12, 0, 0, tz='Europe/London')
86-
8775
.. code-block:: python
8876
8977
pendulum.from_format(time, format, tz)
@@ -138,3 +126,118 @@ you can create a ``Pendulum`` instance via the ``instance()`` function.
138126
p = pendulum.instance(dt)
139127
print(p.to_datetime_string())
140128
'2008-01-01 00:00:00'
129+
130+
Parsing
131+
-------
132+
133+
You can also instantiate ``Pendulum`` instances by passing a string to the ``parse()`` method.
134+
135+
.. code-block:: python
136+
137+
import pendulum
138+
139+
dt = pendulum.parse('1975-05-21 22:00:00')
140+
print(dt)
141+
'1975-05-21T22:00:00+00:00
142+
143+
The library natively supports the RFC 3339 format, most ISO 8601 formats and some other common formats. If you pass a non-standard or more complicated
144+
string, the library will fallback on the `dateutil <https://dateutil.readthedocs.io>`_ parser.
145+
146+
RFC 3339
147+
~~~~~~~~
148+
149+
+-----------------------------------+-------------------------------------------+
150+
|String |Output |
151+
+===================================+===========================================+
152+
|1996-12-19T16:39:57-08:00 |1996-12-19T16:39:57-08:00 |
153+
+-----------------------------------+-------------------------------------------+
154+
|1990-12-31T23:59:59Z |1990-12-31T23:59:59+00:00 |
155+
+-----------------------------------+-------------------------------------------+
156+
157+
ISO 8601
158+
~~~~~~~~
159+
160+
Datetime
161+
++++++++
162+
163+
+-----------------------------------+-------------------------------------------+
164+
|String |Output |
165+
+===================================+===========================================+
166+
|20161001T143028+0530 |2016-10-01T14:30:28+05:30 |
167+
+-----------------------------------+-------------------------------------------+
168+
|20161001T14 |2016-10-01T14:00:00+00:00 |
169+
+-----------------------------------+-------------------------------------------+
170+
171+
Date
172+
++++
173+
174+
+-----------------------------------+-------------------------------------------+
175+
|String |Output |
176+
+===================================+===========================================+
177+
|2012 |2012-01-01T00:00:00+00:00 |
178+
+-----------------------------------+-------------------------------------------+
179+
|2012-05-03 |2012-05-03T00:00:00+00:00 |
180+
+-----------------------------------+-------------------------------------------+
181+
|20120503 |2012-05-03T00:00:00+00:00 |
182+
+-----------------------------------+-------------------------------------------+
183+
|2012-05 |2016-10-01T14:00:00+00:00 |
184+
+-----------------------------------+-------------------------------------------+
185+
186+
Ordinal day
187+
+++++++++++
188+
189+
+-----------------------------------+-------------------------------------------+
190+
|String |Output |
191+
+===================================+===========================================+
192+
|2012-007 |2012-01-07T00:00:00+00:00 |
193+
+-----------------------------------+-------------------------------------------+
194+
|2012007 |2012-01-07T00:00:00+00:00 |
195+
+-----------------------------------+-------------------------------------------+
196+
197+
Week number
198+
+++++++++++
199+
200+
+-----------------------------------+-------------------------------------------+
201+
|String |Output |
202+
+===================================+===========================================+
203+
|2012-W05 |2012-01-30T00:00:00+00:00 |
204+
+-----------------------------------+-------------------------------------------+
205+
|2012W05 |2012-01-30T00:00:00+00:00 |
206+
+-----------------------------------+-------------------------------------------+
207+
|2012-W05-5 |2012-02-03T00:00:00+00:00 |
208+
+-----------------------------------+-------------------------------------------+
209+
|2012W055 |2012-02-03T00:00:00+00:00 |
210+
+-----------------------------------+-------------------------------------------+
211+
212+
Time
213+
++++
214+
215+
When passing only time information the date will default to today.
216+
217+
+-----------------------------------+-------------------------------------------+
218+
|String |Output |
219+
+===================================+===========================================+
220+
|00:00 |2016-12-17T00:00:00+00:00 |
221+
+-----------------------------------+-------------------------------------------+
222+
|12:04:23 |2016-12-17T12:04:23+00:00 |
223+
+-----------------------------------+-------------------------------------------+
224+
|120423 |2016-12-17T12:04:23+00:00 |
225+
+-----------------------------------+-------------------------------------------+
226+
|12:04:23.45 |2016-12-17T12:04:23.450000+00:00 |
227+
+-----------------------------------+-------------------------------------------+
228+
229+
230+
.. note::
231+
232+
You can pass the ``strict`` keyword argument to ``parse()`` to get the exact type
233+
that the string represents:
234+
235+
.. code-block:: python
236+
237+
import pendulum
238+
239+
pendulum.parse('2012-05-03', strict=True)
240+
# <Date [2012-05-03]>
241+
242+
pendulum.parse('12:04:23', strict=True)
243+
# <Time [12:04:23]>

docs/_docs/introduction.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ For example all comparisons are done in UTC or in the timezone of the datetime b
2121
2222
import pendulum
2323
24-
dt_toronto = pendulum.from_date(2012, 1, 1, 'America/Toronto')
25-
dt_vancouver = pendulum.from_date(2012, 1, 1, 'America/Vancouver')
24+
dt_toronto = pendulum.create(2012, 1, 1, tz='America/Toronto')
25+
dt_vancouver = pendulum.create(2012, 1, 1, tz='America/Vancouver')
2626
2727
print(dt_vancouver.diff(dt_toronto).in_hours())
2828
3

docs/_docs/limitations.rst

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
Limitations
2+
===========
3+
4+
Even though the ``Pendulum`` class is a subclass of ``datetime`` there are some rare cases where
5+
it can't replace the native class directly. Here is a list (non-exhaustive) of the reported cases with
6+
a possible solution, if any:
7+
8+
* ``sqlite3`` will use the the ``type()`` function to determine the type of the object by default. To work around it you can register a new adapter:
9+
10+
.. code-block:: python
11+
12+
from pendulum import Pendulum
13+
from sqlite3 import register_adapter
14+
15+
register_adapter(Pendulum, lambda val: val.isoformat(' '))
16+
17+
* ``mysqlclient`` (former ``MySQLdb``) and ``PyMySQL`` will use the the ``type()`` function to determine the type of the object by default. To work around it you can register a new adapter:
18+
19+
.. code-block:: python
20+
21+
import MySQLdb.converters
22+
import pymysql.converters
23+
24+
from pendulum import Pendulum
25+
26+
MySQLdb.converters.conversions[Pendulum] = MySQLdb.converters.DateTime2literal
27+
pymysql.converters.conversions[Pendulum] = pymysql.converters.escape_datetime
28+
29+
* ``django`` will use the ``isoformat()`` method to store datetimes in the database. However since ``pendulum`` is always timezone aware the offset information will always be returned by ``isoformat()`` raising an error, at least for MySQL databases. To work around it you can either create your own ``DateTimeField`` or use the previous workaround for ``MySQLdb``:
30+
31+
.. code-block:: python
32+
33+
from django.db.models import DateTimeField as BaseDateTimeField
34+
from pendulum import Pendulum
35+
36+
37+
class DateTimeField(BaseDateTimeField):
38+
39+
def value_to_string(self, obj):
40+
val = self.value_from_object(obj)
41+
42+
if isinstance(value, Pendulum):
43+
return value.to_datetime_string()
44+
45+
return '' if val is None else val.isoformat()

docs/_docs/period.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,19 @@ If you want to iterate over a period, you can use the ``range()`` method:
133133

134134
If you just want a generator you can use the ``xrange()`` method.
135135

136+
You can pass an amount for the passed unit to control the length of the gap:
137+
138+
.. code-block:: python
139+
140+
for dt in period.range('days', 2):
141+
print(dt)
142+
143+
'2000-01-01T00:00:00+00:00'
144+
'2000-01-03T00:00:00+00:00'
145+
'2000-01-05T00:00:00+00:00'
146+
'2000-01-07T00:00:00+00:00'
147+
'2000-01-09T00:00:00+00:00'
148+
136149
You can also directly iterate over the ``Period`` instance, the unit will be ``days`` in this case:
137150

138151
.. code-block:: python

0 commit comments

Comments
 (0)