253 lines
8.3 KiB
Plaintext
253 lines
8.3 KiB
Plaintext
Metadata-Version: 2.1
|
|
Name: pendulum
|
|
Version: 2.1.2
|
|
Summary: Python datetimes made easy
|
|
Home-page: https://pendulum.eustace.io
|
|
License: MIT
|
|
Keywords: datetime,date,time
|
|
Author: Sébastien Eustace
|
|
Author-email: sebastien@eustace.io
|
|
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
|
|
Classifier: License :: OSI Approved :: MIT License
|
|
Classifier: Programming Language :: Python :: 2
|
|
Classifier: Programming Language :: Python :: 2.7
|
|
Classifier: Programming Language :: Python :: 3
|
|
Classifier: Programming Language :: Python :: 3.5
|
|
Classifier: Programming Language :: Python :: 3.6
|
|
Classifier: Programming Language :: Python :: 3.7
|
|
Classifier: Programming Language :: Python :: 3.8
|
|
Classifier: Programming Language :: Python :: 3.9
|
|
Classifier: Programming Language :: Python :: 3.10
|
|
Requires-Dist: python-dateutil (>=2.6,<3.0)
|
|
Requires-Dist: pytzdata (>=2020.1)
|
|
Requires-Dist: typing (>=3.6,<4.0); python_version < "3.5"
|
|
Project-URL: Documentation, https://pendulum.eustace.io/docs
|
|
Project-URL: Repository, https://github.com/sdispater/pendulum
|
|
Description-Content-Type: text/x-rst
|
|
|
|
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
|
|
|
|
>>> 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'
|
|
|
|
|
|
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')
|
|
# <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.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 <https://pendulum.eustace.io>`_
|
|
* `Documentation <https://pendulum.eustace.io/docs/>`_
|
|
* `Issue Tracker <https://github.com/sdispater/pendulum/issues>`_
|
|
|
|
|
|
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 <https://poetry.eustace.io>`_.
|
|
|
|
.. code-block:: bash
|
|
|
|
$ 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:
|
|
|
|
.. code-block:: bash
|
|
|
|
./clock locale create <your-locale>
|
|
|
|
It will generate a directory in ``pendulum/locales`` named after your locale, with the following
|
|
structure:
|
|
|
|
.. code-block:: text
|
|
|
|
<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 <https://github.com/sdispater/pendulum/tree/master/pendulum/locales/en/custom.py>`_
|
|
data as a reference to see which data is needed.
|
|
|
|
You should also add tests for the created or modified locale.
|
|
|