mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
AYON: ISO date format conversion issues (#4981)
* added arrow to requirements of openpype * moved 'arrow' from ftrack python 2 dependencies to global * use arrow in conversion utils for datetime conversion * skip datetime conversion
This commit is contained in:
parent
4b980b5b1b
commit
0daa5580d9
39 changed files with 3 additions and 8072 deletions
|
|
@ -1,5 +1,5 @@
|
|||
import os
|
||||
import datetime
|
||||
import arrow
|
||||
import collections
|
||||
import json
|
||||
|
||||
|
|
@ -566,7 +566,7 @@ def convert_v4_version_to_v3(version):
|
|||
output_data[dst_key] = version[src_key]
|
||||
|
||||
if "createdAt" in version:
|
||||
created_at = datetime.datetime.fromisoformat(version["createdAt"])
|
||||
created_at = arrow.get(version["createdAt"])
|
||||
output_data["time"] = created_at.strftime("%Y%m%dT%H%M%SZ")
|
||||
|
||||
output["data"] = output_data
|
||||
|
|
|
|||
|
|
@ -124,8 +124,6 @@ class FtrackModule(
|
|||
python_paths = [
|
||||
# `python-ftrack-api`
|
||||
os.path.join(python_2_vendor, "ftrack-python-api", "source"),
|
||||
# `arrow`
|
||||
os.path.join(python_2_vendor, "arrow"),
|
||||
# `builtins` from `python-future`
|
||||
# - `python-future` is strict Python 2 module that cause crashes
|
||||
# of Python 3 scripts executed through OpenPype
|
||||
|
|
|
|||
|
|
@ -1,211 +0,0 @@
|
|||
README.rst.new
|
||||
|
||||
# Small entry point file for debugging tasks
|
||||
test.py
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
pip-wheel-metadata/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
local/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# Swap
|
||||
[._]*.s[a-v][a-z]
|
||||
[._]*.sw[a-p]
|
||||
[._]s[a-rt-v][a-z]
|
||||
[._]ss[a-gi-z]
|
||||
[._]sw[a-p]
|
||||
|
||||
# Session
|
||||
Session.vim
|
||||
Sessionx.vim
|
||||
|
||||
# Temporary
|
||||
.netrwhist
|
||||
*~
|
||||
# Auto-generated tag files
|
||||
tags
|
||||
# Persistent undo
|
||||
[._]*.un~
|
||||
|
||||
.idea/
|
||||
.vscode/
|
||||
|
||||
# General
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear in the root of a volume
|
||||
.DocumentRevisions-V100
|
||||
.fseventsd
|
||||
.Spotlight-V100
|
||||
.TemporaryItems
|
||||
.Trashes
|
||||
.VolumeIcon.icns
|
||||
.com.apple.timemachine.donotpresent
|
||||
|
||||
# Directories potentially created on remote AFP share
|
||||
.AppleDB
|
||||
.AppleDesktop
|
||||
Network Trash Folder
|
||||
Temporary Items
|
||||
.apdisk
|
||||
|
||||
*~
|
||||
|
||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||
.fuse_hidden*
|
||||
|
||||
# KDE directory preferences
|
||||
.directory
|
||||
|
||||
# Linux trash folder which might appear on any partition or disk
|
||||
.Trash-*
|
||||
|
||||
# .nfs files are created when an open file is removed but is still being accessed
|
||||
.nfs*
|
||||
|
||||
# Windows thumbnail cache files
|
||||
Thumbs.db
|
||||
Thumbs.db:encryptable
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
|
||||
# Dump file
|
||||
*.stackdump
|
||||
|
||||
# Folder config file
|
||||
[Dd]esktop.ini
|
||||
|
||||
# Recycle Bin used on file shares
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Windows Installer files
|
||||
*.cab
|
||||
*.msi
|
||||
*.msix
|
||||
*.msm
|
||||
*.msp
|
||||
|
||||
# Windows shortcuts
|
||||
*.lnk
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
default_language_version:
|
||||
python: python3
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
- id: end-of-file-fixer
|
||||
- id: fix-encoding-pragma
|
||||
exclude: ^arrow/_version.py
|
||||
- id: requirements-txt-fixer
|
||||
- id: check-ast
|
||||
- id: check-yaml
|
||||
- id: check-case-conflict
|
||||
- id: check-docstring-first
|
||||
- id: check-merge-conflict
|
||||
- id: debug-statements
|
||||
- repo: https://github.com/timothycrosley/isort
|
||||
rev: 5.4.2
|
||||
hooks:
|
||||
- id: isort
|
||||
- repo: https://github.com/asottile/pyupgrade
|
||||
rev: v2.7.2
|
||||
hooks:
|
||||
- id: pyupgrade
|
||||
- repo: https://github.com/pre-commit/pygrep-hooks
|
||||
rev: v1.6.0
|
||||
hooks:
|
||||
- id: python-no-eval
|
||||
- id: python-check-blanket-noqa
|
||||
- id: rst-backticks
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 20.8b1
|
||||
hooks:
|
||||
- id: black
|
||||
args: [--safe, --quiet]
|
||||
- repo: https://gitlab.com/pycqa/flake8
|
||||
rev: 3.8.3
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies: [flake8-bugbear]
|
||||
|
|
@ -1,598 +0,0 @@
|
|||
Changelog
|
||||
=========
|
||||
|
||||
0.17.0 (2020-10-2)
|
||||
-------------------
|
||||
|
||||
- [WARN] Arrow will **drop support** for Python 2.7 and 3.5 in the upcoming 1.0.0 release. This is the last major release to support Python 2.7 and Python 3.5.
|
||||
- [NEW] Arrow now properly handles imaginary datetimes during DST shifts. For example:
|
||||
|
||||
..code-block:: python
|
||||
>>> just_before = arrow.get(2013, 3, 31, 1, 55, tzinfo="Europe/Paris")
|
||||
>>> just_before.shift(minutes=+10)
|
||||
<Arrow [2013-03-31T03:05:00+02:00]>
|
||||
|
||||
..code-block:: python
|
||||
>>> before = arrow.get("2018-03-10 23:00:00", "YYYY-MM-DD HH:mm:ss", tzinfo="US/Pacific")
|
||||
>>> after = arrow.get("2018-03-11 04:00:00", "YYYY-MM-DD HH:mm:ss", tzinfo="US/Pacific")
|
||||
>>> result=[(t, t.to("utc")) for t in arrow.Arrow.range("hour", before, after)]
|
||||
>>> for r in result:
|
||||
... print(r)
|
||||
...
|
||||
(<Arrow [2018-03-10T23:00:00-08:00]>, <Arrow [2018-03-11T07:00:00+00:00]>)
|
||||
(<Arrow [2018-03-11T00:00:00-08:00]>, <Arrow [2018-03-11T08:00:00+00:00]>)
|
||||
(<Arrow [2018-03-11T01:00:00-08:00]>, <Arrow [2018-03-11T09:00:00+00:00]>)
|
||||
(<Arrow [2018-03-11T03:00:00-07:00]>, <Arrow [2018-03-11T10:00:00+00:00]>)
|
||||
(<Arrow [2018-03-11T04:00:00-07:00]>, <Arrow [2018-03-11T11:00:00+00:00]>)
|
||||
|
||||
- [NEW] Added ``humanize`` week granularity translation for Tagalog.
|
||||
- [CHANGE] Calls to the ``timestamp`` property now emit a ``DeprecationWarning``. In a future release, ``timestamp`` will be changed to a method to align with Python's datetime module. If you would like to continue using the property, please change your code to use the ``int_timestamp`` or ``float_timestamp`` properties instead.
|
||||
- [CHANGE] Expanded and improved Catalan locale.
|
||||
- [FIX] Fixed a bug that caused ``Arrow.range()`` to incorrectly cut off ranges in certain scenarios when using month, quarter, or year endings.
|
||||
- [FIX] Fixed a bug that caused day of week token parsing to be case sensitive.
|
||||
- [INTERNAL] A number of functions were reordered in arrow.py for better organization and grouping of related methods. This change will have no impact on usage.
|
||||
- [INTERNAL] A minimum tox version is now enforced for compatibility reasons. Contributors must use tox >3.18.0 going forward.
|
||||
|
||||
0.16.0 (2020-08-23)
|
||||
-------------------
|
||||
|
||||
- [WARN] Arrow will **drop support** for Python 2.7 and 3.5 in the upcoming 1.0.0 release. The 0.16.x and 0.17.x releases are the last to support Python 2.7 and 3.5.
|
||||
- [NEW] Implemented `PEP 495 <https://www.python.org/dev/peps/pep-0495/>`_ to handle ambiguous datetimes. This is achieved by the addition of the ``fold`` attribute for Arrow objects. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> before = Arrow(2017, 10, 29, 2, 0, tzinfo='Europe/Stockholm')
|
||||
<Arrow [2017-10-29T02:00:00+02:00]>
|
||||
>>> before.fold
|
||||
0
|
||||
>>> before.ambiguous
|
||||
True
|
||||
>>> after = Arrow(2017, 10, 29, 2, 0, tzinfo='Europe/Stockholm', fold=1)
|
||||
<Arrow [2017-10-29T02:00:00+01:00]>
|
||||
>>> after = before.replace(fold=1)
|
||||
<Arrow [2017-10-29T02:00:00+01:00]>
|
||||
|
||||
- [NEW] Added ``normalize_whitespace`` flag to ``arrow.get``. This is useful for parsing log files and/or any files that may contain inconsistent spacing. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get("Jun 1 2005 1:33PM", "MMM D YYYY H:mmA", normalize_whitespace=True)
|
||||
<Arrow [2005-06-01T13:33:00+00:00]>
|
||||
>>> arrow.get("2013-036 \t 04:05:06Z", normalize_whitespace=True)
|
||||
<Arrow [2013-02-05T04:05:06+00:00]>
|
||||
|
||||
0.15.8 (2020-07-23)
|
||||
-------------------
|
||||
|
||||
- [WARN] Arrow will **drop support** for Python 2.7 and 3.5 in the upcoming 1.0.0 release. The 0.15.x, 0.16.x, and 0.17.x releases are the last to support Python 2.7 and 3.5.
|
||||
- [NEW] Added ``humanize`` week granularity translation for Czech.
|
||||
- [FIX] ``arrow.get`` will now pick sane defaults when weekdays are passed with particular token combinations, see `#446 <https://github.com/arrow-py/arrow/issues/446>`_.
|
||||
- [INTERNAL] Moved arrow to an organization. The repo can now be found `here <https://github.com/arrow-py/arrow>`_.
|
||||
- [INTERNAL] Started issuing deprecation warnings for Python 2.7 and 3.5.
|
||||
- [INTERNAL] Added Python 3.9 to CI pipeline.
|
||||
|
||||
0.15.7 (2020-06-19)
|
||||
-------------------
|
||||
|
||||
- [NEW] Added a number of built-in format strings. See the `docs <https://arrow.readthedocs.io/#built-in-formats>`_ for a complete list of supported formats. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arw = arrow.utcnow()
|
||||
>>> arw.format(arrow.FORMAT_COOKIE)
|
||||
'Wednesday, 27-May-2020 10:30:35 UTC'
|
||||
|
||||
- [NEW] Arrow is now fully compatible with Python 3.9 and PyPy3.
|
||||
- [NEW] Added Makefile, tox.ini, and requirements.txt files to the distribution bundle.
|
||||
- [NEW] Added French Canadian and Swahili locales.
|
||||
- [NEW] Added ``humanize`` week granularity translation for Hebrew, Greek, Macedonian, Swedish, Slovak.
|
||||
- [FIX] ms and μs timestamps are now normalized in ``arrow.get()``, ``arrow.fromtimestamp()``, and ``arrow.utcfromtimestamp()``. For example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> ts = 1591161115194556
|
||||
>>> arw = arrow.get(ts)
|
||||
<Arrow [2020-06-03T05:11:55.194556+00:00]>
|
||||
>>> arw.timestamp
|
||||
1591161115
|
||||
|
||||
- [FIX] Refactored and updated Macedonian, Hebrew, Korean, and Portuguese locales.
|
||||
|
||||
0.15.6 (2020-04-29)
|
||||
-------------------
|
||||
|
||||
- [NEW] Added support for parsing and formatting `ISO 8601 week dates <https://en.wikipedia.org/wiki/ISO_week_date>`_ via a new token ``W``, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get("2013-W29-6", "W")
|
||||
<Arrow [2013-07-20T00:00:00+00:00]>
|
||||
>>> utc=arrow.utcnow()
|
||||
>>> utc
|
||||
<Arrow [2020-01-23T18:37:55.417624+00:00]>
|
||||
>>> utc.format("W")
|
||||
'2020-W04-4'
|
||||
|
||||
- [NEW] Formatting with ``x`` token (microseconds) is now possible, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> dt = arrow.utcnow()
|
||||
>>> dt.format("x")
|
||||
'1585669870688329'
|
||||
>>> dt.format("X")
|
||||
'1585669870'
|
||||
|
||||
- [NEW] Added ``humanize`` week granularity translation for German, Italian, Polish & Taiwanese locales.
|
||||
- [FIX] Consolidated and simplified German locales.
|
||||
- [INTERNAL] Moved testing suite from nosetest/Chai to pytest/pytest-mock.
|
||||
- [INTERNAL] Converted xunit-style setup and teardown functions in tests to pytest fixtures.
|
||||
- [INTERNAL] Setup Github Actions for CI alongside Travis.
|
||||
- [INTERNAL] Help support Arrow's future development by donating to the project on `Open Collective <https://opencollective.com/arrow>`_.
|
||||
|
||||
0.15.5 (2020-01-03)
|
||||
-------------------
|
||||
|
||||
- [WARN] Python 2 reached EOL on 2020-01-01. arrow will **drop support** for Python 2 in a future release to be decided (see `#739 <https://github.com/arrow-py/arrow/issues/739>`_).
|
||||
- [NEW] Added bounds parameter to ``span_range``, ``interval`` and ``span`` methods. This allows you to include or exclude the start and end values.
|
||||
- [NEW] ``arrow.get()`` can now create arrow objects from a timestamp with a timezone, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get(1367900664, tzinfo=tz.gettz('US/Pacific'))
|
||||
<Arrow [2013-05-06T21:24:24-07:00]>
|
||||
|
||||
- [NEW] ``humanize`` can now combine multiple levels of granularity, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> later140 = arrow.utcnow().shift(seconds=+8400)
|
||||
>>> later140.humanize(granularity="minute")
|
||||
'in 139 minutes'
|
||||
>>> later140.humanize(granularity=["hour", "minute"])
|
||||
'in 2 hours and 19 minutes'
|
||||
|
||||
- [NEW] Added Hong Kong locale (``zh_hk``).
|
||||
- [NEW] Added ``humanize`` week granularity translation for Dutch.
|
||||
- [NEW] Numbers are now displayed when using the seconds granularity in ``humanize``.
|
||||
- [CHANGE] ``range`` now supports both the singular and plural forms of the ``frames`` argument (e.g. day and days).
|
||||
- [FIX] Improved parsing of strings that contain punctuation.
|
||||
- [FIX] Improved behaviour of ``humanize`` when singular seconds are involved.
|
||||
|
||||
0.15.4 (2019-11-02)
|
||||
-------------------
|
||||
|
||||
- [FIX] Fixed an issue that caused package installs to fail on Conda Forge.
|
||||
|
||||
0.15.3 (2019-11-02)
|
||||
-------------------
|
||||
|
||||
- [NEW] ``factory.get()`` can now create arrow objects from a ISO calendar tuple, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get((2013, 18, 7))
|
||||
<Arrow [2013-05-05T00:00:00+00:00]>
|
||||
|
||||
- [NEW] Added a new token ``x`` to allow parsing of integer timestamps with milliseconds and microseconds.
|
||||
- [NEW] Formatting now supports escaping of characters using the same syntax as parsing, for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arw = arrow.now()
|
||||
>>> fmt = "YYYY-MM-DD h [h] m"
|
||||
>>> arw.format(fmt)
|
||||
'2019-11-02 3 h 32'
|
||||
|
||||
- [NEW] Added ``humanize`` week granularity translations for Chinese, Spanish and Vietnamese.
|
||||
- [CHANGE] Added ``ParserError`` to module exports.
|
||||
- [FIX] Added support for midnight at end of day. See `#703 <https://github.com/arrow-py/arrow/issues/703>`_ for details.
|
||||
- [INTERNAL] Created Travis build for macOS.
|
||||
- [INTERNAL] Test parsing and formatting against full timezone database.
|
||||
|
||||
0.15.2 (2019-09-14)
|
||||
-------------------
|
||||
|
||||
- [NEW] Added ``humanize`` week granularity translations for Portuguese and Brazilian Portuguese.
|
||||
- [NEW] Embedded changelog within docs and added release dates to versions.
|
||||
- [FIX] Fixed a bug that caused test failures on Windows only, see `#668 <https://github.com/arrow-py/arrow/issues/668>`_ for details.
|
||||
|
||||
0.15.1 (2019-09-10)
|
||||
-------------------
|
||||
|
||||
- [NEW] Added ``humanize`` week granularity translations for Japanese.
|
||||
- [FIX] Fixed a bug that caused Arrow to fail when passed a negative timestamp string.
|
||||
- [FIX] Fixed a bug that caused Arrow to fail when passed a datetime object with ``tzinfo`` of type ``StaticTzInfo``.
|
||||
|
||||
0.15.0 (2019-09-08)
|
||||
-------------------
|
||||
|
||||
- [NEW] Added support for DDD and DDDD ordinal date tokens. The following functionality is now possible: ``arrow.get("1998-045")``, ``arrow.get("1998-45", "YYYY-DDD")``, ``arrow.get("1998-045", "YYYY-DDDD")``.
|
||||
- [NEW] ISO 8601 basic format for dates and times is now supported (e.g. ``YYYYMMDDTHHmmssZ``).
|
||||
- [NEW] Added ``humanize`` week granularity translations for French, Russian and Swiss German locales.
|
||||
- [CHANGE] Timestamps of type ``str`` are no longer supported **without a format string** in the ``arrow.get()`` method. This change was made to support the ISO 8601 basic format and to address bugs such as `#447 <https://github.com/arrow-py/arrow/issues/447>`_.
|
||||
|
||||
The following will NOT work in v0.15.0:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get("1565358758")
|
||||
>>> arrow.get("1565358758.123413")
|
||||
|
||||
The following will work in v0.15.0:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get("1565358758", "X")
|
||||
>>> arrow.get("1565358758.123413", "X")
|
||||
>>> arrow.get(1565358758)
|
||||
>>> arrow.get(1565358758.123413)
|
||||
|
||||
- [CHANGE] When a meridian token (a|A) is passed and no meridians are available for the specified locale (e.g. unsupported or untranslated) a ``ParserError`` is raised.
|
||||
- [CHANGE] The timestamp token (``X``) will now match float timestamps of type ``str``: ``arrow.get(“1565358758.123415”, “X”)``.
|
||||
- [CHANGE] Strings with leading and/or trailing whitespace will no longer be parsed without a format string. Please see `the docs <https://arrow.readthedocs.io/#regular-expressions>`_ for ways to handle this.
|
||||
- [FIX] The timestamp token (``X``) will now only match on strings that **strictly contain integers and floats**, preventing incorrect matches.
|
||||
- [FIX] Most instances of ``arrow.get()`` returning an incorrect ``Arrow`` object from a partial parsing match have been eliminated. The following issue have been addressed: `#91 <https://github.com/arrow-py/arrow/issues/91>`_, `#196 <https://github.com/arrow-py/arrow/issues/196>`_, `#396 <https://github.com/arrow-py/arrow/issues/396>`_, `#434 <https://github.com/arrow-py/arrow/issues/434>`_, `#447 <https://github.com/arrow-py/arrow/issues/447>`_, `#456 <https://github.com/arrow-py/arrow/issues/456>`_, `#519 <https://github.com/arrow-py/arrow/issues/519>`_, `#538 <https://github.com/arrow-py/arrow/issues/538>`_, `#560 <https://github.com/arrow-py/arrow/issues/560>`_.
|
||||
|
||||
0.14.7 (2019-09-04)
|
||||
-------------------
|
||||
|
||||
- [CHANGE] ``ArrowParseWarning`` will no longer be printed on every call to ``arrow.get()`` with a datetime string. The purpose of the warning was to start a conversation about the upcoming 0.15.0 changes and we appreciate all the feedback that the community has given us!
|
||||
|
||||
0.14.6 (2019-08-28)
|
||||
-------------------
|
||||
|
||||
- [NEW] Added support for ``week`` granularity in ``Arrow.humanize()``. For example, ``arrow.utcnow().shift(weeks=-1).humanize(granularity="week")`` outputs "a week ago". This change introduced two new untranslated words, ``week`` and ``weeks``, to all locale dictionaries, so locale contributions are welcome!
|
||||
- [NEW] Fully translated the Brazilian Portugese locale.
|
||||
- [CHANGE] Updated the Macedonian locale to inherit from a Slavic base.
|
||||
- [FIX] Fixed a bug that caused ``arrow.get()`` to ignore tzinfo arguments of type string (e.g. ``arrow.get(tzinfo="Europe/Paris")``).
|
||||
- [FIX] Fixed a bug that occurred when ``arrow.Arrow()`` was instantiated with a ``pytz`` tzinfo object.
|
||||
- [FIX] Fixed a bug that caused Arrow to fail when passed a sub-second token, that when rounded, had a value greater than 999999 (e.g. ``arrow.get("2015-01-12T01:13:15.9999995")``). Arrow should now accurately propagate the rounding for large sub-second tokens.
|
||||
|
||||
0.14.5 (2019-08-09)
|
||||
-------------------
|
||||
|
||||
- [NEW] Added Afrikaans locale.
|
||||
- [CHANGE] Removed deprecated ``replace`` shift functionality. Users looking to pass plural properties to the ``replace`` function to shift values should use ``shift`` instead.
|
||||
- [FIX] Fixed bug that occurred when ``factory.get()`` was passed a locale kwarg.
|
||||
|
||||
0.14.4 (2019-07-30)
|
||||
-------------------
|
||||
|
||||
- [FIX] Fixed a regression in 0.14.3 that prevented a tzinfo argument of type string to be passed to the ``get()`` function. Functionality such as ``arrow.get("2019072807", "YYYYMMDDHH", tzinfo="UTC")`` should work as normal again.
|
||||
- [CHANGE] Moved ``backports.functools_lru_cache`` dependency from ``extra_requires`` to ``install_requires`` for ``Python 2.7`` installs to fix `#495 <https://github.com/arrow-py/arrow/issues/495>`_.
|
||||
|
||||
0.14.3 (2019-07-28)
|
||||
-------------------
|
||||
|
||||
- [NEW] Added full support for Python 3.8.
|
||||
- [CHANGE] Added warnings for upcoming factory.get() parsing changes in 0.15.0. Please see `#612 <https://github.com/arrow-py/arrow/issues/612>`_ for full details.
|
||||
- [FIX] Extensive refactor and update of documentation.
|
||||
- [FIX] factory.get() can now construct from kwargs.
|
||||
- [FIX] Added meridians to Spanish Locale.
|
||||
|
||||
0.14.2 (2019-06-06)
|
||||
-------------------
|
||||
|
||||
- [CHANGE] Travis CI builds now use tox to lint and run tests.
|
||||
- [FIX] Fixed UnicodeDecodeError on certain locales (#600).
|
||||
|
||||
0.14.1 (2019-06-06)
|
||||
-------------------
|
||||
|
||||
- [FIX] Fixed ``ImportError: No module named 'dateutil'`` (#598).
|
||||
|
||||
0.14.0 (2019-06-06)
|
||||
-------------------
|
||||
|
||||
- [NEW] Added provisional support for Python 3.8.
|
||||
- [CHANGE] Removed support for EOL Python 3.4.
|
||||
- [FIX] Updated setup.py with modern Python standards.
|
||||
- [FIX] Upgraded dependencies to latest versions.
|
||||
- [FIX] Enabled flake8 and black on travis builds.
|
||||
- [FIX] Formatted code using black and isort.
|
||||
|
||||
0.13.2 (2019-05-30)
|
||||
-------------------
|
||||
|
||||
- [NEW] Add is_between method.
|
||||
- [FIX] Improved humanize behaviour for near zero durations (#416).
|
||||
- [FIX] Correct humanize behaviour with future days (#541).
|
||||
- [FIX] Documentation updates.
|
||||
- [FIX] Improvements to German Locale.
|
||||
|
||||
0.13.1 (2019-02-17)
|
||||
-------------------
|
||||
|
||||
- [NEW] Add support for Python 3.7.
|
||||
- [CHANGE] Remove deprecation decorators for Arrow.range(), Arrow.span_range() and Arrow.interval(), all now return generators, wrap with list() to get old behavior.
|
||||
- [FIX] Documentation and docstring updates.
|
||||
|
||||
0.13.0 (2019-01-09)
|
||||
-------------------
|
||||
|
||||
- [NEW] Added support for Python 3.6.
|
||||
- [CHANGE] Drop support for Python 2.6/3.3.
|
||||
- [CHANGE] Return generator instead of list for Arrow.range(), Arrow.span_range() and Arrow.interval().
|
||||
- [FIX] Make arrow.get() work with str & tzinfo combo.
|
||||
- [FIX] Make sure special RegEx characters are escaped in format string.
|
||||
- [NEW] Added support for ZZZ when formatting.
|
||||
- [FIX] Stop using datetime.utcnow() in internals, use datetime.now(UTC) instead.
|
||||
- [FIX] Return NotImplemented instead of TypeError in arrow math internals.
|
||||
- [NEW] Added Estonian Locale.
|
||||
- [FIX] Small fixes to Greek locale.
|
||||
- [FIX] TagalogLocale improvements.
|
||||
- [FIX] Added test requirements to setup.
|
||||
- [FIX] Improve docs for get, now and utcnow methods.
|
||||
- [FIX] Correct typo in depreciation warning.
|
||||
|
||||
0.12.1
|
||||
------
|
||||
|
||||
- [FIX] Allow universal wheels to be generated and reliably installed.
|
||||
- [FIX] Make humanize respect only_distance when granularity argument is also given.
|
||||
|
||||
0.12.0
|
||||
------
|
||||
|
||||
- [FIX] Compatibility fix for Python 2.x
|
||||
|
||||
0.11.0
|
||||
------
|
||||
|
||||
- [FIX] Fix grammar of ArabicLocale
|
||||
- [NEW] Add Nepali Locale
|
||||
- [FIX] Fix month name + rename AustriaLocale -> AustrianLocale
|
||||
- [FIX] Fix typo in Basque Locale
|
||||
- [FIX] Fix grammar in PortugueseBrazilian locale
|
||||
- [FIX] Remove pip --user-mirrors flag
|
||||
- [NEW] Add Indonesian Locale
|
||||
|
||||
0.10.0
|
||||
------
|
||||
|
||||
- [FIX] Fix getattr off by one for quarter
|
||||
- [FIX] Fix negative offset for UTC
|
||||
- [FIX] Update arrow.py
|
||||
|
||||
0.9.0
|
||||
-----
|
||||
|
||||
- [NEW] Remove duplicate code
|
||||
- [NEW] Support gnu date iso 8601
|
||||
- [NEW] Add support for universal wheels
|
||||
- [NEW] Slovenian locale
|
||||
- [NEW] Slovak locale
|
||||
- [NEW] Romanian locale
|
||||
- [FIX] respect limit even if end is defined range
|
||||
- [FIX] Separate replace & shift functions
|
||||
- [NEW] Added tox
|
||||
- [FIX] Fix supported Python versions in documentation
|
||||
- [NEW] Azerbaijani locale added, locale issue fixed in Turkish.
|
||||
- [FIX] Format ParserError's raise message
|
||||
|
||||
0.8.0
|
||||
-----
|
||||
|
||||
- []
|
||||
|
||||
0.7.1
|
||||
-----
|
||||
|
||||
- [NEW] Esperanto locale (batisteo)
|
||||
|
||||
0.7.0
|
||||
-----
|
||||
|
||||
- [FIX] Parse localized strings #228 (swistakm)
|
||||
- [FIX] Modify tzinfo parameter in ``get`` api #221 (bottleimp)
|
||||
- [FIX] Fix Czech locale (PrehistoricTeam)
|
||||
- [FIX] Raise TypeError when adding/subtracting non-dates (itsmeolivia)
|
||||
- [FIX] Fix pytz conversion error (Kudo)
|
||||
- [FIX] Fix overzealous time truncation in span_range (kdeldycke)
|
||||
- [NEW] Humanize for time duration #232 (ybrs)
|
||||
- [NEW] Add Thai locale (sipp11)
|
||||
- [NEW] Adding Belarusian (be) locale (oire)
|
||||
- [NEW] Search date in strings (beenje)
|
||||
- [NEW] Note that arrow's tokens differ from strptime's. (offby1)
|
||||
|
||||
0.6.0
|
||||
-----
|
||||
|
||||
- [FIX] Added support for Python 3
|
||||
- [FIX] Avoid truncating oversized epoch timestamps. Fixes #216.
|
||||
- [FIX] Fixed month abbreviations for Ukrainian
|
||||
- [FIX] Fix typo timezone
|
||||
- [FIX] A couple of dialect fixes and two new languages
|
||||
- [FIX] Spanish locale: ``Miercoles`` should have acute accent
|
||||
- [Fix] Fix Finnish grammar
|
||||
- [FIX] Fix typo in 'Arrow.floor' docstring
|
||||
- [FIX] Use read() utility to open README
|
||||
- [FIX] span_range for week frame
|
||||
- [NEW] Add minimal support for fractional seconds longer than six digits.
|
||||
- [NEW] Adding locale support for Marathi (mr)
|
||||
- [NEW] Add count argument to span method
|
||||
- [NEW] Improved docs
|
||||
|
||||
0.5.1 - 0.5.4
|
||||
-------------
|
||||
|
||||
- [FIX] test the behavior of simplejson instead of calling for_json directly (tonyseek)
|
||||
- [FIX] Add Hebrew Locale (doodyparizada)
|
||||
- [FIX] Update documentation location (andrewelkins)
|
||||
- [FIX] Update setup.py Development Status level (andrewelkins)
|
||||
- [FIX] Case insensitive month match (cshowe)
|
||||
|
||||
0.5.0
|
||||
-----
|
||||
|
||||
- [NEW] struct_time addition. (mhworth)
|
||||
- [NEW] Version grep (eirnym)
|
||||
- [NEW] Default to ISO 8601 format (emonty)
|
||||
- [NEW] Raise TypeError on comparison (sniekamp)
|
||||
- [NEW] Adding Macedonian(mk) locale (krisfremen)
|
||||
- [FIX] Fix for ISO seconds and fractional seconds (sdispater) (andrewelkins)
|
||||
- [FIX] Use correct Dutch wording for "hours" (wbolster)
|
||||
- [FIX] Complete the list of english locales (indorilftw)
|
||||
- [FIX] Change README to reStructuredText (nyuszika7h)
|
||||
- [FIX] Parse lower-cased 'h' (tamentis)
|
||||
- [FIX] Slight modifications to Dutch locale (nvie)
|
||||
|
||||
0.4.4
|
||||
-----
|
||||
|
||||
- [NEW] Include the docs in the released tarball
|
||||
- [NEW] Czech localization Czech localization for Arrow
|
||||
- [NEW] Add fa_ir to locales
|
||||
- [FIX] Fixes parsing of time strings with a final Z
|
||||
- [FIX] Fixes ISO parsing and formatting for fractional seconds
|
||||
- [FIX] test_fromtimestamp sp
|
||||
- [FIX] some typos fixed
|
||||
- [FIX] removed an unused import statement
|
||||
- [FIX] docs table fix
|
||||
- [FIX] Issue with specify 'X' template and no template at all to arrow.get
|
||||
- [FIX] Fix "import" typo in docs/index.rst
|
||||
- [FIX] Fix unit tests for zero passed
|
||||
- [FIX] Update layout.html
|
||||
- [FIX] In Norwegian and new Norwegian months and weekdays should not be capitalized
|
||||
- [FIX] Fixed discrepancy between specifying 'X' to arrow.get and specifying no template
|
||||
|
||||
0.4.3
|
||||
-----
|
||||
|
||||
- [NEW] Turkish locale (Emre)
|
||||
- [NEW] Arabic locale (Mosab Ahmad)
|
||||
- [NEW] Danish locale (Holmars)
|
||||
- [NEW] Icelandic locale (Holmars)
|
||||
- [NEW] Hindi locale (Atmb4u)
|
||||
- [NEW] Malayalam locale (Atmb4u)
|
||||
- [NEW] Finnish locale (Stormpat)
|
||||
- [NEW] Portuguese locale (Danielcorreia)
|
||||
- [NEW] ``h`` and ``hh`` strings are now supported (Averyonghub)
|
||||
- [FIX] An incorrect inflection in the Polish locale has been fixed (Avalanchy)
|
||||
- [FIX] ``arrow.get`` now properly handles ``Date`` (Jaapz)
|
||||
- [FIX] Tests are now declared in ``setup.py`` and the manifest (Pypingou)
|
||||
- [FIX] ``__version__`` has been added to ``__init__.py`` (Sametmax)
|
||||
- [FIX] ISO 8601 strings can be parsed without a separator (Ivandiguisto / Root)
|
||||
- [FIX] Documentation is now more clear regarding some inputs on ``arrow.get`` (Eriktaubeneck)
|
||||
- [FIX] Some documentation links have been fixed (Vrutsky)
|
||||
- [FIX] Error messages for parse errors are now more descriptive (Maciej Albin)
|
||||
- [FIX] The parser now correctly checks for separators in strings (Mschwager)
|
||||
|
||||
0.4.2
|
||||
-----
|
||||
|
||||
- [NEW] Factory ``get`` method now accepts a single ``Arrow`` argument.
|
||||
- [NEW] Tokens SSSS, SSSSS and SSSSSS are supported in parsing.
|
||||
- [NEW] ``Arrow`` objects have a ``float_timestamp`` property.
|
||||
- [NEW] Vietnamese locale (Iu1nguoi)
|
||||
- [NEW] Factory ``get`` method now accepts a list of format strings (Dgilland)
|
||||
- [NEW] A MANIFEST.in file has been added (Pypingou)
|
||||
- [NEW] Tests can be run directly from ``setup.py`` (Pypingou)
|
||||
- [FIX] Arrow docs now list 'day of week' format tokens correctly (Rudolphfroger)
|
||||
- [FIX] Several issues with the Korean locale have been resolved (Yoloseem)
|
||||
- [FIX] ``humanize`` now correctly returns unicode (Shvechikov)
|
||||
- [FIX] ``Arrow`` objects now pickle / unpickle correctly (Yoloseem)
|
||||
|
||||
0.4.1
|
||||
-----
|
||||
|
||||
- [NEW] Table / explanation of formatting & parsing tokens in docs
|
||||
- [NEW] Brazilian locale (Augusto2112)
|
||||
- [NEW] Dutch locale (OrangeTux)
|
||||
- [NEW] Italian locale (Pertux)
|
||||
- [NEW] Austrain locale (LeChewbacca)
|
||||
- [NEW] Tagalog locale (Marksteve)
|
||||
- [FIX] Corrected spelling and day numbers in German locale (LeChewbacca)
|
||||
- [FIX] Factory ``get`` method should now handle unicode strings correctly (Bwells)
|
||||
- [FIX] Midnight and noon should now parse and format correctly (Bwells)
|
||||
|
||||
0.4.0
|
||||
-----
|
||||
|
||||
- [NEW] Format-free ISO 8601 parsing in factory ``get`` method
|
||||
- [NEW] Support for 'week' / 'weeks' in ``span``, ``range``, ``span_range``, ``floor`` and ``ceil``
|
||||
- [NEW] Support for 'weeks' in ``replace``
|
||||
- [NEW] Norwegian locale (Martinp)
|
||||
- [NEW] Japanese locale (CortYuming)
|
||||
- [FIX] Timezones no longer show the wrong sign when formatted (Bean)
|
||||
- [FIX] Microseconds are parsed correctly from strings (Bsidhom)
|
||||
- [FIX] Locale day-of-week is no longer off by one (Cynddl)
|
||||
- [FIX] Corrected plurals of Ukrainian and Russian nouns (Catchagain)
|
||||
- [CHANGE] Old 0.1 ``arrow`` module method removed
|
||||
- [CHANGE] Dropped timestamp support in ``range`` and ``span_range`` (never worked correctly)
|
||||
- [CHANGE] Dropped parsing of single string as tz string in factory ``get`` method (replaced by ISO 8601)
|
||||
|
||||
0.3.5
|
||||
-----
|
||||
|
||||
- [NEW] French locale (Cynddl)
|
||||
- [NEW] Spanish locale (Slapresta)
|
||||
- [FIX] Ranges handle multiple timezones correctly (Ftobia)
|
||||
|
||||
0.3.4
|
||||
-----
|
||||
|
||||
- [FIX] Humanize no longer sometimes returns the wrong month delta
|
||||
- [FIX] ``__format__`` works correctly with no format string
|
||||
|
||||
0.3.3
|
||||
-----
|
||||
|
||||
- [NEW] Python 2.6 support
|
||||
- [NEW] Initial support for locale-based parsing and formatting
|
||||
- [NEW] ArrowFactory class, now proxied as the module API
|
||||
- [NEW] ``factory`` api method to obtain a factory for a custom type
|
||||
- [FIX] Python 3 support and tests completely ironed out
|
||||
|
||||
0.3.2
|
||||
-----
|
||||
|
||||
- [NEW] Python 3+ support
|
||||
|
||||
0.3.1
|
||||
-----
|
||||
|
||||
- [FIX] The old ``arrow`` module function handles timestamps correctly as it used to
|
||||
|
||||
0.3.0
|
||||
-----
|
||||
|
||||
- [NEW] ``Arrow.replace`` method
|
||||
- [NEW] Accept timestamps, datetimes and Arrows for datetime inputs, where reasonable
|
||||
- [FIX] ``range`` and ``span_range`` respect end and limit parameters correctly
|
||||
- [CHANGE] Arrow objects are no longer mutable
|
||||
- [CHANGE] Plural attribute name semantics altered: single -> absolute, plural -> relative
|
||||
- [CHANGE] Plural names no longer supported as properties (e.g. ``arrow.utcnow().years``)
|
||||
|
||||
0.2.1
|
||||
-----
|
||||
|
||||
- [NEW] Support for localized humanization
|
||||
- [NEW] English, Russian, Greek, Korean, Chinese locales
|
||||
|
||||
0.2.0
|
||||
-----
|
||||
|
||||
- **REWRITE**
|
||||
- [NEW] Date parsing
|
||||
- [NEW] Date formatting
|
||||
- [NEW] ``floor``, ``ceil`` and ``span`` methods
|
||||
- [NEW] ``datetime`` interface implementation
|
||||
- [NEW] ``clone`` method
|
||||
- [NEW] ``get``, ``now`` and ``utcnow`` API methods
|
||||
|
||||
0.1.6
|
||||
-----
|
||||
|
||||
- [NEW] Humanized time deltas
|
||||
- [NEW] ``__eq__`` implemented
|
||||
- [FIX] Issues with conversions related to daylight savings time resolved
|
||||
- [CHANGE] ``__str__`` uses ISO formatting
|
||||
|
||||
0.1.5
|
||||
-----
|
||||
|
||||
- **Started tracking changes**
|
||||
- [NEW] Parsing of ISO-formatted time zone offsets (e.g. '+02:30', '-05:00')
|
||||
- [NEW] Resolved some issues with timestamps and delta / Olson time zones
|
||||
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2019 Chris Smith
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
include LICENSE CHANGELOG.rst README.rst Makefile requirements.txt tox.ini
|
||||
recursive-include tests *.py
|
||||
recursive-include docs *.py *.rst *.bat Makefile
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
.PHONY: auto test docs clean
|
||||
|
||||
auto: build38
|
||||
|
||||
build27: PYTHON_VER = python2.7
|
||||
build35: PYTHON_VER = python3.5
|
||||
build36: PYTHON_VER = python3.6
|
||||
build37: PYTHON_VER = python3.7
|
||||
build38: PYTHON_VER = python3.8
|
||||
build39: PYTHON_VER = python3.9
|
||||
|
||||
build27 build35 build36 build37 build38 build39: clean
|
||||
virtualenv venv --python=$(PYTHON_VER)
|
||||
. venv/bin/activate; \
|
||||
pip install -r requirements.txt; \
|
||||
pre-commit install
|
||||
|
||||
test:
|
||||
rm -f .coverage coverage.xml
|
||||
. venv/bin/activate; pytest
|
||||
|
||||
lint:
|
||||
. venv/bin/activate; pre-commit run --all-files --show-diff-on-failure
|
||||
|
||||
docs:
|
||||
rm -rf docs/_build
|
||||
. venv/bin/activate; cd docs; make html
|
||||
|
||||
clean: clean-dist
|
||||
rm -rf venv .pytest_cache ./**/__pycache__
|
||||
rm -f .coverage coverage.xml ./**/*.pyc
|
||||
|
||||
clean-dist:
|
||||
rm -rf dist build .egg .eggs arrow.egg-info
|
||||
|
||||
build-dist:
|
||||
. venv/bin/activate; \
|
||||
pip install -U setuptools twine wheel; \
|
||||
python setup.py sdist bdist_wheel
|
||||
|
||||
upload-dist:
|
||||
. venv/bin/activate; twine upload dist/*
|
||||
|
||||
publish: test clean-dist build-dist upload-dist clean-dist
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
Arrow: Better dates & times for Python
|
||||
======================================
|
||||
|
||||
.. start-inclusion-marker-do-not-remove
|
||||
|
||||
.. image:: https://github.com/arrow-py/arrow/workflows/tests/badge.svg?branch=master
|
||||
:alt: Build Status
|
||||
:target: https://github.com/arrow-py/arrow/actions?query=workflow%3Atests+branch%3Amaster
|
||||
|
||||
.. image:: https://codecov.io/gh/arrow-py/arrow/branch/master/graph/badge.svg
|
||||
:alt: Coverage
|
||||
:target: https://codecov.io/gh/arrow-py/arrow
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/arrow.svg
|
||||
:alt: PyPI Version
|
||||
:target: https://pypi.python.org/pypi/arrow
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/arrow.svg
|
||||
:alt: Supported Python Versions
|
||||
:target: https://pypi.python.org/pypi/arrow
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/arrow.svg
|
||||
:alt: License
|
||||
:target: https://pypi.python.org/pypi/arrow
|
||||
|
||||
.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
|
||||
:alt: Code Style: Black
|
||||
:target: https://github.com/psf/black
|
||||
|
||||
|
||||
**Arrow** is a Python library that offers a sensible and human-friendly approach to creating, manipulating, formatting and converting dates, times and timestamps. It implements and updates the datetime type, plugging gaps in functionality and providing an intelligent module API that supports many common creation scenarios. Simply put, it helps you work with dates and times with fewer imports and a lot less code.
|
||||
|
||||
Arrow is named after the `arrow of time <https://en.wikipedia.org/wiki/Arrow_of_time>`_ and is heavily inspired by `moment.js <https://github.com/moment/moment>`_ and `requests <https://github.com/psf/requests>`_.
|
||||
|
||||
Why use Arrow over built-in modules?
|
||||
------------------------------------
|
||||
|
||||
Python's standard library and some other low-level modules have near-complete date, time and timezone functionality, but don't work very well from a usability perspective:
|
||||
|
||||
- Too many modules: datetime, time, calendar, dateutil, pytz and more
|
||||
- Too many types: date, time, datetime, tzinfo, timedelta, relativedelta, etc.
|
||||
- Timezones and timestamp conversions are verbose and unpleasant
|
||||
- Timezone naivety is the norm
|
||||
- Gaps in functionality: ISO 8601 parsing, timespans, humanization
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Fully-implemented, drop-in replacement for datetime
|
||||
- Supports Python 2.7, 3.5, 3.6, 3.7, 3.8 and 3.9
|
||||
- Timezone-aware and UTC by default
|
||||
- Provides super-simple creation options for many common input scenarios
|
||||
- :code:`shift` method with support for relative offsets, including weeks
|
||||
- Formats and parses strings automatically
|
||||
- Wide support for ISO 8601
|
||||
- Timezone conversion
|
||||
- Timestamp available as a property
|
||||
- Generates time spans, ranges, floors and ceilings for time frames ranging from microsecond to year
|
||||
- Humanizes and supports a growing list of contributed locales
|
||||
- Extensible for your own Arrow-derived types
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
||||
Installation
|
||||
~~~~~~~~~~~~
|
||||
|
||||
To install Arrow, use `pip <https://pip.pypa.io/en/stable/quickstart/>`_ or `pipenv <https://docs.pipenv.org>`_:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install -U arrow
|
||||
|
||||
Example Usage
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import arrow
|
||||
>>> arrow.get('2013-05-11T21:23:58.970460+07:00')
|
||||
<Arrow [2013-05-11T21:23:58.970460+07:00]>
|
||||
|
||||
>>> utc = arrow.utcnow()
|
||||
>>> utc
|
||||
<Arrow [2013-05-11T21:23:58.970460+00:00]>
|
||||
|
||||
>>> utc = utc.shift(hours=-1)
|
||||
>>> utc
|
||||
<Arrow [2013-05-11T20:23:58.970460+00:00]>
|
||||
|
||||
>>> local = utc.to('US/Pacific')
|
||||
>>> local
|
||||
<Arrow [2013-05-11T13:23:58.970460-07:00]>
|
||||
|
||||
>>> local.timestamp
|
||||
1368303838
|
||||
|
||||
>>> local.format()
|
||||
'2013-05-11 13:23:58 -07:00'
|
||||
|
||||
>>> local.format('YYYY-MM-DD HH:mm:ss ZZ')
|
||||
'2013-05-11 13:23:58 -07:00'
|
||||
|
||||
>>> local.humanize()
|
||||
'an hour ago'
|
||||
|
||||
>>> local.humanize(locale='ko_kr')
|
||||
'1시간 전'
|
||||
|
||||
.. end-inclusion-marker-do-not-remove
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
For full documentation, please visit `arrow.readthedocs.io <https://arrow.readthedocs.io>`_.
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
Contributions are welcome for both code and localizations (adding and updating locales). Begin by gaining familiarity with the Arrow library and its features. Then, jump into contributing:
|
||||
|
||||
#. Find an issue or feature to tackle on the `issue tracker <https://github.com/arrow-py/arrow/issues>`_. Issues marked with the `"good first issue" label <https://github.com/arrow-py/arrow/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22>`_ may be a great place to start!
|
||||
#. Fork `this repository <https://github.com/arrow-py/arrow>`_ on GitHub and begin making changes in a branch.
|
||||
#. Add a few tests to ensure that the bug was fixed or the feature works as expected.
|
||||
#. Run the entire test suite and linting checks by running one of the following commands: :code:`tox` (if you have `tox <https://tox.readthedocs.io>`_ installed) **OR** :code:`make build38 && make test && make lint` (if you do not have Python 3.8 installed, replace :code:`build38` with the latest Python version on your system).
|
||||
#. Submit a pull request and await feedback 😃.
|
||||
|
||||
If you have any questions along the way, feel free to ask them `here <https://github.com/arrow-py/arrow/issues/new?labels=question>`_.
|
||||
|
||||
Support Arrow
|
||||
-------------
|
||||
|
||||
`Open Collective <https://opencollective.com/>`_ is an online funding platform that provides tools to raise money and share your finances with full transparency. It is the platform of choice for individuals and companies to make one-time or recurring donations directly to the project. If you are interested in making a financial contribution, please visit the `Arrow collective <https://opencollective.com/arrow>`_.
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath(".."))
|
||||
|
||||
about = {}
|
||||
with io.open("../arrow/_version.py", "r", encoding="utf-8") as f:
|
||||
exec(f.read(), about)
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = u"Arrow 🏹"
|
||||
copyright = "2020, Chris Smith"
|
||||
author = "Chris Smith"
|
||||
|
||||
release = about["__version__"]
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
extensions = ["sphinx.ext.autodoc"]
|
||||
|
||||
templates_path = []
|
||||
|
||||
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||
|
||||
master_doc = "index"
|
||||
source_suffix = ".rst"
|
||||
pygments_style = "sphinx"
|
||||
|
||||
language = None
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
html_theme = "alabaster"
|
||||
html_theme_path = []
|
||||
html_static_path = []
|
||||
|
||||
html_show_sourcelink = False
|
||||
html_show_sphinx = False
|
||||
html_show_copyright = True
|
||||
|
||||
# https://alabaster.readthedocs.io/en/latest/customization.html
|
||||
html_theme_options = {
|
||||
"description": "Arrow is a sensible and human-friendly approach to dates, times and timestamps.",
|
||||
"github_user": "arrow-py",
|
||||
"github_repo": "arrow",
|
||||
"github_banner": True,
|
||||
"show_related": False,
|
||||
"show_powered_by": False,
|
||||
"github_button": True,
|
||||
"github_type": "star",
|
||||
"github_count": "true", # must be a string
|
||||
}
|
||||
|
||||
html_sidebars = {
|
||||
"**": ["about.html", "localtoc.html", "relations.html", "searchbox.html"]
|
||||
}
|
||||
|
|
@ -1,566 +0,0 @@
|
|||
Arrow: Better dates & times for Python
|
||||
======================================
|
||||
|
||||
Release v\ |release| (`Installation`_) (`Changelog <releases.html>`_)
|
||||
|
||||
.. include:: ../README.rst
|
||||
:start-after: start-inclusion-marker-do-not-remove
|
||||
:end-before: end-inclusion-marker-do-not-remove
|
||||
|
||||
User's Guide
|
||||
------------
|
||||
|
||||
Creation
|
||||
~~~~~~~~
|
||||
|
||||
Get 'now' easily:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.utcnow()
|
||||
<Arrow [2013-05-07T04:20:39.369271+00:00]>
|
||||
|
||||
>>> arrow.now()
|
||||
<Arrow [2013-05-06T21:20:40.841085-07:00]>
|
||||
|
||||
>>> arrow.now('US/Pacific')
|
||||
<Arrow [2013-05-06T21:20:44.761511-07:00]>
|
||||
|
||||
Create from timestamps (:code:`int` or :code:`float`):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get(1367900664)
|
||||
<Arrow [2013-05-07T04:24:24+00:00]>
|
||||
|
||||
>>> arrow.get(1367900664.152325)
|
||||
<Arrow [2013-05-07T04:24:24.152325+00:00]>
|
||||
|
||||
Use a naive or timezone-aware datetime, or flexibly specify a timezone:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get(datetime.utcnow())
|
||||
<Arrow [2013-05-07T04:24:24.152325+00:00]>
|
||||
|
||||
>>> arrow.get(datetime(2013, 5, 5), 'US/Pacific')
|
||||
<Arrow [2013-05-05T00:00:00-07:00]>
|
||||
|
||||
>>> from dateutil import tz
|
||||
>>> arrow.get(datetime(2013, 5, 5), tz.gettz('US/Pacific'))
|
||||
<Arrow [2013-05-05T00:00:00-07:00]>
|
||||
|
||||
>>> arrow.get(datetime.now(tz.gettz('US/Pacific')))
|
||||
<Arrow [2013-05-06T21:24:49.552236-07:00]>
|
||||
|
||||
Parse from a string:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get('2013-05-05 12:30:45', 'YYYY-MM-DD HH:mm:ss')
|
||||
<Arrow [2013-05-05T12:30:45+00:00]>
|
||||
|
||||
Search a date in a string:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get('June was born in May 1980', 'MMMM YYYY')
|
||||
<Arrow [1980-05-01T00:00:00+00:00]>
|
||||
|
||||
Some ISO 8601 compliant strings are recognized and parsed without a format string:
|
||||
|
||||
>>> arrow.get('2013-09-30T15:34:00.000-07:00')
|
||||
<Arrow [2013-09-30T15:34:00-07:00]>
|
||||
|
||||
Arrow objects can be instantiated directly too, with the same arguments as a datetime:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get(2013, 5, 5)
|
||||
<Arrow [2013-05-05T00:00:00+00:00]>
|
||||
|
||||
>>> arrow.Arrow(2013, 5, 5)
|
||||
<Arrow [2013-05-05T00:00:00+00:00]>
|
||||
|
||||
Properties
|
||||
~~~~~~~~~~
|
||||
|
||||
Get a datetime or timestamp representation:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> a = arrow.utcnow()
|
||||
>>> a.datetime
|
||||
datetime.datetime(2013, 5, 7, 4, 38, 15, 447644, tzinfo=tzutc())
|
||||
|
||||
>>> a.timestamp
|
||||
1367901495
|
||||
|
||||
Get a naive datetime, and tzinfo:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> a.naive
|
||||
datetime.datetime(2013, 5, 7, 4, 38, 15, 447644)
|
||||
|
||||
>>> a.tzinfo
|
||||
tzutc()
|
||||
|
||||
Get any datetime value:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> a.year
|
||||
2013
|
||||
|
||||
Call datetime functions that return properties:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> a.date()
|
||||
datetime.date(2013, 5, 7)
|
||||
|
||||
>>> a.time()
|
||||
datetime.time(4, 38, 15, 447644)
|
||||
|
||||
Replace & Shift
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Get a new :class:`Arrow <arrow.arrow.Arrow>` object, with altered attributes, just as you would with a datetime:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arw = arrow.utcnow()
|
||||
>>> arw
|
||||
<Arrow [2013-05-12T03:29:35.334214+00:00]>
|
||||
|
||||
>>> arw.replace(hour=4, minute=40)
|
||||
<Arrow [2013-05-12T04:40:35.334214+00:00]>
|
||||
|
||||
Or, get one with attributes shifted forward or backward:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arw.shift(weeks=+3)
|
||||
<Arrow [2013-06-02T03:29:35.334214+00:00]>
|
||||
|
||||
Even replace the timezone without altering other attributes:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arw.replace(tzinfo='US/Pacific')
|
||||
<Arrow [2013-05-12T03:29:35.334214-07:00]>
|
||||
|
||||
Move between the earlier and later moments of an ambiguous time:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> paris_transition = arrow.Arrow(2019, 10, 27, 2, tzinfo="Europe/Paris", fold=0)
|
||||
>>> paris_transition
|
||||
<Arrow [2019-10-27T02:00:00+02:00]>
|
||||
>>> paris_transition.ambiguous
|
||||
True
|
||||
>>> paris_transition.replace(fold=1)
|
||||
<Arrow [2019-10-27T02:00:00+01:00]>
|
||||
|
||||
Format
|
||||
~~~~~~
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.utcnow().format('YYYY-MM-DD HH:mm:ss ZZ')
|
||||
'2013-05-07 05:23:16 -00:00'
|
||||
|
||||
Convert
|
||||
~~~~~~~
|
||||
|
||||
Convert from UTC to other timezones by name or tzinfo:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> utc = arrow.utcnow()
|
||||
>>> utc
|
||||
<Arrow [2013-05-07T05:24:11.823627+00:00]>
|
||||
|
||||
>>> utc.to('US/Pacific')
|
||||
<Arrow [2013-05-06T22:24:11.823627-07:00]>
|
||||
|
||||
>>> utc.to(tz.gettz('US/Pacific'))
|
||||
<Arrow [2013-05-06T22:24:11.823627-07:00]>
|
||||
|
||||
Or using shorthand:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> utc.to('local')
|
||||
<Arrow [2013-05-06T22:24:11.823627-07:00]>
|
||||
|
||||
>>> utc.to('local').to('utc')
|
||||
<Arrow [2013-05-07T05:24:11.823627+00:00]>
|
||||
|
||||
|
||||
Humanize
|
||||
~~~~~~~~
|
||||
|
||||
Humanize relative to now:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> past = arrow.utcnow().shift(hours=-1)
|
||||
>>> past.humanize()
|
||||
'an hour ago'
|
||||
|
||||
Or another Arrow, or datetime:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> present = arrow.utcnow()
|
||||
>>> future = present.shift(hours=2)
|
||||
>>> future.humanize(present)
|
||||
'in 2 hours'
|
||||
|
||||
Indicate time as relative or include only the distance
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> present = arrow.utcnow()
|
||||
>>> future = present.shift(hours=2)
|
||||
>>> future.humanize(present)
|
||||
'in 2 hours'
|
||||
>>> future.humanize(present, only_distance=True)
|
||||
'2 hours'
|
||||
|
||||
|
||||
Indicate a specific time granularity (or multiple):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> present = arrow.utcnow()
|
||||
>>> future = present.shift(minutes=66)
|
||||
>>> future.humanize(present, granularity="minute")
|
||||
'in 66 minutes'
|
||||
>>> future.humanize(present, granularity=["hour", "minute"])
|
||||
'in an hour and 6 minutes'
|
||||
>>> present.humanize(future, granularity=["hour", "minute"])
|
||||
'an hour and 6 minutes ago'
|
||||
>>> future.humanize(present, only_distance=True, granularity=["hour", "minute"])
|
||||
'an hour and 6 minutes'
|
||||
|
||||
Support for a growing number of locales (see ``locales.py`` for supported languages):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
>>> future = arrow.utcnow().shift(hours=1)
|
||||
>>> future.humanize(a, locale='ru')
|
||||
'через 2 час(а,ов)'
|
||||
|
||||
|
||||
Ranges & Spans
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Get the time span of any unit:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.utcnow().span('hour')
|
||||
(<Arrow [2013-05-07T05:00:00+00:00]>, <Arrow [2013-05-07T05:59:59.999999+00:00]>)
|
||||
|
||||
Or just get the floor and ceiling:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.utcnow().floor('hour')
|
||||
<Arrow [2013-05-07T05:00:00+00:00]>
|
||||
|
||||
>>> arrow.utcnow().ceil('hour')
|
||||
<Arrow [2013-05-07T05:59:59.999999+00:00]>
|
||||
|
||||
You can also get a range of time spans:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> start = datetime(2013, 5, 5, 12, 30)
|
||||
>>> end = datetime(2013, 5, 5, 17, 15)
|
||||
>>> for r in arrow.Arrow.span_range('hour', start, end):
|
||||
... print r
|
||||
...
|
||||
(<Arrow [2013-05-05T12:00:00+00:00]>, <Arrow [2013-05-05T12:59:59.999999+00:00]>)
|
||||
(<Arrow [2013-05-05T13:00:00+00:00]>, <Arrow [2013-05-05T13:59:59.999999+00:00]>)
|
||||
(<Arrow [2013-05-05T14:00:00+00:00]>, <Arrow [2013-05-05T14:59:59.999999+00:00]>)
|
||||
(<Arrow [2013-05-05T15:00:00+00:00]>, <Arrow [2013-05-05T15:59:59.999999+00:00]>)
|
||||
(<Arrow [2013-05-05T16:00:00+00:00]>, <Arrow [2013-05-05T16:59:59.999999+00:00]>)
|
||||
|
||||
Or just iterate over a range of time:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> start = datetime(2013, 5, 5, 12, 30)
|
||||
>>> end = datetime(2013, 5, 5, 17, 15)
|
||||
>>> for r in arrow.Arrow.range('hour', start, end):
|
||||
... print repr(r)
|
||||
...
|
||||
<Arrow [2013-05-05T12:30:00+00:00]>
|
||||
<Arrow [2013-05-05T13:30:00+00:00]>
|
||||
<Arrow [2013-05-05T14:30:00+00:00]>
|
||||
<Arrow [2013-05-05T15:30:00+00:00]>
|
||||
<Arrow [2013-05-05T16:30:00+00:00]>
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
Factories
|
||||
~~~~~~~~~
|
||||
|
||||
Use factories to harness Arrow's module API for a custom Arrow-derived type. First, derive your type:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> class CustomArrow(arrow.Arrow):
|
||||
...
|
||||
... def days_till_xmas(self):
|
||||
...
|
||||
... xmas = arrow.Arrow(self.year, 12, 25)
|
||||
...
|
||||
... if self > xmas:
|
||||
... xmas = xmas.shift(years=1)
|
||||
...
|
||||
... return (xmas - self).days
|
||||
|
||||
|
||||
Then get and use a factory for it:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> factory = arrow.ArrowFactory(CustomArrow)
|
||||
>>> custom = factory.utcnow()
|
||||
>>> custom
|
||||
>>> <CustomArrow [2013-05-27T23:35:35.533160+00:00]>
|
||||
|
||||
>>> custom.days_till_xmas()
|
||||
>>> 211
|
||||
|
||||
Supported Tokens
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Use the following tokens for parsing and formatting. Note that they are **not** the same as the tokens for `strptime <https://linux.die.net/man/3/strptime>`_:
|
||||
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |Token |Output |
|
||||
+================================+==============+===========================================+
|
||||
|**Year** |YYYY |2000, 2001, 2002 ... 2012, 2013 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |YY |00, 01, 02 ... 12, 13 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**Month** |MMMM |January, February, March ... [#t1]_ |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |MMM |Jan, Feb, Mar ... [#t1]_ |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |MM |01, 02, 03 ... 11, 12 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |M |1, 2, 3 ... 11, 12 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**Day of Year** |DDDD |001, 002, 003 ... 364, 365 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |DDD |1, 2, 3 ... 364, 365 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**Day of Month** |DD |01, 02, 03 ... 30, 31 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |D |1, 2, 3 ... 30, 31 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |Do |1st, 2nd, 3rd ... 30th, 31st |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**Day of Week** |dddd |Monday, Tuesday, Wednesday ... [#t2]_ |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |ddd |Mon, Tue, Wed ... [#t2]_ |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |d |1, 2, 3 ... 6, 7 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**ISO week date** |W |2011-W05-4, 2019-W17 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**Hour** |HH |00, 01, 02 ... 23, 24 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |H |0, 1, 2 ... 23, 24 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |hh |01, 02, 03 ... 11, 12 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |h |1, 2, 3 ... 11, 12 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**AM / PM** |A |AM, PM, am, pm [#t1]_ |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |a |am, pm [#t1]_ |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**Minute** |mm |00, 01, 02 ... 58, 59 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |m |0, 1, 2 ... 58, 59 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**Second** |ss |00, 01, 02 ... 58, 59 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |s |0, 1, 2 ... 58, 59 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**Sub-second** |S... |0, 02, 003, 000006, 123123123123... [#t3]_ |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**Timezone** |ZZZ |Asia/Baku, Europe/Warsaw, GMT ... [#t4]_ |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |ZZ |-07:00, -06:00 ... +06:00, +07:00, +08, Z |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
| |Z |-0700, -0600 ... +0600, +0700, +08, Z |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**Seconds Timestamp** |X |1381685817, 1381685817.915482 ... [#t5]_ |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|**ms or µs Timestamp** |x |1569980330813, 1569980330813221 |
|
||||
+--------------------------------+--------------+-------------------------------------------+
|
||||
|
||||
.. rubric:: Footnotes
|
||||
|
||||
.. [#t1] localization support for parsing and formatting
|
||||
.. [#t2] localization support only for formatting
|
||||
.. [#t3] the result is truncated to microseconds, with `half-to-even rounding <https://en.wikipedia.org/wiki/IEEE_floating_point#Roundings_to_nearest>`_.
|
||||
.. [#t4] timezone names from `tz database <https://www.iana.org/time-zones>`_ provided via dateutil package, note that abbreviations such as MST, PDT, BRST are unlikely to parse due to ambiguity. Use the full IANA zone name instead (Asia/Shanghai, Europe/London, America/Chicago etc).
|
||||
.. [#t5] this token cannot be used for parsing timestamps out of natural language strings due to compatibility reasons
|
||||
|
||||
Built-in Formats
|
||||
++++++++++++++++
|
||||
|
||||
There are several formatting standards that are provided as built-in tokens.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arw = arrow.utcnow()
|
||||
>>> arw.format(arrow.FORMAT_ATOM)
|
||||
'2020-05-27 10:30:35+00:00'
|
||||
>>> arw.format(arrow.FORMAT_COOKIE)
|
||||
'Wednesday, 27-May-2020 10:30:35 UTC'
|
||||
>>> arw.format(arrow.FORMAT_RSS)
|
||||
'Wed, 27 May 2020 10:30:35 +0000'
|
||||
>>> arw.format(arrow.FORMAT_RFC822)
|
||||
'Wed, 27 May 20 10:30:35 +0000'
|
||||
>>> arw.format(arrow.FORMAT_RFC850)
|
||||
'Wednesday, 27-May-20 10:30:35 UTC'
|
||||
>>> arw.format(arrow.FORMAT_RFC1036)
|
||||
'Wed, 27 May 20 10:30:35 +0000'
|
||||
>>> arw.format(arrow.FORMAT_RFC1123)
|
||||
'Wed, 27 May 2020 10:30:35 +0000'
|
||||
>>> arw.format(arrow.FORMAT_RFC2822)
|
||||
'Wed, 27 May 2020 10:30:35 +0000'
|
||||
>>> arw.format(arrow.FORMAT_RFC3339)
|
||||
'2020-05-27 10:30:35+00:00'
|
||||
>>> arw.format(arrow.FORMAT_W3C)
|
||||
'2020-05-27 10:30:35+00:00'
|
||||
|
||||
Escaping Formats
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Tokens, phrases, and regular expressions in a format string can be escaped when parsing and formatting by enclosing them within square brackets.
|
||||
|
||||
Tokens & Phrases
|
||||
++++++++++++++++
|
||||
|
||||
Any `token <Supported Tokens_>`_ or phrase can be escaped as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> fmt = "YYYY-MM-DD h [h] m"
|
||||
>>> arw = arrow.get("2018-03-09 8 h 40", fmt)
|
||||
<Arrow [2018-03-09T08:40:00+00:00]>
|
||||
>>> arw.format(fmt)
|
||||
'2018-03-09 8 h 40'
|
||||
|
||||
>>> fmt = "YYYY-MM-DD h [hello] m"
|
||||
>>> arw = arrow.get("2018-03-09 8 hello 40", fmt)
|
||||
<Arrow [2018-03-09T08:40:00+00:00]>
|
||||
>>> arw.format(fmt)
|
||||
'2018-03-09 8 hello 40'
|
||||
|
||||
>>> fmt = "YYYY-MM-DD h [hello world] m"
|
||||
>>> arw = arrow.get("2018-03-09 8 hello world 40", fmt)
|
||||
<Arrow [2018-03-09T08:40:00+00:00]>
|
||||
>>> arw.format(fmt)
|
||||
'2018-03-09 8 hello world 40'
|
||||
|
||||
This can be useful for parsing dates in different locales such as French, in which it is common to format time strings as "8 h 40" rather than "8:40".
|
||||
|
||||
Regular Expressions
|
||||
+++++++++++++++++++
|
||||
|
||||
You can also escape regular expressions by enclosing them within square brackets. In the following example, we are using the regular expression :code:`\s+` to match any number of whitespace characters that separate the tokens. This is useful if you do not know the number of spaces between tokens ahead of time (e.g. in log files).
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> fmt = r"ddd[\s+]MMM[\s+]DD[\s+]HH:mm:ss[\s+]YYYY"
|
||||
>>> arrow.get("Mon Sep 08 16:41:45 2014", fmt)
|
||||
<Arrow [2014-09-08T16:41:45+00:00]>
|
||||
|
||||
>>> arrow.get("Mon \tSep 08 16:41:45 2014", fmt)
|
||||
<Arrow [2014-09-08T16:41:45+00:00]>
|
||||
|
||||
>>> arrow.get("Mon Sep 08 16:41:45 2014", fmt)
|
||||
<Arrow [2014-09-08T16:41:45+00:00]>
|
||||
|
||||
Punctuation
|
||||
~~~~~~~~~~~
|
||||
|
||||
Date and time formats may be fenced on either side by one punctuation character from the following list: ``, . ; : ? ! " \` ' [ ] { } ( ) < >``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get("Cool date: 2019-10-31T09:12:45.123456+04:30.", "YYYY-MM-DDTHH:mm:ss.SZZ")
|
||||
<Arrow [2019-10-31T09:12:45.123456+04:30]>
|
||||
|
||||
>>> arrow.get("Tomorrow (2019-10-31) is Halloween!", "YYYY-MM-DD")
|
||||
<Arrow [2019-10-31T00:00:00+00:00]>
|
||||
|
||||
>>> arrow.get("Halloween is on 2019.10.31.", "YYYY.MM.DD")
|
||||
<Arrow [2019-10-31T00:00:00+00:00]>
|
||||
|
||||
>>> arrow.get("It's Halloween tomorrow (2019-10-31)!", "YYYY-MM-DD")
|
||||
# Raises exception because there are multiple punctuation marks following the date
|
||||
|
||||
Redundant Whitespace
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Redundant whitespace characters (spaces, tabs, and newlines) can be normalized automatically by passing in the ``normalize_whitespace`` flag to ``arrow.get``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> arrow.get('\t \n 2013-05-05T12:30:45.123456 \t \n', normalize_whitespace=True)
|
||||
<Arrow [2013-05-05T12:30:45.123456+00:00]>
|
||||
|
||||
>>> arrow.get('2013-05-05 T \n 12:30:45\t123456', 'YYYY-MM-DD T HH:mm:ss S', normalize_whitespace=True)
|
||||
<Arrow [2013-05-05T12:30:45.123456+00:00]>
|
||||
|
||||
API Guide
|
||||
---------
|
||||
|
||||
arrow.arrow
|
||||
~~~~~~~~~~~
|
||||
|
||||
.. automodule:: arrow.arrow
|
||||
:members:
|
||||
|
||||
arrow.factory
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
.. automodule:: arrow.factory
|
||||
:members:
|
||||
|
||||
arrow.api
|
||||
~~~~~~~~~
|
||||
|
||||
.. automodule:: arrow.api
|
||||
:members:
|
||||
|
||||
arrow.locale
|
||||
~~~~~~~~~~~~
|
||||
|
||||
.. automodule:: arrow.locales
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
Release History
|
||||
---------------
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
releases
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
.. _releases:
|
||||
|
||||
.. include:: ../CHANGELOG.rst
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
backports.functools_lru_cache==1.6.1; python_version == "2.7"
|
||||
dateparser==0.7.*
|
||||
pre-commit==1.21.*; python_version <= "3.5"
|
||||
pre-commit==2.6.*; python_version >= "3.6"
|
||||
pytest==4.6.*; python_version == "2.7"
|
||||
pytest==6.0.*; python_version >= "3.5"
|
||||
pytest-cov==2.10.*
|
||||
pytest-mock==2.0.*; python_version == "2.7"
|
||||
pytest-mock==3.2.*; python_version >= "3.5"
|
||||
python-dateutil==2.8.*
|
||||
pytz==2019.*
|
||||
simplejson==3.17.*
|
||||
sphinx==1.8.*; python_version == "2.7"
|
||||
sphinx==3.2.*; python_version >= "3.5"
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
[bdist_wheel]
|
||||
universal = 1
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import io
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
with io.open("README.rst", "r", encoding="utf-8") as f:
|
||||
readme = f.read()
|
||||
|
||||
about = {}
|
||||
with io.open("arrow/_version.py", "r", encoding="utf-8") as f:
|
||||
exec(f.read(), about)
|
||||
|
||||
setup(
|
||||
name="arrow",
|
||||
version=about["__version__"],
|
||||
description="Better dates & times for Python",
|
||||
long_description=readme,
|
||||
long_description_content_type="text/x-rst",
|
||||
url="https://arrow.readthedocs.io",
|
||||
author="Chris Smith",
|
||||
author_email="crsmithdev@gmail.com",
|
||||
license="Apache 2.0",
|
||||
packages=["arrow"],
|
||||
zip_safe=False,
|
||||
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
|
||||
install_requires=[
|
||||
"python-dateutil>=2.7.0",
|
||||
"backports.functools_lru_cache>=1.2.1;python_version=='2.7'",
|
||||
],
|
||||
classifiers=[
|
||||
"Development Status :: 4 - Beta",
|
||||
"Intended Audience :: Developers",
|
||||
"License :: OSI Approved :: Apache Software License",
|
||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||
"Programming Language :: Python :: 2",
|
||||
"Programming Language :: Python :: 2.7",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3.5",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
],
|
||||
keywords="arrow date time datetime timestamp timezone humanize",
|
||||
project_urls={
|
||||
"Repository": "https://github.com/arrow-py/arrow",
|
||||
"Bug Reports": "https://github.com/arrow-py/arrow/issues",
|
||||
"Documentation": "https://arrow.readthedocs.io",
|
||||
},
|
||||
)
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
from dateutil import tz as dateutil_tz
|
||||
|
||||
from arrow import arrow, factory, formatter, locales, parser
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def time_utcnow(request):
|
||||
request.cls.arrow = arrow.Arrow.utcnow()
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def time_2013_01_01(request):
|
||||
request.cls.now = arrow.Arrow.utcnow()
|
||||
request.cls.arrow = arrow.Arrow(2013, 1, 1)
|
||||
request.cls.datetime = datetime(2013, 1, 1)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def time_2013_02_03(request):
|
||||
request.cls.arrow = arrow.Arrow(2013, 2, 3, 12, 30, 45, 1)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def time_2013_02_15(request):
|
||||
request.cls.datetime = datetime(2013, 2, 15, 3, 41, 22, 8923)
|
||||
request.cls.arrow = arrow.Arrow.fromdatetime(request.cls.datetime)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def time_1975_12_25(request):
|
||||
request.cls.datetime = datetime(
|
||||
1975, 12, 25, 14, 15, 16, tzinfo=dateutil_tz.gettz("America/New_York")
|
||||
)
|
||||
request.cls.arrow = arrow.Arrow.fromdatetime(request.cls.datetime)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def arrow_formatter(request):
|
||||
request.cls.formatter = formatter.DateTimeFormatter()
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def arrow_factory(request):
|
||||
request.cls.factory = factory.ArrowFactory()
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def lang_locales(request):
|
||||
request.cls.locales = locales._locales
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def lang_locale(request):
|
||||
# As locale test classes are prefixed with Test, we are dynamically getting the locale by the test class name.
|
||||
# TestEnglishLocale -> EnglishLocale
|
||||
name = request.cls.__name__[4:]
|
||||
request.cls.locale = locales.get_locale_by_class_name(name)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def dt_parser(request):
|
||||
request.cls.parser = parser.DateTimeParser()
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def dt_parser_regex(request):
|
||||
request.cls.format_regex = parser.DateTimeParser._FORMAT_RE
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def tzinfo_parser(request):
|
||||
request.cls.parser = parser.TzinfoParser()
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import arrow
|
||||
|
||||
|
||||
class TestModule:
|
||||
def test_get(self, mocker):
|
||||
mocker.patch("arrow.api._factory.get", return_value="result")
|
||||
|
||||
assert arrow.api.get() == "result"
|
||||
|
||||
def test_utcnow(self, mocker):
|
||||
mocker.patch("arrow.api._factory.utcnow", return_value="utcnow")
|
||||
|
||||
assert arrow.api.utcnow() == "utcnow"
|
||||
|
||||
def test_now(self, mocker):
|
||||
mocker.patch("arrow.api._factory.now", tz="tz", return_value="now")
|
||||
|
||||
assert arrow.api.now("tz") == "now"
|
||||
|
||||
def test_factory(self):
|
||||
class MockCustomArrowClass(arrow.Arrow):
|
||||
pass
|
||||
|
||||
result = arrow.api.factory(MockCustomArrowClass)
|
||||
|
||||
assert isinstance(result, arrow.factory.ArrowFactory)
|
||||
assert isinstance(result.utcnow(), MockCustomArrowClass)
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,390 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
from datetime import date, datetime
|
||||
|
||||
import pytest
|
||||
from dateutil import tz
|
||||
|
||||
from arrow.parser import ParserError
|
||||
|
||||
from .utils import assert_datetime_equality
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("arrow_factory")
|
||||
class TestGet:
|
||||
def test_no_args(self):
|
||||
|
||||
assert_datetime_equality(
|
||||
self.factory.get(), datetime.utcnow().replace(tzinfo=tz.tzutc())
|
||||
)
|
||||
|
||||
def test_timestamp_one_arg_no_arg(self):
|
||||
|
||||
no_arg = self.factory.get(1406430900).timestamp
|
||||
one_arg = self.factory.get("1406430900", "X").timestamp
|
||||
|
||||
assert no_arg == one_arg
|
||||
|
||||
def test_one_arg_none(self):
|
||||
|
||||
assert_datetime_equality(
|
||||
self.factory.get(None), datetime.utcnow().replace(tzinfo=tz.tzutc())
|
||||
)
|
||||
|
||||
def test_struct_time(self):
|
||||
|
||||
assert_datetime_equality(
|
||||
self.factory.get(time.gmtime()),
|
||||
datetime.utcnow().replace(tzinfo=tz.tzutc()),
|
||||
)
|
||||
|
||||
def test_one_arg_timestamp(self):
|
||||
|
||||
int_timestamp = int(time.time())
|
||||
timestamp_dt = datetime.utcfromtimestamp(int_timestamp).replace(
|
||||
tzinfo=tz.tzutc()
|
||||
)
|
||||
|
||||
assert self.factory.get(int_timestamp) == timestamp_dt
|
||||
|
||||
with pytest.raises(ParserError):
|
||||
self.factory.get(str(int_timestamp))
|
||||
|
||||
float_timestamp = time.time()
|
||||
timestamp_dt = datetime.utcfromtimestamp(float_timestamp).replace(
|
||||
tzinfo=tz.tzutc()
|
||||
)
|
||||
|
||||
assert self.factory.get(float_timestamp) == timestamp_dt
|
||||
|
||||
with pytest.raises(ParserError):
|
||||
self.factory.get(str(float_timestamp))
|
||||
|
||||
# Regression test for issue #216
|
||||
# Python 3 raises OverflowError, Python 2 raises ValueError
|
||||
timestamp = 99999999999999999999999999.99999999999999999999999999
|
||||
with pytest.raises((OverflowError, ValueError)):
|
||||
self.factory.get(timestamp)
|
||||
|
||||
def test_one_arg_expanded_timestamp(self):
|
||||
|
||||
millisecond_timestamp = 1591328104308
|
||||
microsecond_timestamp = 1591328104308505
|
||||
|
||||
# Regression test for issue #796
|
||||
assert self.factory.get(millisecond_timestamp) == datetime.utcfromtimestamp(
|
||||
1591328104.308
|
||||
).replace(tzinfo=tz.tzutc())
|
||||
assert self.factory.get(microsecond_timestamp) == datetime.utcfromtimestamp(
|
||||
1591328104.308505
|
||||
).replace(tzinfo=tz.tzutc())
|
||||
|
||||
def test_one_arg_timestamp_with_tzinfo(self):
|
||||
|
||||
timestamp = time.time()
|
||||
timestamp_dt = datetime.fromtimestamp(timestamp, tz=tz.tzutc()).astimezone(
|
||||
tz.gettz("US/Pacific")
|
||||
)
|
||||
timezone = tz.gettz("US/Pacific")
|
||||
|
||||
assert_datetime_equality(
|
||||
self.factory.get(timestamp, tzinfo=timezone), timestamp_dt
|
||||
)
|
||||
|
||||
def test_one_arg_arrow(self):
|
||||
|
||||
arw = self.factory.utcnow()
|
||||
result = self.factory.get(arw)
|
||||
|
||||
assert arw == result
|
||||
|
||||
def test_one_arg_datetime(self):
|
||||
|
||||
dt = datetime.utcnow().replace(tzinfo=tz.tzutc())
|
||||
|
||||
assert self.factory.get(dt) == dt
|
||||
|
||||
def test_one_arg_date(self):
|
||||
|
||||
d = date.today()
|
||||
dt = datetime(d.year, d.month, d.day, tzinfo=tz.tzutc())
|
||||
|
||||
assert self.factory.get(d) == dt
|
||||
|
||||
def test_one_arg_tzinfo(self):
|
||||
|
||||
self.expected = (
|
||||
datetime.utcnow()
|
||||
.replace(tzinfo=tz.tzutc())
|
||||
.astimezone(tz.gettz("US/Pacific"))
|
||||
)
|
||||
|
||||
assert_datetime_equality(
|
||||
self.factory.get(tz.gettz("US/Pacific")), self.expected
|
||||
)
|
||||
|
||||
# regression test for issue #658
|
||||
def test_one_arg_dateparser_datetime(self):
|
||||
dateparser = pytest.importorskip("dateparser")
|
||||
expected = datetime(1990, 1, 1).replace(tzinfo=tz.tzutc())
|
||||
# dateparser outputs: datetime.datetime(1990, 1, 1, 0, 0, tzinfo=<StaticTzInfo 'UTC\+00:00'>)
|
||||
parsed_date = dateparser.parse("1990-01-01T00:00:00+00:00")
|
||||
dt_output = self.factory.get(parsed_date)._datetime.replace(tzinfo=tz.tzutc())
|
||||
assert dt_output == expected
|
||||
|
||||
def test_kwarg_tzinfo(self):
|
||||
|
||||
self.expected = (
|
||||
datetime.utcnow()
|
||||
.replace(tzinfo=tz.tzutc())
|
||||
.astimezone(tz.gettz("US/Pacific"))
|
||||
)
|
||||
|
||||
assert_datetime_equality(
|
||||
self.factory.get(tzinfo=tz.gettz("US/Pacific")), self.expected
|
||||
)
|
||||
|
||||
def test_kwarg_tzinfo_string(self):
|
||||
|
||||
self.expected = (
|
||||
datetime.utcnow()
|
||||
.replace(tzinfo=tz.tzutc())
|
||||
.astimezone(tz.gettz("US/Pacific"))
|
||||
)
|
||||
|
||||
assert_datetime_equality(self.factory.get(tzinfo="US/Pacific"), self.expected)
|
||||
|
||||
with pytest.raises(ParserError):
|
||||
self.factory.get(tzinfo="US/PacificInvalidTzinfo")
|
||||
|
||||
def test_kwarg_normalize_whitespace(self):
|
||||
result = self.factory.get(
|
||||
"Jun 1 2005 1:33PM",
|
||||
"MMM D YYYY H:mmA",
|
||||
tzinfo=tz.tzutc(),
|
||||
normalize_whitespace=True,
|
||||
)
|
||||
assert result._datetime == datetime(2005, 6, 1, 13, 33, tzinfo=tz.tzutc())
|
||||
|
||||
result = self.factory.get(
|
||||
"\t 2013-05-05T12:30:45.123456 \t \n",
|
||||
tzinfo=tz.tzutc(),
|
||||
normalize_whitespace=True,
|
||||
)
|
||||
assert result._datetime == datetime(
|
||||
2013, 5, 5, 12, 30, 45, 123456, tzinfo=tz.tzutc()
|
||||
)
|
||||
|
||||
def test_one_arg_iso_str(self):
|
||||
|
||||
dt = datetime.utcnow()
|
||||
|
||||
assert_datetime_equality(
|
||||
self.factory.get(dt.isoformat()), dt.replace(tzinfo=tz.tzutc())
|
||||
)
|
||||
|
||||
def test_one_arg_iso_calendar(self):
|
||||
|
||||
pairs = [
|
||||
(datetime(2004, 1, 4), (2004, 1, 7)),
|
||||
(datetime(2008, 12, 30), (2009, 1, 2)),
|
||||
(datetime(2010, 1, 2), (2009, 53, 6)),
|
||||
(datetime(2000, 2, 29), (2000, 9, 2)),
|
||||
(datetime(2005, 1, 1), (2004, 53, 6)),
|
||||
(datetime(2010, 1, 4), (2010, 1, 1)),
|
||||
(datetime(2010, 1, 3), (2009, 53, 7)),
|
||||
(datetime(2003, 12, 29), (2004, 1, 1)),
|
||||
]
|
||||
|
||||
for pair in pairs:
|
||||
dt, iso = pair
|
||||
assert self.factory.get(iso) == self.factory.get(dt)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
self.factory.get((2014, 7, 1, 4))
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
self.factory.get((2014, 7))
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
self.factory.get((2014, 70, 1))
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
self.factory.get((2014, 7, 10))
|
||||
|
||||
def test_one_arg_other(self):
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
self.factory.get(object())
|
||||
|
||||
def test_one_arg_bool(self):
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
self.factory.get(False)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
self.factory.get(True)
|
||||
|
||||
def test_two_args_datetime_tzinfo(self):
|
||||
|
||||
result = self.factory.get(datetime(2013, 1, 1), tz.gettz("US/Pacific"))
|
||||
|
||||
assert result._datetime == datetime(2013, 1, 1, tzinfo=tz.gettz("US/Pacific"))
|
||||
|
||||
def test_two_args_datetime_tz_str(self):
|
||||
|
||||
result = self.factory.get(datetime(2013, 1, 1), "US/Pacific")
|
||||
|
||||
assert result._datetime == datetime(2013, 1, 1, tzinfo=tz.gettz("US/Pacific"))
|
||||
|
||||
def test_two_args_date_tzinfo(self):
|
||||
|
||||
result = self.factory.get(date(2013, 1, 1), tz.gettz("US/Pacific"))
|
||||
|
||||
assert result._datetime == datetime(2013, 1, 1, tzinfo=tz.gettz("US/Pacific"))
|
||||
|
||||
def test_two_args_date_tz_str(self):
|
||||
|
||||
result = self.factory.get(date(2013, 1, 1), "US/Pacific")
|
||||
|
||||
assert result._datetime == datetime(2013, 1, 1, tzinfo=tz.gettz("US/Pacific"))
|
||||
|
||||
def test_two_args_datetime_other(self):
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
self.factory.get(datetime.utcnow(), object())
|
||||
|
||||
def test_two_args_date_other(self):
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
self.factory.get(date.today(), object())
|
||||
|
||||
def test_two_args_str_str(self):
|
||||
|
||||
result = self.factory.get("2013-01-01", "YYYY-MM-DD")
|
||||
|
||||
assert result._datetime == datetime(2013, 1, 1, tzinfo=tz.tzutc())
|
||||
|
||||
def test_two_args_str_tzinfo(self):
|
||||
|
||||
result = self.factory.get("2013-01-01", tzinfo=tz.gettz("US/Pacific"))
|
||||
|
||||
assert_datetime_equality(
|
||||
result._datetime, datetime(2013, 1, 1, tzinfo=tz.gettz("US/Pacific"))
|
||||
)
|
||||
|
||||
def test_two_args_twitter_format(self):
|
||||
|
||||
# format returned by twitter API for created_at:
|
||||
twitter_date = "Fri Apr 08 21:08:54 +0000 2016"
|
||||
result = self.factory.get(twitter_date, "ddd MMM DD HH:mm:ss Z YYYY")
|
||||
|
||||
assert result._datetime == datetime(2016, 4, 8, 21, 8, 54, tzinfo=tz.tzutc())
|
||||
|
||||
def test_two_args_str_list(self):
|
||||
|
||||
result = self.factory.get("2013-01-01", ["MM/DD/YYYY", "YYYY-MM-DD"])
|
||||
|
||||
assert result._datetime == datetime(2013, 1, 1, tzinfo=tz.tzutc())
|
||||
|
||||
def test_two_args_unicode_unicode(self):
|
||||
|
||||
result = self.factory.get(u"2013-01-01", u"YYYY-MM-DD")
|
||||
|
||||
assert result._datetime == datetime(2013, 1, 1, tzinfo=tz.tzutc())
|
||||
|
||||
def test_two_args_other(self):
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
self.factory.get(object(), object())
|
||||
|
||||
def test_three_args_with_tzinfo(self):
|
||||
|
||||
timefmt = "YYYYMMDD"
|
||||
d = "20150514"
|
||||
|
||||
assert self.factory.get(d, timefmt, tzinfo=tz.tzlocal()) == datetime(
|
||||
2015, 5, 14, tzinfo=tz.tzlocal()
|
||||
)
|
||||
|
||||
def test_three_args(self):
|
||||
|
||||
assert self.factory.get(2013, 1, 1) == datetime(2013, 1, 1, tzinfo=tz.tzutc())
|
||||
|
||||
def test_full_kwargs(self):
|
||||
|
||||
assert (
|
||||
self.factory.get(
|
||||
year=2016,
|
||||
month=7,
|
||||
day=14,
|
||||
hour=7,
|
||||
minute=16,
|
||||
second=45,
|
||||
microsecond=631092,
|
||||
)
|
||||
== datetime(2016, 7, 14, 7, 16, 45, 631092, tzinfo=tz.tzutc())
|
||||
)
|
||||
|
||||
def test_three_kwargs(self):
|
||||
|
||||
assert self.factory.get(year=2016, month=7, day=14) == datetime(
|
||||
2016, 7, 14, 0, 0, tzinfo=tz.tzutc()
|
||||
)
|
||||
|
||||
def test_tzinfo_string_kwargs(self):
|
||||
result = self.factory.get("2019072807", "YYYYMMDDHH", tzinfo="UTC")
|
||||
assert result._datetime == datetime(2019, 7, 28, 7, 0, 0, 0, tzinfo=tz.tzutc())
|
||||
|
||||
def test_insufficient_kwargs(self):
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
self.factory.get(year=2016)
|
||||
|
||||
with pytest.raises(TypeError):
|
||||
self.factory.get(year=2016, month=7)
|
||||
|
||||
def test_locale(self):
|
||||
result = self.factory.get("2010", "YYYY", locale="ja")
|
||||
assert result._datetime == datetime(2010, 1, 1, 0, 0, 0, 0, tzinfo=tz.tzutc())
|
||||
|
||||
# regression test for issue #701
|
||||
result = self.factory.get(
|
||||
"Montag, 9. September 2019, 16:15-20:00", "dddd, D. MMMM YYYY", locale="de"
|
||||
)
|
||||
assert result._datetime == datetime(2019, 9, 9, 0, 0, 0, 0, tzinfo=tz.tzutc())
|
||||
|
||||
def test_locale_kwarg_only(self):
|
||||
res = self.factory.get(locale="ja")
|
||||
assert res.tzinfo == tz.tzutc()
|
||||
|
||||
def test_locale_with_tzinfo(self):
|
||||
res = self.factory.get(locale="ja", tzinfo=tz.gettz("Asia/Tokyo"))
|
||||
assert res.tzinfo == tz.gettz("Asia/Tokyo")
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("arrow_factory")
|
||||
class TestUtcNow:
|
||||
def test_utcnow(self):
|
||||
|
||||
assert_datetime_equality(
|
||||
self.factory.utcnow()._datetime,
|
||||
datetime.utcnow().replace(tzinfo=tz.tzutc()),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("arrow_factory")
|
||||
class TestNow:
|
||||
def test_no_tz(self):
|
||||
|
||||
assert_datetime_equality(self.factory.now(), datetime.now(tz.tzlocal()))
|
||||
|
||||
def test_tzinfo(self):
|
||||
|
||||
assert_datetime_equality(
|
||||
self.factory.now(tz.gettz("EST")), datetime.now(tz.gettz("EST"))
|
||||
)
|
||||
|
||||
def test_tz_str(self):
|
||||
|
||||
assert_datetime_equality(self.factory.now("EST"), datetime.now(tz.gettz("EST")))
|
||||
|
|
@ -1,282 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
import pytz
|
||||
from dateutil import tz as dateutil_tz
|
||||
|
||||
from arrow import (
|
||||
FORMAT_ATOM,
|
||||
FORMAT_COOKIE,
|
||||
FORMAT_RFC822,
|
||||
FORMAT_RFC850,
|
||||
FORMAT_RFC1036,
|
||||
FORMAT_RFC1123,
|
||||
FORMAT_RFC2822,
|
||||
FORMAT_RFC3339,
|
||||
FORMAT_RSS,
|
||||
FORMAT_W3C,
|
||||
)
|
||||
|
||||
from .utils import make_full_tz_list
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("arrow_formatter")
|
||||
class TestFormatterFormatToken:
|
||||
def test_format(self):
|
||||
|
||||
dt = datetime(2013, 2, 5, 12, 32, 51)
|
||||
|
||||
result = self.formatter.format(dt, "MM-DD-YYYY hh:mm:ss a")
|
||||
|
||||
assert result == "02-05-2013 12:32:51 pm"
|
||||
|
||||
def test_year(self):
|
||||
|
||||
dt = datetime(2013, 1, 1)
|
||||
assert self.formatter._format_token(dt, "YYYY") == "2013"
|
||||
assert self.formatter._format_token(dt, "YY") == "13"
|
||||
|
||||
def test_month(self):
|
||||
|
||||
dt = datetime(2013, 1, 1)
|
||||
assert self.formatter._format_token(dt, "MMMM") == "January"
|
||||
assert self.formatter._format_token(dt, "MMM") == "Jan"
|
||||
assert self.formatter._format_token(dt, "MM") == "01"
|
||||
assert self.formatter._format_token(dt, "M") == "1"
|
||||
|
||||
def test_day(self):
|
||||
|
||||
dt = datetime(2013, 2, 1)
|
||||
assert self.formatter._format_token(dt, "DDDD") == "032"
|
||||
assert self.formatter._format_token(dt, "DDD") == "32"
|
||||
assert self.formatter._format_token(dt, "DD") == "01"
|
||||
assert self.formatter._format_token(dt, "D") == "1"
|
||||
assert self.formatter._format_token(dt, "Do") == "1st"
|
||||
|
||||
assert self.formatter._format_token(dt, "dddd") == "Friday"
|
||||
assert self.formatter._format_token(dt, "ddd") == "Fri"
|
||||
assert self.formatter._format_token(dt, "d") == "5"
|
||||
|
||||
def test_hour(self):
|
||||
|
||||
dt = datetime(2013, 1, 1, 2)
|
||||
assert self.formatter._format_token(dt, "HH") == "02"
|
||||
assert self.formatter._format_token(dt, "H") == "2"
|
||||
|
||||
dt = datetime(2013, 1, 1, 13)
|
||||
assert self.formatter._format_token(dt, "HH") == "13"
|
||||
assert self.formatter._format_token(dt, "H") == "13"
|
||||
|
||||
dt = datetime(2013, 1, 1, 2)
|
||||
assert self.formatter._format_token(dt, "hh") == "02"
|
||||
assert self.formatter._format_token(dt, "h") == "2"
|
||||
|
||||
dt = datetime(2013, 1, 1, 13)
|
||||
assert self.formatter._format_token(dt, "hh") == "01"
|
||||
assert self.formatter._format_token(dt, "h") == "1"
|
||||
|
||||
# test that 12-hour time converts to '12' at midnight
|
||||
dt = datetime(2013, 1, 1, 0)
|
||||
assert self.formatter._format_token(dt, "hh") == "12"
|
||||
assert self.formatter._format_token(dt, "h") == "12"
|
||||
|
||||
def test_minute(self):
|
||||
|
||||
dt = datetime(2013, 1, 1, 0, 1)
|
||||
assert self.formatter._format_token(dt, "mm") == "01"
|
||||
assert self.formatter._format_token(dt, "m") == "1"
|
||||
|
||||
def test_second(self):
|
||||
|
||||
dt = datetime(2013, 1, 1, 0, 0, 1)
|
||||
assert self.formatter._format_token(dt, "ss") == "01"
|
||||
assert self.formatter._format_token(dt, "s") == "1"
|
||||
|
||||
def test_sub_second(self):
|
||||
|
||||
dt = datetime(2013, 1, 1, 0, 0, 0, 123456)
|
||||
assert self.formatter._format_token(dt, "SSSSSS") == "123456"
|
||||
assert self.formatter._format_token(dt, "SSSSS") == "12345"
|
||||
assert self.formatter._format_token(dt, "SSSS") == "1234"
|
||||
assert self.formatter._format_token(dt, "SSS") == "123"
|
||||
assert self.formatter._format_token(dt, "SS") == "12"
|
||||
assert self.formatter._format_token(dt, "S") == "1"
|
||||
|
||||
dt = datetime(2013, 1, 1, 0, 0, 0, 2000)
|
||||
assert self.formatter._format_token(dt, "SSSSSS") == "002000"
|
||||
assert self.formatter._format_token(dt, "SSSSS") == "00200"
|
||||
assert self.formatter._format_token(dt, "SSSS") == "0020"
|
||||
assert self.formatter._format_token(dt, "SSS") == "002"
|
||||
assert self.formatter._format_token(dt, "SS") == "00"
|
||||
assert self.formatter._format_token(dt, "S") == "0"
|
||||
|
||||
def test_timestamp(self):
|
||||
|
||||
timestamp = 1588437009.8952794
|
||||
dt = datetime.utcfromtimestamp(timestamp)
|
||||
expected = str(int(timestamp))
|
||||
assert self.formatter._format_token(dt, "X") == expected
|
||||
|
||||
# Must round because time.time() may return a float with greater
|
||||
# than 6 digits of precision
|
||||
expected = str(int(timestamp * 1000000))
|
||||
assert self.formatter._format_token(dt, "x") == expected
|
||||
|
||||
def test_timezone(self):
|
||||
|
||||
dt = datetime.utcnow().replace(tzinfo=dateutil_tz.gettz("US/Pacific"))
|
||||
|
||||
result = self.formatter._format_token(dt, "ZZ")
|
||||
assert result == "-07:00" or result == "-08:00"
|
||||
|
||||
result = self.formatter._format_token(dt, "Z")
|
||||
assert result == "-0700" or result == "-0800"
|
||||
|
||||
@pytest.mark.parametrize("full_tz_name", make_full_tz_list())
|
||||
def test_timezone_formatter(self, full_tz_name):
|
||||
|
||||
# This test will fail if we use "now" as date as soon as we change from/to DST
|
||||
dt = datetime(1986, 2, 14, tzinfo=pytz.timezone("UTC")).replace(
|
||||
tzinfo=dateutil_tz.gettz(full_tz_name)
|
||||
)
|
||||
abbreviation = dt.tzname()
|
||||
|
||||
result = self.formatter._format_token(dt, "ZZZ")
|
||||
assert result == abbreviation
|
||||
|
||||
def test_am_pm(self):
|
||||
|
||||
dt = datetime(2012, 1, 1, 11)
|
||||
assert self.formatter._format_token(dt, "a") == "am"
|
||||
assert self.formatter._format_token(dt, "A") == "AM"
|
||||
|
||||
dt = datetime(2012, 1, 1, 13)
|
||||
assert self.formatter._format_token(dt, "a") == "pm"
|
||||
assert self.formatter._format_token(dt, "A") == "PM"
|
||||
|
||||
def test_week(self):
|
||||
dt = datetime(2017, 5, 19)
|
||||
assert self.formatter._format_token(dt, "W") == "2017-W20-5"
|
||||
|
||||
# make sure week is zero padded when needed
|
||||
dt_early = datetime(2011, 1, 20)
|
||||
assert self.formatter._format_token(dt_early, "W") == "2011-W03-4"
|
||||
|
||||
def test_nonsense(self):
|
||||
dt = datetime(2012, 1, 1, 11)
|
||||
assert self.formatter._format_token(dt, None) is None
|
||||
assert self.formatter._format_token(dt, "NONSENSE") is None
|
||||
|
||||
def test_escape(self):
|
||||
|
||||
assert (
|
||||
self.formatter.format(
|
||||
datetime(2015, 12, 10, 17, 9), "MMMM D, YYYY [at] h:mma"
|
||||
)
|
||||
== "December 10, 2015 at 5:09pm"
|
||||
)
|
||||
|
||||
assert (
|
||||
self.formatter.format(
|
||||
datetime(2015, 12, 10, 17, 9), "[MMMM] M D, YYYY [at] h:mma"
|
||||
)
|
||||
== "MMMM 12 10, 2015 at 5:09pm"
|
||||
)
|
||||
|
||||
assert (
|
||||
self.formatter.format(
|
||||
datetime(1990, 11, 25),
|
||||
"[It happened on] MMMM Do [in the year] YYYY [a long time ago]",
|
||||
)
|
||||
== "It happened on November 25th in the year 1990 a long time ago"
|
||||
)
|
||||
|
||||
assert (
|
||||
self.formatter.format(
|
||||
datetime(1990, 11, 25),
|
||||
"[It happened on] MMMM Do [in the][ year] YYYY [a long time ago]",
|
||||
)
|
||||
== "It happened on November 25th in the year 1990 a long time ago"
|
||||
)
|
||||
|
||||
assert (
|
||||
self.formatter.format(
|
||||
datetime(1, 1, 1), "[I'm][ entirely][ escaped,][ weee!]"
|
||||
)
|
||||
== "I'm entirely escaped, weee!"
|
||||
)
|
||||
|
||||
# Special RegEx characters
|
||||
assert (
|
||||
self.formatter.format(
|
||||
datetime(2017, 12, 31, 2, 0), "MMM DD, YYYY |^${}().*+?<>-& h:mm A"
|
||||
)
|
||||
== "Dec 31, 2017 |^${}().*+?<>-& 2:00 AM"
|
||||
)
|
||||
|
||||
# Escaping is atomic: brackets inside brackets are treated literally
|
||||
assert self.formatter.format(datetime(1, 1, 1), "[[[ ]]") == "[[ ]"
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("arrow_formatter", "time_1975_12_25")
|
||||
class TestFormatterBuiltinFormats:
|
||||
def test_atom(self):
|
||||
assert (
|
||||
self.formatter.format(self.datetime, FORMAT_ATOM)
|
||||
== "1975-12-25 14:15:16-05:00"
|
||||
)
|
||||
|
||||
def test_cookie(self):
|
||||
assert (
|
||||
self.formatter.format(self.datetime, FORMAT_COOKIE)
|
||||
== "Thursday, 25-Dec-1975 14:15:16 EST"
|
||||
)
|
||||
|
||||
def test_rfc_822(self):
|
||||
assert (
|
||||
self.formatter.format(self.datetime, FORMAT_RFC822)
|
||||
== "Thu, 25 Dec 75 14:15:16 -0500"
|
||||
)
|
||||
|
||||
def test_rfc_850(self):
|
||||
assert (
|
||||
self.formatter.format(self.datetime, FORMAT_RFC850)
|
||||
== "Thursday, 25-Dec-75 14:15:16 EST"
|
||||
)
|
||||
|
||||
def test_rfc_1036(self):
|
||||
assert (
|
||||
self.formatter.format(self.datetime, FORMAT_RFC1036)
|
||||
== "Thu, 25 Dec 75 14:15:16 -0500"
|
||||
)
|
||||
|
||||
def test_rfc_1123(self):
|
||||
assert (
|
||||
self.formatter.format(self.datetime, FORMAT_RFC1123)
|
||||
== "Thu, 25 Dec 1975 14:15:16 -0500"
|
||||
)
|
||||
|
||||
def test_rfc_2822(self):
|
||||
assert (
|
||||
self.formatter.format(self.datetime, FORMAT_RFC2822)
|
||||
== "Thu, 25 Dec 1975 14:15:16 -0500"
|
||||
)
|
||||
|
||||
def test_rfc3339(self):
|
||||
assert (
|
||||
self.formatter.format(self.datetime, FORMAT_RFC3339)
|
||||
== "1975-12-25 14:15:16-05:00"
|
||||
)
|
||||
|
||||
def test_rss(self):
|
||||
assert (
|
||||
self.formatter.format(self.datetime, FORMAT_RSS)
|
||||
== "Thu, 25 Dec 1975 14:15:16 -0500"
|
||||
)
|
||||
|
||||
def test_w3c(self):
|
||||
assert (
|
||||
self.formatter.format(self.datetime, FORMAT_W3C)
|
||||
== "1975-12-25 14:15:16-05:00"
|
||||
)
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,81 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from arrow import util
|
||||
|
||||
|
||||
class TestUtil:
|
||||
def test_next_weekday(self):
|
||||
# Get first Monday after epoch
|
||||
assert util.next_weekday(datetime(1970, 1, 1), 0) == datetime(1970, 1, 5)
|
||||
|
||||
# Get first Tuesday after epoch
|
||||
assert util.next_weekday(datetime(1970, 1, 1), 1) == datetime(1970, 1, 6)
|
||||
|
||||
# Get first Wednesday after epoch
|
||||
assert util.next_weekday(datetime(1970, 1, 1), 2) == datetime(1970, 1, 7)
|
||||
|
||||
# Get first Thursday after epoch
|
||||
assert util.next_weekday(datetime(1970, 1, 1), 3) == datetime(1970, 1, 1)
|
||||
|
||||
# Get first Friday after epoch
|
||||
assert util.next_weekday(datetime(1970, 1, 1), 4) == datetime(1970, 1, 2)
|
||||
|
||||
# Get first Saturday after epoch
|
||||
assert util.next_weekday(datetime(1970, 1, 1), 5) == datetime(1970, 1, 3)
|
||||
|
||||
# Get first Sunday after epoch
|
||||
assert util.next_weekday(datetime(1970, 1, 1), 6) == datetime(1970, 1, 4)
|
||||
|
||||
# Weekdays are 0-indexed
|
||||
with pytest.raises(ValueError):
|
||||
util.next_weekday(datetime(1970, 1, 1), 7)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
util.next_weekday(datetime(1970, 1, 1), -1)
|
||||
|
||||
def test_total_seconds(self):
|
||||
td = datetime(2019, 1, 1) - datetime(2018, 1, 1)
|
||||
assert util.total_seconds(td) == td.total_seconds()
|
||||
|
||||
def test_is_timestamp(self):
|
||||
timestamp_float = time.time()
|
||||
timestamp_int = int(timestamp_float)
|
||||
|
||||
assert util.is_timestamp(timestamp_int)
|
||||
assert util.is_timestamp(timestamp_float)
|
||||
assert util.is_timestamp(str(timestamp_int))
|
||||
assert util.is_timestamp(str(timestamp_float))
|
||||
|
||||
assert not util.is_timestamp(True)
|
||||
assert not util.is_timestamp(False)
|
||||
|
||||
class InvalidTimestamp:
|
||||
pass
|
||||
|
||||
assert not util.is_timestamp(InvalidTimestamp())
|
||||
|
||||
full_datetime = "2019-06-23T13:12:42"
|
||||
assert not util.is_timestamp(full_datetime)
|
||||
|
||||
def test_normalize_timestamp(self):
|
||||
timestamp = 1591161115.194556
|
||||
millisecond_timestamp = 1591161115194
|
||||
microsecond_timestamp = 1591161115194556
|
||||
|
||||
assert util.normalize_timestamp(timestamp) == timestamp
|
||||
assert util.normalize_timestamp(millisecond_timestamp) == 1591161115.194
|
||||
assert util.normalize_timestamp(microsecond_timestamp) == 1591161115.194556
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
util.normalize_timestamp(3e17)
|
||||
|
||||
def test_iso_gregorian(self):
|
||||
with pytest.raises(ValueError):
|
||||
util.iso_to_gregorian(2013, 0, 5)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
util.iso_to_gregorian(2013, 8, 0)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import pytz
|
||||
from dateutil.zoneinfo import get_zonefile_instance
|
||||
|
||||
from arrow import util
|
||||
|
||||
|
||||
def make_full_tz_list():
|
||||
dateutil_zones = set(get_zonefile_instance().zones)
|
||||
pytz_zones = set(pytz.all_timezones)
|
||||
return dateutil_zones.union(pytz_zones)
|
||||
|
||||
|
||||
def assert_datetime_equality(dt1, dt2, within=10):
|
||||
assert dt1.tzinfo == dt2.tzinfo
|
||||
assert abs(util.total_seconds(dt1 - dt2)) < within
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
[tox]
|
||||
minversion = 3.18.0
|
||||
envlist = py{py3,27,35,36,37,38,39},lint,docs
|
||||
skip_missing_interpreters = true
|
||||
|
||||
[gh-actions]
|
||||
python =
|
||||
pypy3: pypy3
|
||||
2.7: py27
|
||||
3.5: py35
|
||||
3.6: py36
|
||||
3.7: py37
|
||||
3.8: py38
|
||||
3.9: py39
|
||||
|
||||
[testenv]
|
||||
deps = -rrequirements.txt
|
||||
allowlist_externals = pytest
|
||||
commands = pytest
|
||||
|
||||
[testenv:lint]
|
||||
basepython = python3
|
||||
skip_install = true
|
||||
deps = pre-commit
|
||||
commands =
|
||||
pre-commit install
|
||||
pre-commit run --all-files --show-diff-on-failure
|
||||
|
||||
[testenv:docs]
|
||||
basepython = python3
|
||||
skip_install = true
|
||||
changedir = docs
|
||||
deps =
|
||||
doc8
|
||||
sphinx
|
||||
python-dateutil
|
||||
allowlist_externals = make
|
||||
commands =
|
||||
doc8 index.rst ../README.rst --extension .rst --ignore D001
|
||||
make html SPHINXOPTS="-W --keep-going"
|
||||
|
||||
[pytest]
|
||||
addopts = -v --cov-branch --cov=arrow --cov-fail-under=100 --cov-report=term-missing --cov-report=xml
|
||||
testpaths = tests
|
||||
|
||||
[isort]
|
||||
line_length = 88
|
||||
multi_line_output = 3
|
||||
include_trailing_comma = true
|
||||
|
||||
[flake8]
|
||||
per-file-ignores = arrow/__init__.py:F401
|
||||
ignore = E203,E501,W503
|
||||
|
|
@ -40,6 +40,7 @@ clique = "1.6.*"
|
|||
Click = "^7"
|
||||
dnspython = "^2.1.0"
|
||||
ftrack-python-api = "^2.3.3"
|
||||
arrow = "^0.17"
|
||||
shotgun_api3 = {git = "https://github.com/shotgunsoftware/python-api.git", rev = "v3.3.3"}
|
||||
gazu = "^0.9.3"
|
||||
google-api-python-client = "^1.12.8" # sync server google support (should be separate?)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue