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 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') # 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 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 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.