Pendulum
Python datetimes made easy.
Supports Python 3.9 and newer.
>>> 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)
>>> 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.datetime(2013, 3, 31, 2, 30, tz='Europe/Paris')
'2013-03-31T03:30:00+02:00' # 2:30 does not exist (Skipped time)
# Proper handling of dst transitions
>>> just_before = pendulum.datetime(2013, 3, 31, 1, 59, 59, 999999, tz='Europe/Paris')
'2013-03-31T01:59:59.999999+01:00'
>>> just_before.add(microseconds=1)
'2013-03-31T03:00:00+02:00'
Resources
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 DateTime
instances in your 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.
Limitations
Even though the DateTime
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 thetype()
function to determine the type of the object by default. To work around it you can register a new adapter:
from pendulum import DateTime
from sqlite3 import register_adapter
register_adapter(DateTime, lambda val: val.isoformat(' '))
mysqlclient
(formerMySQLdb
) andPyMySQL
will use thetype()
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 DateTime
MySQLdb.converters.conversions[DateTime] = MySQLdb.converters.DateTime2literal
pymysql.converters.conversions[DateTime] = pymysql.converters.escape_datetime
django
will use theisoformat()
method to store datetimes in the database. However sincependulum
is always timezone aware the offset information will always be returned byisoformat()
raising an error, at least for MySQL databases. To work around it you can either create your ownDateTimeField
or use the previous workaround forMySQLdb
:
from django.db.models import DateTimeField as BaseDateTimeField
from pendulum import DateTime
class DateTimeField(BaseDateTimeField):
def value_to_string(self, obj):
val = self.value_from_object(obj)
if isinstance(value, DateTime):
return value.to_datetime_string()
return '' if val is None else val.isoformat()
Contributing
Contributions are welcome, especially with localization.
Getting started
To work on the Pendulum codebase, you'll want to clone the project locally and install the required dependencies via poetry.
$ git clone git@github.com:sdispater/pendulum.git
$ poetry install
Localization
If you want to help with localization, there are two different cases: the locale already exists or not.
If the locale does not exist you will need to create it by using the
clock
utility:
./clock locale create <your-locale>
It will generate a directory in pendulum/locales
named after your
locale, with the following structure:
<your-locale>/
- custom.py
- locale.py
The locale.py
file must not be modified. It contains the translations
provided by the CLDR database.
The custom.py
file is the one you want to modify. It contains the data
needed by Pendulum that are not provided by the CLDR database. You can
take the
en
data as a reference to see which data is needed.
You should also add tests for the created or modified locale.