Need help with pendulum?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

sdispater
4.2K Stars 238 Forks MIT License 696 Commits 172 Opened issues

Description

Python datetimes made easy

Services available

!
?

Need anything else?

Contributors list

No Data

Pendulum

.. image:: https://img.shields.io/pypi/v/pendulum.svg :target: https://pypi.python.org/pypi/pendulum

.. image:: https://img.shields.io/pypi/l/pendulum.svg :target: https://pypi.python.org/pypi/pendulum

.. image:: https://img.shields.io/codecov/c/github/sdispater/pendulum/master.svg :target: https://codecov.io/gh/sdispater/pendulum/branch/master

.. image:: https://travis-ci.org/sdispater/pendulum.svg :alt: Pendulum Build status :target: https://travis-ci.org/sdispater/pendulum

Python datetimes made easy.

Supports Python 2.7 and 3.4+.

.. code-block:: python

import pendulum

nowinparis = pendulum.now('Europe/Paris') nowinparis '2016-07-04T00:49:58.502116+02:00'

# Seamless timezone switching

nowinparis.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.diffforhumans() '2 minutes ago'

delta = past - lastweek delta.hours 23 delta.inwords(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

justbefore = pendulum.datetime(2013, 3, 31, 1, 59, 59, 999999, tz='Europe/Paris') '2013-03-31T01:59:59.999999+01:00' justbefore.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
DateTime
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:

.. code-block:: python

arrow.get('2016-1-17')
# 

pendulum.parse('2016-1-17')

arrow.get('20160413')

pendulum.parse('20160413')

arrow.get('2016-W07-5')

pendulum.parse('2016-W07-5')

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.datetime(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

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 the
    type()
    function to determine the type of the object by default. To work around it you can register a new adapter:

.. code-block:: python

from pendulum import DateTime
from sqlite3 import register_adapter

register_adapter(DateTime, 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:

.. code-block:: python

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 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
    :

.. code-block:: python

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()

Resources

  • Official Website 
    _
  • Documentation 
    _
  • Issue Tracker 
    _

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 depedendencies via

poetry 
_.

.. code-block:: bash

$ git clone [email protected]: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:

.. code-block:: bash

./clock locale create 

It will generate a directory in

pendulum/locales
named after your locale, with the following structure:

.. code-block:: text

/
    - 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.

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.