Python datetimes made easy.
Project description
Python datetimes made easy.
Supports Python 2.7+, 3.4+ and PyPy.
>>> import pendulum
>>> now_in_paris = pendulum.now('Europe/Paris')
>>> now_in_paris
'2016-07-04T00:49:58.502116+02:00'
# Seamless timezone switching
>>> now_in_paris.in_timezone('UTC')
'2016-07-03T22:49:58.502116+00:00'
>>> tomorrow = pendulum.now().add(days=1)
>>> last_week = pendulum.now().subtract(weeks=1)
>>> if pendulum.now().is_weekend():
... print('Party!')
'Party!'
>>> past = pendulum.now().subtract(minutes=2)
>>> past.diff_for_humans()
>>> '2 minutes ago'
>>> delta = past - last_week
>>> delta.hours
23
>>> delta.in_words(locale='en')
'6 days 23 hours 58 minutes'
# Proper handling of datetime normalization
>>> pendulum.create(2013, 3, 31, 2, 30, 0, 0, 'Europe/Paris')
'2013-03-31T03:30:00+02:00' # 2:30 does not exist (Skipped time)
# Proper handling of dst transitions
>>> just_before = pendulum.create(2013, 3, 31, 1, 59, 59, 999999, 'Europe/Paris')
'2013-03-31T01:59:59.999999+01:00'
>>> just_before.add(microseconds=1)
'2013-03-31T03:00:00+02:00'
Why Pendulum?
Native datetime instances are enough for basic cases but when you face more complex use-cases they often show limitations and are not so intuitive to work with. Pendulum provides a cleaner and more easy to use API while still relying on the standard library. So it’s still datetime but better.
Unlike other datetime libraries for Python, Pendulum is a drop-in replacement for the standard datetime class (it inherits from it), so, basically, you can replace all your datetime instances by Pendulum instances in you code (exceptions exist for libraries that check the type of the objects by using the type function like sqlite3 or PyMySQL for instance).
It also removes the notion of naive datetimes: each Pendulum instance is timezone-aware and by default in UTC for ease of use.
Pendulum also improves the standard timedelta class by providing more intuitive methods and properties.
Why not Arrow?
Arrow is the most popular datetime library for Python right now, however its behavior and API can be erratic and unpredictable. The get() method can receive pretty much anything and it will try its best to return something while silently failing to handle some cases:
arrow.get('2016-1-17')
# <Arrow [2016-01-01T00:00:00+00:00]>
pendulum.parse('2016-1-17')
# <Pendulum [2016-01-17T00:00:00+00:00]>
arrow.get('20160413')
# <Arrow [1970-08-22T08:06:53+00:00]>
pendulum.parse('20160413')
# <Pendulum [2016-04-13T00:00:00+00:00]>
arrow.get('2016-W07-5')
# <Arrow [2016-01-01T00:00:00+00:00]>
pendulum.parse('2016-W07-5')
# <Pendulum [2016-02-19T00:00:00+00:00]>
# Working with DST
just_before = arrow.Arrow(2013, 3, 31, 1, 59, 59, 999999, 'Europe/Paris')
just_after = just_before.replace(microseconds=1)
'2013-03-31T02:00:00+02:00'
# Should be 2013-03-31T03:00:00+02:00
(just_after.to('utc') - just_before.to('utc')).total_seconds()
-3599.999999
# Should be 1e-06
just_before = pendulum.create(2013, 3, 31, 1, 59, 59, 999999, 'Europe/Paris')
just_after = just_before.add(microseconds=1)
'2013-03-31T03:00:00+02:00'
(just_after.in_timezone('utc') - just_before.in_timezone('utc')).total_seconds()
1e-06
Those are a few examples showing that Arrow cannot always be trusted to have a consistent behavior with the data you are passing to it.
Limitations
Even though the Pendulum class is a subclass of datetime there are some rare cases where it can’t replace the native class directly. Here is a list (non-exhaustive) of the reported cases with a possible solution, if any:
sqlite3 will use the type() function to determine the type of the object by default. To work around it you can register a new adapter:
from pendulum import Pendulum
from sqlite3 import register_adapter
register_adapter(Pendulum, lambda val: val.isoformat(' '))
mysqlclient (former MySQLdb) and PyMySQL will use the type() function to determine the type of the object by default. To work around it you can register a new adapter:
import MySQLdb.converters
import pymysql.converters
from pendulum import Pendulum
MySQLdb.converters.conversions[Pendulum] = MySQLdb.converters.DateTime2literal
pymysql.converters.conversions[Pendulum] = pymysql.converters.escape_datetime
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:
from django.db.models import DateTimeField as BaseDateTimeField
from pendulum import Pendulum
class DateTimeField(BaseDateTimeField):
def value_to_string(self, obj):
val = self.value_from_object(obj)
if isinstance(value, Pendulum):
return value.to_datetime_string()
return '' if val is None else val.isoformat()
Resources
Contributing
Contributions are welcome, especially with localization. Check the languages already supported, and if you want to add a new one, take the en file as a starting point and add tests accordingly.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for pendulum-1.3.2-cp36-cp36m-manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | beffaba5b2f5d22b1384062e4c4b0d6f710da225c8f43c1f03734c5e9d3bdfbb |
|
MD5 | 31f716c8517fce06abaa78d5cdfb826d |
|
BLAKE2b-256 | d1a8bf0bd1273e53a4fab5a403c7a02877ed17177bd236342727d9e86f57ff61 |
Hashes for pendulum-1.3.2-cp36-cp36m-manylinux1_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0bdeba610b66c4674764efa090088ce9a8bae780d8600e22ec55c4a4d01c01b5 |
|
MD5 | 1ec79913850e581a261bc002c05bf450 |
|
BLAKE2b-256 | 26e98fa3030aaba55d1c003c74d3e55383fedfe765d28137f16d9e46e3b52af9 |
Hashes for pendulum-1.3.2-cp36-cp36m-macosx_10_11_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | aebffa08eefa3a4b9872dc1be87d5801a30604cde8dd7e25c9ec70ad2328e188 |
|
MD5 | 56a462652b476ab308ef2c66a67c80c9 |
|
BLAKE2b-256 | baf7d47f06d518430e52b66e8aa7fe6d5074054db25284f2d9f80fa3e631a55a |
Hashes for pendulum-1.3.2-cp35-cp35m-manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e2cad79f49134d743024f9d59b71224117d2712350cf601c6e93c8be84a1c82b |
|
MD5 | b6ad0e44d39f4314fd5e24fe2773f24d |
|
BLAKE2b-256 | ba230817b0bcbd9775f7e204e67e2b17b1f45cdd7cda17b9d16bb90d37d9ae35 |
Hashes for pendulum-1.3.2-cp35-cp35m-manylinux1_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6eefa306dd3c9bf3ec6058fb7042877d0d7a12343925b67b62e6259a2541b899 |
|
MD5 | 6ede358b89986c76fd93567478d3d092 |
|
BLAKE2b-256 | 4c4882a8143df6f7a60d059b3ec09713f2d7878452916483ab18f111f395120d |
Hashes for pendulum-1.3.2-cp27-cp27m-manylinux1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 44361188a07f76a26dc1ea41fb20746723db17951d525617ae0db4a256d3ca32 |
|
MD5 | 7bac437600d423fc94fc130fe6a95d60 |
|
BLAKE2b-256 | 186b53f9f74d46f05c7f29034cde8dcbfc43d02e62b60e87a66aadc17c116a24 |
Hashes for pendulum-1.3.2-cp27-cp27m-manylinux1_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 44ed222f2bcbbda64a4a9f7503bfbb7c539420f0a163a007c92cea9878d60dea |
|
MD5 | a14edeba72b3c7a124f6bd824e29d1ff |
|
BLAKE2b-256 | 58ba64cc966085ac777e4a4a3d75a6b92cf9f74b62699f5cb54be5e195bd0aa7 |