mirror of
https://github.com/OpenVoiceOS/OpenVoiceOS
synced 2025-03-25 16:00:27 +01:00
[WIP] Pushed for backup.
... Do not build this as of yet ...
This commit is contained in:
parent
5c7af8b058
commit
c6460b9307
@ -175,6 +175,7 @@ menu "Additional external python modules"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-gpsdclient/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-gtts/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-gtts_token/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-h3/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-hijri-converter/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-holidays/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/python-humanhash3/Config.in"
|
||||
@ -395,8 +396,8 @@ menu "Skills"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/mycroft-skill-parrot/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/skill-ovos-personal/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/skill-ovos-weather/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/skill-ovos-wikipedia/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/skill-ovos-wolfie/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/mycroft-skill-wikipedia-for-humans/Config.in"
|
||||
source "$BR2_EXTERNAL_OPENVOICEOS_PATH/package/skill-youtube-music/Config.in"
|
||||
endmenu
|
||||
endmenu
|
||||
|
@ -241,6 +241,7 @@ BR2_PACKAGE_SOX=y
|
||||
BR2_PACKAGE_SQUEEZELITE=y
|
||||
BR2_PACKAGE_SQUEEZELITE_RESAMPLE=y
|
||||
BR2_PACKAGE_VLC=y
|
||||
BR2_PACKAGE_VORBIS_TOOLS=y
|
||||
BR2_PACKAGE_GZIP=y
|
||||
BR2_PACKAGE_LZIP=y
|
||||
BR2_PACKAGE_LZOP=y
|
||||
@ -321,6 +322,7 @@ BR2_PACKAGE_PYTHON3_CODECSCJK=y
|
||||
BR2_PACKAGE_PYTHON3_CURSES=y
|
||||
BR2_PACKAGE_PYTHON3_DECIMAL=y
|
||||
BR2_PACKAGE_PYTHON3_OSSAUDIODEV=y
|
||||
BR2_PACKAGE_PYTHON3_READLINE=y
|
||||
BR2_PACKAGE_PYTHON3_SQLITE=y
|
||||
BR2_PACKAGE_PYTHON3_XZ=y
|
||||
BR2_PACKAGE_PYTHON_ALSAAUDIO=y
|
||||
@ -328,7 +330,6 @@ BR2_PACKAGE_PYTHON_ARROW=y
|
||||
BR2_PACKAGE_PYTHON_AUTOBAHN=y
|
||||
BR2_PACKAGE_PYTHON_CHERRYPY=y
|
||||
BR2_PACKAGE_PYTHON_COLORAMA=y
|
||||
BR2_PACKAGE_PYTHON_CONFIGSHELL_FB=y
|
||||
BR2_PACKAGE_PYTHON_DAEMONIZE=y
|
||||
BR2_PACKAGE_PYTHON_DBUS_NEXT=y
|
||||
BR2_PACKAGE_PYTHON_FILELOCK=y
|
||||
@ -350,12 +351,15 @@ BR2_PACKAGE_PYTHON_OAUTHLIB=y
|
||||
BR2_PACKAGE_PYTHON_PACKAGING=y
|
||||
BR2_PACKAGE_PYTHON_PAHO_MQTT=y
|
||||
BR2_PACKAGE_PYTHON_PEXPECT=y
|
||||
BR2_PACKAGE_PYTHON_PILLOW=y
|
||||
BR2_PACKAGE_PYTHON_PIP=y
|
||||
BR2_PACKAGE_PYTHON_PLY=y
|
||||
BR2_PACKAGE_PYTHON_PSUTIL=y
|
||||
BR2_PACKAGE_PYTHON_PYGMENTS=y
|
||||
BR2_PACKAGE_PYTHON_PYJWT=y
|
||||
BR2_PACKAGE_PYTHON_PYUDEV=y
|
||||
BR2_PACKAGE_PYTHON_QRCODE=y
|
||||
BR2_PACKAGE_PYTHON_QRCODE_SVG=y
|
||||
BR2_PACKAGE_PYTHON_QRCODE_PIL=y
|
||||
BR2_PACKAGE_PYTHON_RPI_WS281X=y
|
||||
BR2_PACKAGE_PYTHON_RUAMEL_YAML=y
|
||||
BR2_PACKAGE_PYTHON_SDNOTIFY=y
|
||||
@ -369,13 +373,13 @@ BR2_PACKAGE_PYTHON_TEXTTABLE=y
|
||||
BR2_PACKAGE_PYTHON_TWISTED=y
|
||||
BR2_PACKAGE_PYTHON_TWISTED_HTTP2=y
|
||||
BR2_PACKAGE_PYTHON_TWISTED_TLS=y
|
||||
BR2_PACKAGE_PYTHON_URWID=y
|
||||
BR2_PACKAGE_PYTHON_VALIDATORS=y
|
||||
BR2_PACKAGE_PYTHON_WATCHDOG=y
|
||||
BR2_PACKAGE_PYTHON_WEBSOCKET_CLIENT=y
|
||||
BR2_PACKAGE_PYTHON_ZC_LOCKFILE=y
|
||||
BR2_PACKAGE_ALSA_LIB_PYTHON=y
|
||||
BR2_PACKAGE_ALSA_PLUGINS=y
|
||||
BR2_PACKAGE_LIBAO=y
|
||||
BR2_PACKAGE_LIBSAMPLERATE=y
|
||||
BR2_PACKAGE_OPUS_FIXED_POINT=y
|
||||
BR2_PACKAGE_OPUSFILE=y
|
||||
@ -492,7 +496,6 @@ BR2_PACKAGE_SYSTEMD_HIBERNATE=y
|
||||
BR2_PACKAGE_SYSTEMD_LOCALED=y
|
||||
BR2_PACKAGE_SYSTEMD_LOGIND=y
|
||||
# BR2_PACKAGE_SYSTEMD_NETWORKD is not set
|
||||
BR2_PACKAGE_SYSTEMD_OOMD=y
|
||||
BR2_PACKAGE_SYSTEMD_POLKIT=y
|
||||
BR2_PACKAGE_SYSTEMD_RANDOMSEED=y
|
||||
BR2_PACKAGE_SYSTEMD_REPART=y
|
||||
@ -550,7 +553,8 @@ BR2_PACKAGE_TENSORFLOW_LITE=y
|
||||
BR2_PACKAGE_WHISPERCPP=y
|
||||
BR2_PACKAGE_PYTHON_ADAPT_PARSER=y
|
||||
BR2_PACKAGE_PYTHON_ASTRAL=y
|
||||
BR2_PACKAGE_PYTHON_AUDIO_METADATA=y
|
||||
BR2_PACKAGE_PYTHON_AUTOCOMMAND=y
|
||||
BR2_PACKAGE_PYTHON_BITSTRUCT=y
|
||||
BR2_PACKAGE_PYTHON_BOARD=y
|
||||
BR2_PACKAGE_PYTHON_CLICK_DEFAULT_GROUP=y
|
||||
BR2_PACKAGE_PYTHON_COMBO_LOCK=y
|
||||
@ -560,20 +564,30 @@ BR2_PACKAGE_PYTHON_DATACLASSES=y
|
||||
BR2_PACKAGE_PYTHON_DEPRECATED=y
|
||||
BR2_PACKAGE_PYTHON_FEEDPARSER=y
|
||||
BR2_PACKAGE_PYTHON_FLASK_FONTAWESOME=y
|
||||
BR2_PACKAGE_PYTHON_FLASK_MAIL=y
|
||||
BR2_PACKAGE_PYTHON_FLASK_SIMPLELOGIN=y
|
||||
BR2_PACKAGE_PYTHON_FLASK_SOCKETIO=y
|
||||
BR2_PACKAGE_PYTHON_GEOCODER=y
|
||||
BR2_PACKAGE_PYTHON_GEOIP_GEOLITE2=y
|
||||
BR2_PACKAGE_PYTHON_GOOGLE_API_PYTHON_CLIENT=y
|
||||
BR2_PACKAGE_PYTHON_GOOGLE_TRANS_NEW=y
|
||||
BR2_PACKAGE_PYTHON_GPSDCLIENT=y
|
||||
BR2_PACKAGE_PYTHON_GTTS=y
|
||||
BR2_PACKAGE_PYTHON_H3=y
|
||||
BR2_PACKAGE_PYTHON_HIJRI_CONVERTER=y
|
||||
BR2_PACKAGE_PYTHON_HOLIDAYS=y
|
||||
BR2_PACKAGE_PYTHON_HUMANHASH3=y
|
||||
BR2_PACKAGE_PYTHON_IMPORTLIB_METADATA=y
|
||||
BR2_PACKAGE_PYTHON_JARACO_COLLECTIONS=y
|
||||
BR2_PACKAGE_PYTHON_JARACO_CONTEXT=y
|
||||
BR2_PACKAGE_PYTHON_JARACO_TEXT=y
|
||||
BR2_PACKAGE_PYTHON_JSON_DATABASE=y
|
||||
BR2_PACKAGE_PYTHON_KTHREAD=y
|
||||
BR2_PACKAGE_PYTHON_LANGCODES=y
|
||||
BR2_PACKAGE_PYTHON_LAZY=y
|
||||
BR2_PACKAGE_PYTHON_LEVENSHTEIN=y
|
||||
BR2_PACKAGE_PYTHON_MARKDOWN_IT_PY=y
|
||||
BR2_PACKAGE_PYTHON_MDURL=y
|
||||
BR2_PACKAGE_PYTHON_MEMORY_TEMPFILE=y
|
||||
BR2_PACKAGE_PYTHON_MOCK_MSM=y
|
||||
BR2_PACKAGE_PYTHON_MSM=y
|
||||
@ -585,6 +599,8 @@ BR2_PACKAGE_PYTHON_NEON_SOLVER_PLUGIN_WOLFRAM_ALPHA=y
|
||||
BR2_PACKAGE_PYTHON_NEON_SOLVERS=y
|
||||
BR2_PACKAGE_PYTHON_NEON_TRANSFORMERS=y
|
||||
BR2_PACKAGE_PYTHON_NEON_UTTERANCE_PLUGIN_RAKE=y
|
||||
BR2_PACKAGE_PYTHON_NESTED_LOOKUP=y
|
||||
BR2_PACKAGE_PYTHON_NLTK=y
|
||||
BR2_PACKAGE_PYTHON_OAUTH2CLIENT=y
|
||||
BR2_PACKAGE_PYTHON_OLEFILE=y
|
||||
BR2_PACKAGE_PYTHON_PADACIOSO=y
|
||||
@ -612,19 +628,25 @@ BR2_PACKAGE_PYTHON_RAKEKEYWORDS=y
|
||||
BR2_PACKAGE_PYTHON_RAPIDFUZZ=y
|
||||
BR2_PACKAGE_PYTHON_REQUESTS_FUTURES=y
|
||||
BR2_PACKAGE_PYTHON_REVERSE_GEOCODER=y
|
||||
BR2_PACKAGE_PYTHON_RICH=y
|
||||
BR2_PACKAGE_PYTHON_RICH_CLICK=y
|
||||
BR2_PACKAGE_PYTHON_SGMLLIB3K=y
|
||||
BR2_PACKAGE_PYTHON_SMBUS2=y
|
||||
BR2_PACKAGE_PYTHON_SMMAP=y
|
||||
BR2_PACKAGE_PYTHON_SONOPY=y
|
||||
BR2_PACKAGE_PYTHON_SOURCE=y
|
||||
BR2_PACKAGE_PYTHON_SPEECH2TEXT=y
|
||||
BR2_PACKAGE_PYTHON_SQLALCHEMY_JSON=y
|
||||
BR2_PACKAGE_PYTHON_SYSV_IPC=y
|
||||
BR2_PACKAGE_PYTHON_TAILHEAD=y
|
||||
BR2_PACKAGE_PYTHON_TBM_UTILS=y
|
||||
BR2_PACKAGE_PYTHON_TFLIT=y
|
||||
BR2_PACKAGE_PYTHON_TUTUBO=y
|
||||
BR2_PACKAGE_PYTHON_TZLOCAL=y
|
||||
BR2_PACKAGE_PYTHON_URL_NORMALIZE=y
|
||||
BR2_PACKAGE_PYTHON_VLC=y
|
||||
BR2_PACKAGE_PYTHON_VOSK_API=y
|
||||
BR2_PACKAGE_PYTHON_WEBCOLORS=y
|
||||
BR2_PACKAGE_PYTHON_WEBRTCVAD=y
|
||||
BR2_PACKAGE_PYTHON_WHEEL=y
|
||||
BR2_PACKAGE_PYTHON_WIKIPEDIA_FOR_HUMANS=y
|
||||
@ -633,6 +655,7 @@ BR2_PACKAGE_PYTHON_YAGMAIL=y
|
||||
BR2_PACKAGE_PYTHON_YOUTUBE_DL=y
|
||||
BR2_PACKAGE_PYTHON_YOUTUBE_SEARCHER=y
|
||||
BR2_PACKAGE_PYTHON_YT_DLP=y
|
||||
BR2_PACKAGE_PYTHON_ZIPP=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_AUDIO=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_CLASSIFIERS=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_CLI_CLIENT=y
|
||||
@ -643,12 +666,9 @@ BR2_PACKAGE_PYTHON_OVOS_LISTENER=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_MESSAGEBUS=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_AUDIO_PLUGIN_SIMPLE=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_BACKEND_CLIENT=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_BACKEND_MANAGER=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_BUS_CLIENT=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_CONFIG_ASSISTANT=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_LINGUA_FRANCA=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_LOCAL_BACKEND=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_NOTIFICATIONS_SERVICE=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_OCP_AUDIO_PLUGIN=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_OCP_BANDCAMP_PLUGIN=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_OCP_DEEZER_PLUGIN=y
|
||||
@ -659,17 +679,14 @@ BR2_PACKAGE_PYTHON_OVOS_OCP_RSS_PLUGIN=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_OCP_YOUTUBE_PLUGIN=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL_PLUGIN_ALSA=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL_PLUGIN_BALENA_WIFI=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL_PLUGIN_CONFIGURATION_PROVIDER=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL_PLUGIN_CONNECTIVITY_EVENTS=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL_PLUGIN_DASHBOARD=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL_PLUGIN_HOMEASSISTANT=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL_PLUGIN_IPGEO=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL_PLUGIN_NETWORK_MANAGER=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL_PLUGIN_OAUTH=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_PHAL_PLUGIN_SYSTEM=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_SKILL_INSTALLER=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_SKILL_MANAGER=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_STT_HTTP_SERVER=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_STT_PLUGIN_CHROMIUM=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_STT_PLUGIN_SELENE=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_STT_PLUGIN_SERVER=y
|
||||
@ -680,7 +697,6 @@ BR2_PACKAGE_PYTHON_OVOS_TTS_PLUGIN_MIMIC=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_TTS_PLUGIN_MIMIC2=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_TTS_PLUGIN_MIMIC3_SERVER=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_TTS_PLUGIN_PICO=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_TTS_SERVER=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_TTS_SERVER_PLUGIN=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_UTILS=y
|
||||
BR2_PACKAGE_PYTHON_OVOS_VAD_PLUGIN_WEBRTCVAD=y
|
||||
@ -699,10 +715,10 @@ BR2_PACKAGE_SKILL_OVOS_NAPTIME=y
|
||||
BR2_PACKAGE_SKILL_OVOS_NEWS=y
|
||||
BR2_PACKAGE_SKILL_OVOS_NOTES=y
|
||||
BR2_PACKAGE_SKILL_OVOS_SETTINGS=y
|
||||
BR2_PACKAGE_SKILL_OVOS_SETUP=y
|
||||
BR2_PACKAGE_SKILL_OVOS_STOP=y
|
||||
BR2_PACKAGE_SKILL_OVOS_VOLUME=y
|
||||
BR2_PACKAGE_SKILL_OVOS_PERSONAL=y
|
||||
BR2_PACKAGE_SKILL_OVOS_WEATHER=y
|
||||
BR2_PACKAGE_SKILL_OVOS_WIKIPEDIA=y
|
||||
BR2_PACKAGE_SKILL_OVOS_WOLFIE=y
|
||||
BR2_PACKAGE_SKILL_YOUTUBE_MUSIC=y
|
||||
|
@ -1,5 +1,4 @@
|
||||
# md5, sha256 from https://pypi.org/pypi/flask-simplelogin/json
|
||||
md5 9fae54f8fd1414e52e4a6755499f047a flask_simplelogin-0.1.0.tar.gz
|
||||
sha256 a1fb73b7fb37001093d76efc582b085eedc4fca8727a64082ae3f6421411c649 flask_simplelogin-0.1.0.tar.gz
|
||||
# sha256 from https://pypi.org/pypi/flask-simplelogin/json
|
||||
sha256 a99b7ded371aa0f5ecf3271c160e3fd52653abd5d879acf9ae621c4825345a8f flask_simplelogin-0.1.2.tar.gz
|
||||
# Locally computed sha256 checksums
|
||||
sha256 af616823fd3518096256d0ba51fa7078d2be93065e53854e41724ae2f1af71d8 LICENSE
|
||||
|
@ -4,9 +4,9 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
PYTHON_FLASK_SIMPLELOGIN_VERSION = 0.1.0
|
||||
PYTHON_FLASK_SIMPLELOGIN_VERSION = 0.1.2
|
||||
PYTHON_FLASK_SIMPLELOGIN_SOURCE = flask_simplelogin-$(PYTHON_FLASK_SIMPLELOGIN_VERSION).tar.gz
|
||||
PYTHON_FLASK_SIMPLELOGIN_SITE = https://files.pythonhosted.org/packages/34/18/660cd00c6153dddefea29ae6a8274ab2a8bbb6b124fe4d23db944a6a079c
|
||||
PYTHON_FLASK_SIMPLELOGIN_SITE = https://files.pythonhosted.org/packages/e3/9b/942c42c1122e502e0bea52ac96230591df3bf58369de11ad3ad2e0c448d3
|
||||
PYTHON_FLASK_SIMPLELOGIN_SETUP_TYPE = setuptools
|
||||
PYTHON_FLASK_SIMPLELOGIN_LICENSE = MIT
|
||||
PYTHON_FLASK_SIMPLELOGIN_LICENSE_FILES = LICENSE
|
||||
|
6
buildroot-external/package/python-h3/Config.in
Normal file
6
buildroot-external/package/python-h3/Config.in
Normal file
@ -0,0 +1,6 @@
|
||||
config BR2_PACKAGE_PYTHON_H3
|
||||
bool "python-h3"
|
||||
help
|
||||
Uber's H3 Hexagonal Hierarchical Geospatial Indexing System in Python
|
||||
|
||||
https://github.com/uber/h3-py
|
2
buildroot-external/package/python-h3/python-h3.hash
Normal file
2
buildroot-external/package/python-h3/python-h3.hash
Normal file
@ -0,0 +1,2 @@
|
||||
# sha256 from https://pypi.org/pypi/h3/json
|
||||
sha256 9bbd3dbac99532fa521d7d2e288ff55877bea3223b070f659ed7b5f8f1f213eb h3-3.7.6.tar.gz
|
21
buildroot-external/package/python-h3/python-h3.mk
Normal file
21
buildroot-external/package/python-h3/python-h3.mk
Normal file
@ -0,0 +1,21 @@
|
||||
################################################################################
|
||||
#
|
||||
# python-h3
|
||||
#
|
||||
################################################################################
|
||||
|
||||
PYTHON_H3_VERSION = 3.7.6
|
||||
PYTHON_H3_SOURCE = h3-$(PYTHON_H3_VERSION).tar.gz
|
||||
PYTHON_H3_SITE = https://files.pythonhosted.org/packages/0e/92/30070479f7c41d66dc5f0ac44298eaedf4a7dad722348dac82d6dcc7ddd8
|
||||
PYTHON_H3_SETUP_TYPE = setuptools
|
||||
PYTHON_H3_LICENSE = MIT
|
||||
PYTHON_H3_LICENSE_FILES = LICENSE
|
||||
PYTHON_H3_DEPENDENCIES = host-python-scikit-build host-python-wheel host-python-distro
|
||||
PYTHON_H3_BUILD_OPTS = -DPython3_INCLUDE_DIR:PATH=$(STAGING_DIR)/usr/include/python$(PYTHON3_VERSION_MAJOR) \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=$(STAGING_DIR)/usr/include/python$(PYTHON3_VERSION_MAJOR) \
|
||||
-DBUILD_SHARED_LIBS=ON
|
||||
PYTHON_H3_INSTALL_TARGET_OPTS = -DPython3_INCLUDE_DIR:PATH=$(STAGING_DIR)/usr/include/python$(PYTHON3_VERSION_MAJOR) \
|
||||
-DPYTHON_INCLUDE_DIR:PATH=$(STAGING_DIR)/usr/include/python$(PYTHON3_VERSION_MAJOR) \
|
||||
-DBUILD_SHARED_LIBS=ON
|
||||
|
||||
$(eval $(python-package))
|
@ -1 +1 @@
|
||||
sha256 1511291c17d5747ce78468f5e05c6e6fa4c41dd68ee5e08507047c54cce5138c python-ovos-lingua-franca-0c4ead9b3ad396fc68a5b5c6465678b567c6c01f.tar.gz
|
||||
sha256 c301b8624d87cac5a6e44b6d211771347f94d4f4a408ff92386c8ba9099e3a16 python-ovos-lingua-franca-282db576c4cd0c8212eaf00ad303f0653ea0e0ed.tar.gz
|
||||
|
@ -4,7 +4,7 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
PYTHON_OVOS_LINGUA_FRANCA_VERSION = 0c4ead9b3ad396fc68a5b5c6465678b567c6c01f
|
||||
PYTHON_OVOS_LINGUA_FRANCA_VERSION = 282db576c4cd0c8212eaf00ad303f0653ea0e0ed
|
||||
PYTHON_OVOS_LINGUA_FRANCA_SITE = $(call github,OpenVoiceOS,ovos-lingua-franca,$(PYTHON_OVOS_LINGUA_FRANCA_VERSION))
|
||||
PYTHON_OVOS_LINGUA_FRANCA_SETUP_TYPE = setuptools
|
||||
PYTHON_OVOS_LINGUA_FRANCA_LICENSE = Apache-2.0
|
||||
|
@ -0,0 +1,2 @@
|
||||
# sha256 from https://pypi.org/pypi/scikit_build/json
|
||||
sha256 76856e7631d9e8887a7aa71913d5f184a6177246225391af96ce4801d89fa254 scikit_build-0.17.5.tar.gz
|
@ -0,0 +1,14 @@
|
||||
################################################################################
|
||||
#
|
||||
# python-scikit-build
|
||||
#
|
||||
################################################################################
|
||||
|
||||
PYTHON_SCIKIT_BUILD_VERSION = 0.17.5
|
||||
PYTHON_SCIKIT_BUILD_SOURCE = scikit_build-$(PYTHON_SCIKIT_BUILD_VERSION).tar.gz
|
||||
PYTHON_SCIKIT_BUILD_SITE = https://files.pythonhosted.org/packages/f8/23/a07369d9095648b61a302cd45c9661ef2d92fe546e0eb28a467c66c7c1d3
|
||||
PYTHON_SCIKIT_BUILD_LICENSE = MIT
|
||||
PYTHON_SCIKIT_BUILD_LICENSE_FILES = LICENSE
|
||||
PYTHON_SCIKIT_BUILD_SETUP_TYPE = flit
|
||||
|
||||
$(eval $(host-python-package))
|
@ -1,38 +0,0 @@
|
||||
From aabf33f93a95b4ccbd900dfee2b7508227ee9ac7 Mon Sep 17 00:00:00 2001
|
||||
From: j1nx <p.steenbergen@j1nx.nl>
|
||||
Date: Thu, 7 Jan 2021 19:21:24 +0100
|
||||
Subject: [PATCH 1/1] No package name variables
|
||||
|
||||
---
|
||||
setup.py | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/setup.py b/setup.py
|
||||
index d2afc06..0cfac34 100755
|
||||
--- a/setup.py
|
||||
+++ b/setup.py
|
||||
@@ -11,15 +11,15 @@ setup(
|
||||
# version: in VERSION file https://packaging.python.org/guides/single-sourcing-package-version/
|
||||
# With this approach you must make sure that the VERSION file is included in all your source
|
||||
# and binary distributions (e.g. add include VERSION to your MANIFEST.in).
|
||||
- author='Jannik Michelfeit',
|
||||
+ author='J. Michelfeit',
|
||||
author_email='python@michelfe.it',
|
||||
license='MIT licence',
|
||||
- url=f'https://github.com/MrMinimal64/{PACKAGE_NAME}', # use the URL to the github repo
|
||||
+ url='https://github.com/MrMinimal64/timezonefinder', # use the URL to the github repo
|
||||
project_urls={
|
||||
- "Source Code": f"https://github.com/MrMinimal64/{PACKAGE_NAME}",
|
||||
- "Documentation": f"https://{PACKAGE_NAME}.readthedocs.io/en/latest/",
|
||||
- "Changelog": f"https://github.com/MrMinimal64/{PACKAGE_NAME}/blob/master/CHANGELOG.rst",
|
||||
- "License": f"https://github.com/MrMinimal64/{PACKAGE_NAME}/blob/master/LICENSE",
|
||||
+ "Source Code": "https://github.com/MrMinimal64/timezonefinder",
|
||||
+ "Documentation": "https://timezonefinder.readthedocs.io/en/latest/",
|
||||
+ "Changelog": "https://github.com/MrMinimal64/timezonefinder/blob/master/CHANGELOG.rst",
|
||||
+ "License": "https://github.com/MrMinimal64/timezonefinder/blob/master/LICENSE",
|
||||
},
|
||||
keywords='timezone coordinates latitude longitude location pytzwhere tzwhere',
|
||||
classifiers=[
|
||||
--
|
||||
2.20.1
|
||||
|
@ -1,2 +1,2 @@
|
||||
# md5, sha256 from https://pypi.org/pypi/
|
||||
sha256 d8a05c207aab92d6f01b426dc4bcef08118ec31cf4504bd4011c7551f3160694 timezonefinder-5.0.0.tar.gz
|
||||
sha256 d41fd2650bb4221fae5a61f9c2767158f9727c4aaca95e24da86394feb704220 timezonefinder-6.2.0.tar.gz
|
||||
|
@ -4,10 +4,10 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
PYTHON_TIMEZONEFINDER_VERSION = 5.0.0
|
||||
PYTHON_TIMEZONEFINDER_VERSION = 6.2.0
|
||||
PYTHON_TIMEZONEFINDER_SOURCE = timezonefinder-$(PYTHON_TIMEZONEFINDER_VERSION).tar.gz
|
||||
PYTHON_TIMEZONEFINDER_SITE = https://files.pythonhosted.org/packages/74/d2/e6cc8edf6a6da56c5311776334b4bd2a271757573dd020592a8540512b88
|
||||
PYTHON_TIMEZONEFINDER_SETUP_TYPE = setuptools
|
||||
PYTHON_TIMEZONEFINDER_SITE = https://files.pythonhosted.org/packages/e7/68/86c8d0b21573150eb7b3c66da2c451159b0159c15d3d59b17777ea557f48
|
||||
PYTHON_TIMEZONEFINDER_SETUP_TYPE = pep517 #flit #setuptools
|
||||
PYTHON_TIMEZONEFINDER_DEPENDENCIES = host-python-numpy
|
||||
|
||||
$(eval $(python-package))
|
||||
|
@ -10,3 +10,4 @@ PYTHON_WHEEL_SITE = https://files.pythonhosted.org/packages/4e/be/8139f127b4db2f
|
||||
PYTHON_WHEEL_SETUP_TYPE = setuptools
|
||||
|
||||
$(eval $(python-package))
|
||||
$(eval $(host-python-package))
|
||||
|
@ -71,5 +71,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"log_level": "INFO"
|
||||
"log_level": "INFO",
|
||||
"logs": {
|
||||
"path": "/var/log/mycroft"
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,16 @@ vm.dirty_background_ratio = 1
|
||||
vm.dirty_ratio = 50
|
||||
vm.dirty_expire_centisecs = 500
|
||||
vm.dirty_writeback_centisecs = 500
|
||||
vm.overcommit_memory = 2
|
||||
vm.overcommit_ratio = 100
|
||||
|
||||
kernel.panic = 20
|
||||
kernel.printk = 3 4 1 3
|
||||
|
||||
fs.inotify.max_user_instances = 512
|
||||
fs.inotify.max_user_watches = 524288
|
||||
kernel.printk = 3 4 1 3
|
||||
|
||||
net.core.rmem_max = 4194304
|
||||
net.core.wmem_max = 4194304
|
||||
|
||||
net.ipv4.igmp_max_memberships = 1024
|
||||
|
8
buildroot-external/rootfs-overlay/base/usr/bin/timezonefinder
Executable file
8
buildroot-external/rootfs-overlay/base/usr/bin/timezonefinder
Executable file
@ -0,0 +1,8 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from timezonefinder.command_line import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
@ -0,0 +1 @@
|
||||
pip
|
@ -0,0 +1,20 @@
|
||||
Copyright (c) 2015 Sébastien Eustace
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@ -0,0 +1,253 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: pendulum
|
||||
Version: 2.1.2
|
||||
Summary: Python datetimes made easy
|
||||
Home-page: https://pendulum.eustace.io
|
||||
License: MIT
|
||||
Keywords: datetime,date,time
|
||||
Author: Sébastien Eustace
|
||||
Author-email: sebastien@eustace.io
|
||||
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Requires-Dist: python-dateutil (>=2.6,<3.0)
|
||||
Requires-Dist: pytzdata (>=2020.1)
|
||||
Requires-Dist: typing (>=3.6,<4.0) ; python_version < "3.5"
|
||||
Project-URL: Documentation, https://pendulum.eustace.io/docs
|
||||
Project-URL: Repository, https://github.com/sdispater/pendulum
|
||||
Description-Content-Type: text/x-rst
|
||||
|
||||
Pendulum
|
||||
########
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/pendulum.svg
|
||||
:target: https://pypi.python.org/pypi/pendulum
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/pendulum.svg
|
||||
:target: https://pypi.python.org/pypi/pendulum
|
||||
|
||||
.. image:: https://img.shields.io/codecov/c/github/sdispater/pendulum/master.svg
|
||||
:target: https://codecov.io/gh/sdispater/pendulum/branch/master
|
||||
|
||||
.. image:: https://travis-ci.org/sdispater/pendulum.svg
|
||||
:alt: Pendulum Build status
|
||||
:target: https://travis-ci.org/sdispater/pendulum
|
||||
|
||||
Python datetimes made easy.
|
||||
|
||||
Supports Python **2.7** and **3.4+**.
|
||||
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> import pendulum
|
||||
|
||||
>>> now_in_paris = pendulum.now('Europe/Paris')
|
||||
>>> now_in_paris
|
||||
'2016-07-04T00:49:58.502116+02:00'
|
||||
|
||||
# Seamless timezone switching
|
||||
>>> now_in_paris.in_timezone('UTC')
|
||||
'2016-07-03T22:49:58.502116+00:00'
|
||||
|
||||
>>> tomorrow = pendulum.now().add(days=1)
|
||||
>>> last_week = pendulum.now().subtract(weeks=1)
|
||||
|
||||
>>> past = pendulum.now().subtract(minutes=2)
|
||||
>>> past.diff_for_humans()
|
||||
>>> '2 minutes ago'
|
||||
|
||||
>>> delta = past - last_week
|
||||
>>> delta.hours
|
||||
23
|
||||
>>> delta.in_words(locale='en')
|
||||
'6 days 23 hours 58 minutes'
|
||||
|
||||
# Proper handling of datetime normalization
|
||||
>>> pendulum.datetime(2013, 3, 31, 2, 30, tz='Europe/Paris')
|
||||
'2013-03-31T03:30:00+02:00' # 2:30 does not exist (Skipped time)
|
||||
|
||||
# Proper handling of dst transitions
|
||||
>>> just_before = pendulum.datetime(2013, 3, 31, 1, 59, 59, 999999, tz='Europe/Paris')
|
||||
'2013-03-31T01:59:59.999999+01:00'
|
||||
>>> just_before.add(microseconds=1)
|
||||
'2013-03-31T03:00:00+02:00'
|
||||
|
||||
|
||||
Why Pendulum?
|
||||
=============
|
||||
|
||||
Native ``datetime`` instances are enough for basic cases but when you face more complex use-cases
|
||||
they often show limitations and are not so intuitive to work with.
|
||||
``Pendulum`` provides a cleaner and more easy to use API while still relying on the standard library.
|
||||
So it's still ``datetime`` but better.
|
||||
|
||||
Unlike other datetime libraries for Python, Pendulum is a drop-in replacement
|
||||
for the standard ``datetime`` class (it inherits from it), so, basically, you can replace all your ``datetime``
|
||||
instances by ``DateTime`` instances in you code (exceptions exist for libraries that check
|
||||
the type of the objects by using the ``type`` function like ``sqlite3`` or ``PyMySQL`` for instance).
|
||||
|
||||
It also removes the notion of naive datetimes: each ``Pendulum`` instance is timezone-aware
|
||||
and by default in ``UTC`` for ease of use.
|
||||
|
||||
Pendulum also improves the standard ``timedelta`` class by providing more intuitive methods and properties.
|
||||
|
||||
|
||||
Why not Arrow?
|
||||
==============
|
||||
|
||||
Arrow is the most popular datetime library for Python right now, however its behavior
|
||||
and API can be erratic and unpredictable. The ``get()`` method can receive pretty much anything
|
||||
and it will try its best to return something while silently failing to handle some cases:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
arrow.get('2016-1-17')
|
||||
# <Arrow [2016-01-01T00:00:00+00:00]>
|
||||
|
||||
pendulum.parse('2016-1-17')
|
||||
# <Pendulum [2016-01-17T00:00:00+00:00]>
|
||||
|
||||
arrow.get('20160413')
|
||||
# <Arrow [1970-08-22T08:06:53+00:00]>
|
||||
|
||||
pendulum.parse('20160413')
|
||||
# <Pendulum [2016-04-13T00:00:00+00:00]>
|
||||
|
||||
arrow.get('2016-W07-5')
|
||||
# <Arrow [2016-01-01T00:00:00+00:00]>
|
||||
|
||||
pendulum.parse('2016-W07-5')
|
||||
# <Pendulum [2016-02-19T00:00:00+00:00]>
|
||||
|
||||
# Working with DST
|
||||
just_before = arrow.Arrow(2013, 3, 31, 1, 59, 59, 999999, 'Europe/Paris')
|
||||
just_after = just_before.replace(microseconds=1)
|
||||
'2013-03-31T02:00:00+02:00'
|
||||
# Should be 2013-03-31T03:00:00+02:00
|
||||
|
||||
(just_after.to('utc') - just_before.to('utc')).total_seconds()
|
||||
-3599.999999
|
||||
# Should be 1e-06
|
||||
|
||||
just_before = pendulum.datetime(2013, 3, 31, 1, 59, 59, 999999, 'Europe/Paris')
|
||||
just_after = just_before.add(microseconds=1)
|
||||
'2013-03-31T03:00:00+02:00'
|
||||
|
||||
(just_after.in_timezone('utc') - just_before.in_timezone('utc')).total_seconds()
|
||||
1e-06
|
||||
|
||||
Those are a few examples showing that Arrow cannot always be trusted to have a consistent
|
||||
behavior with the data you are passing to it.
|
||||
|
||||
|
||||
Limitations
|
||||
===========
|
||||
|
||||
Even though the ``DateTime`` class is a subclass of ``datetime`` there are some rare cases where
|
||||
it can't replace the native class directly. Here is a list (non-exhaustive) of the reported cases with
|
||||
a possible solution, if any:
|
||||
|
||||
* ``sqlite3`` will use the ``type()`` function to determine the type of the object by default. To work around it you can register a new adapter:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pendulum import DateTime
|
||||
from sqlite3 import register_adapter
|
||||
|
||||
register_adapter(DateTime, lambda val: val.isoformat(' '))
|
||||
|
||||
* ``mysqlclient`` (former ``MySQLdb``) and ``PyMySQL`` will use the ``type()`` function to determine the type of the object by default. To work around it you can register a new adapter:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import MySQLdb.converters
|
||||
import pymysql.converters
|
||||
|
||||
from pendulum import DateTime
|
||||
|
||||
MySQLdb.converters.conversions[DateTime] = MySQLdb.converters.DateTime2literal
|
||||
pymysql.converters.conversions[DateTime] = pymysql.converters.escape_datetime
|
||||
|
||||
* ``django`` will use the ``isoformat()`` method to store datetimes in the database. However since ``pendulum`` is always timezone aware the offset information will always be returned by ``isoformat()`` raising an error, at least for MySQL databases. To work around it you can either create your own ``DateTimeField`` or use the previous workaround for ``MySQLdb``:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from django.db.models import DateTimeField as BaseDateTimeField
|
||||
from pendulum import DateTime
|
||||
|
||||
|
||||
class DateTimeField(BaseDateTimeField):
|
||||
|
||||
def value_to_string(self, obj):
|
||||
val = self.value_from_object(obj)
|
||||
|
||||
if isinstance(value, DateTime):
|
||||
return value.to_datetime_string()
|
||||
|
||||
return '' if val is None else val.isoformat()
|
||||
|
||||
|
||||
Resources
|
||||
=========
|
||||
|
||||
* `Official Website <https://pendulum.eustace.io>`_
|
||||
* `Documentation <https://pendulum.eustace.io/docs/>`_
|
||||
* `Issue Tracker <https://github.com/sdispater/pendulum/issues>`_
|
||||
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
Contributions are welcome, especially with localization.
|
||||
|
||||
Getting started
|
||||
---------------
|
||||
|
||||
To work on the Pendulum codebase, you'll want to clone the project locally
|
||||
and install the required depedendencies via `poetry <https://poetry.eustace.io>`_.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ git clone git@github.com:sdispater/pendulum.git
|
||||
$ poetry install
|
||||
|
||||
Localization
|
||||
------------
|
||||
|
||||
If you want to help with localization, there are two different cases: the locale already exists
|
||||
or not.
|
||||
|
||||
If the locale does not exist you will need to create it by using the ``clock`` utility:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./clock locale create <your-locale>
|
||||
|
||||
It will generate a directory in ``pendulum/locales`` named after your locale, with the following
|
||||
structure:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
<your-locale>/
|
||||
- custom.py
|
||||
- locale.py
|
||||
|
||||
The ``locale.py`` file must not be modified. It contains the translations provided by
|
||||
the CLDR database.
|
||||
|
||||
The ``custom.py`` file is the one you want to modify. It contains the data needed
|
||||
by Pendulum that are not provided by the CLDR database. You can take the `en <https://github.com/sdispater/pendulum/tree/master/pendulum/locales/en/custom.py>`_
|
||||
data as a reference to see which data is needed.
|
||||
|
||||
You should also add tests for the created or modified locale.
|
||||
|
@ -0,0 +1,193 @@
|
||||
pendulum-2.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
pendulum-2.1.2.dist-info/LICENSE,sha256=Jhgfk_52I_W_PhHK7XPsx_u0meJZ9TQzARchMPboFR0,1082
|
||||
pendulum-2.1.2.dist-info/METADATA,sha256=8Y18g-l0NDDZKdf0sOA38a874pY5qEAXbhBlE6_716c,8559
|
||||
pendulum-2.1.2.dist-info/RECORD,,
|
||||
pendulum-2.1.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum-2.1.2.dist-info/WHEEL,sha256=Ggj0fLZgB8T39FttQfxsvhk_5uZkqtSwLlvaw_6TAgo,110
|
||||
pendulum/__init__.py,sha256=I9yZ1ahXqHSNgtnZMJH3d1c0F_DXotVGrTotbIElY10,8597
|
||||
pendulum/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/__pycache__/__version__.cpython-311.pyc,,
|
||||
pendulum/__pycache__/constants.cpython-311.pyc,,
|
||||
pendulum/__pycache__/date.cpython-311.pyc,,
|
||||
pendulum/__pycache__/datetime.cpython-311.pyc,,
|
||||
pendulum/__pycache__/duration.cpython-311.pyc,,
|
||||
pendulum/__pycache__/exceptions.cpython-311.pyc,,
|
||||
pendulum/__pycache__/helpers.cpython-311.pyc,,
|
||||
pendulum/__pycache__/parser.cpython-311.pyc,,
|
||||
pendulum/__pycache__/period.cpython-311.pyc,,
|
||||
pendulum/__pycache__/time.cpython-311.pyc,,
|
||||
pendulum/__version__.py,sha256=ByWE4qw8r36fv4OeLSjIm5p0j96GhZ__fEvMV0EfSWA,23
|
||||
pendulum/_extensions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/_extensions/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/_extensions/__pycache__/helpers.cpython-311.pyc,,
|
||||
pendulum/_extensions/_helpers.c,sha256=7bRT-aSD4i3JXFSYFn5l61bMGWBcvSaN9zfhjEh6rto,25967
|
||||
pendulum/_extensions/helpers.py,sha256=j35ZG0wS5BMCx7JURA8PHZo4OAyNJAjriWXN-kZHc20,9628
|
||||
pendulum/constants.py,sha256=dC8X7rpmZtAZdHLBavg7aJH-SaNxFpuRTnvldnIbtpQ,2921
|
||||
pendulum/date.py,sha256=T95mBE0nEzLHG6fYWyUU13bnp4fne7J1NcaYxmaAFdo,25553
|
||||
pendulum/datetime.py,sha256=ozcljD8A9ZHZNgqGItXXkzYy1Lv8PIzLBFLkbgUZiwA,44014
|
||||
pendulum/duration.py,sha256=VpS69PUfHxGxKxdwcUmR6MJaiMEWk5TfDArfAsxebMo,13111
|
||||
pendulum/exceptions.py,sha256=lj-GpJsrpl-exkmV86Wr0lobPkEo6zAIf5twV7RXBBc,106
|
||||
pendulum/formatting/__init__.py,sha256=U7cXnts7Cvugr2AaECCYFAAhyV4MfMtglNvjMkRGRPY,63
|
||||
pendulum/formatting/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/formatting/__pycache__/difference_formatter.cpython-311.pyc,,
|
||||
pendulum/formatting/__pycache__/formatter.cpython-311.pyc,,
|
||||
pendulum/formatting/difference_formatter.py,sha256=Q9T7m1BF0WT8AHDQXajvvGAZ9sCGKyy5SE6RXN9ye38,4545
|
||||
pendulum/formatting/formatter.py,sha256=-xJkF2o9LyMgbAPWrFsMSaHV6mY3WxcxaELOupoCF_0,22604
|
||||
pendulum/helpers.py,sha256=mdcQhQMxICpXQOtGyVX87LFz_my8fVXVzt7Dz0cWbJM,5505
|
||||
pendulum/locales/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/da/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/da/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/da/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/da/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/da/custom.py,sha256=UBThGUwvsM3NFkkARfxagdc3TOG02ENDrWepJcdSJxQ,451
|
||||
pendulum/locales/da/locale.py,sha256=U_d0jLheiL5YVyzlxpK79kQgXDGZD1JR4lgtRBZ6R0U,4961
|
||||
pendulum/locales/de/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/de/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/de/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/de/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/de/custom.py,sha256=voSoKimREV6hw6_3iLY3QZ2iyzks8QQ8qCFKHCKT3jM,1137
|
||||
pendulum/locales/de/locale.py,sha256=Tsqk4DGa1oOnphUS24zwE6-4EZMo0sqztye1sNwnLN4,4822
|
||||
pendulum/locales/en/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/en/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/en/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/en/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/en/custom.py,sha256=PW4F4dcPoKjEbfzHLQalW66WXDtaLSOIR7SjbyaZGk8,636
|
||||
pendulum/locales/en/locale.py,sha256=wbq_f5YbuKrDKaRB32982W21FYJd7ix00LE1mInlFH8,5064
|
||||
pendulum/locales/es/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/es/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/es/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/es/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/es/custom.py,sha256=17h3Y5HqdxPPdqMheG7Hn29WrXvHs6HqGKlTO_sn1YM,628
|
||||
pendulum/locales/es/locale.py,sha256=j6fmEM5uOivo1PKePKqgnjG7Dj2gIeuuKxEN79Ekals,4871
|
||||
pendulum/locales/fa/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/fa/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/fa/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/fa/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/fa/custom.py,sha256=yuU6s6evM1XFCXmuE4QjHW5RwiwltSy1xhRryF_XsUU,455
|
||||
pendulum/locales/fa/locale.py,sha256=_-K24CSVZ2OtelErgDfeFHzvddAPYx5u2FC8KvWjACo,5112
|
||||
pendulum/locales/fo/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/fo/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/fo/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/fo/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/fo/custom.py,sha256=fMY9tEmLB07Bbp2MkwTcMW28a3koDsHfMHvb7NeCc4Q,499
|
||||
pendulum/locales/fo/locale.py,sha256=UyxR9DM5Ak89BCMSQVl5zctTuQaQHGOqY_iYr_ARd2s,4555
|
||||
pendulum/locales/fr/__init__.py,sha256=lVL4VPz3c4kWCgjPtL4uuQLNmgwK92q1ffAsv5El02k,25
|
||||
pendulum/locales/fr/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/fr/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/fr/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/fr/custom.py,sha256=kAfAr-7FaLIocIrFZPUqZ7kfO833OCbJVF3ypzN5Oqg,612
|
||||
pendulum/locales/fr/locale.py,sha256=nDdBuZ0EciY0dpKWDykp_v1y0PZWFL3U2sMg2gSZ3z4,4704
|
||||
pendulum/locales/id/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/id/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/id/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/id/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/id/custom.py,sha256=uChc_mPCfYxsM4tw0pQvif31YsExoDcTeva2cWjLu9g,523
|
||||
pendulum/locales/id/locale.py,sha256=7Dqfxb5FIoi8UdSrlpUawo40TWAI5awzE3JRmj0xHHc,4184
|
||||
pendulum/locales/it/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/it/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/it/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/it/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/it/custom.py,sha256=nmCVmVTx0B6lknX4UblbsS-S8WJhhsob3kMgUZiYKp8,600
|
||||
pendulum/locales/it/locale.py,sha256=pNRseajglYWnlddr7vAn-9C6Q3pu8u4c6-9t7ABRNqY,4861
|
||||
pendulum/locales/ko/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/ko/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/ko/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/ko/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/ko/custom.py,sha256=GdSQMb-qQ3aIkdoPpW9ff-iycDWSFmuJTMfrjJbiHcU,484
|
||||
pendulum/locales/ko/locale.py,sha256=1SB49DRkj47OcA1ZMJE4xH3t_ASCIa-t2nK4sbbPmOI,3579
|
||||
pendulum/locales/locale.py,sha256=ESQrnDsdyYsFvgyuX3lkJ6tKHG4IezQk-oe_x6ij3cQ,3131
|
||||
pendulum/locales/lt/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/lt/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/lt/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/lt/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/lt/custom.py,sha256=EipZptVq0ATZQzCgiGcrMEhvM06m8Fon-KSrcCKReAI,3574
|
||||
pendulum/locales/lt/locale.py,sha256=AUBDrdCuQY7_ln4rowzlcU22xQ0EHMWqffc8jqQhG5Q,8469
|
||||
pendulum/locales/nb/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/nb/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/nb/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/nb/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/nb/custom.py,sha256=B2rQwzo6hVOf_YFhWEVx7Lr9k6WDzVKG9FG3XbDxOIE,530
|
||||
pendulum/locales/nb/locale.py,sha256=XD0_QdZtGh1Oo0U6zh7hbFiQb5lFzwNpFfcjMXfdYAY,4986
|
||||
pendulum/locales/nl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/nl/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/nl/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/nl/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/nl/custom.py,sha256=dJXiYSTCtIqBYWH74osacEWV3VeqRubIOGb5_XXTR6U,596
|
||||
pendulum/locales/nl/locale.py,sha256=RPQm-GAF-W1xafjWREIqRTgnclq7qP9QBoXtCFvaNlQ,4666
|
||||
pendulum/locales/nn/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/nn/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/nn/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/nn/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/nn/custom.py,sha256=B2rQwzo6hVOf_YFhWEVx7Lr9k6WDzVKG9FG3XbDxOIE,530
|
||||
pendulum/locales/nn/locale.py,sha256=NryH5sNUnpAdCJ01mST4OrGgpr6cLaRKu5Oi2W__aa0,4726
|
||||
pendulum/locales/pl/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/pl/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/pl/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/pl/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/pl/custom.py,sha256=8m_v2Ynv5xMq-EmJrTXdIQkTb3oltLwYhmqFvpOPHVc,537
|
||||
pendulum/locales/pl/locale.py,sha256=8Q25uqfExrMEmob3Qx7NuAfW4dDSnj8zRx4ADZVs_2A,8891
|
||||
pendulum/locales/pt_br/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/pt_br/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/pt_br/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/pt_br/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/pt_br/custom.py,sha256=eWVXefOKashQzV4ypzGRpzWznD3R4RJvp73SFhPC5LA,491
|
||||
pendulum/locales/pt_br/locale.py,sha256=GTotVS2NJkKJiq8aoYKFjP-BKY_7HS5jnxON0UKOhQQ,4792
|
||||
pendulum/locales/ru/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/ru/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/ru/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/ru/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/ru/custom.py,sha256=lbfr7fypGvYUemcGy7A6SEFTdeUZE9Ug9oOkUdWOoU8,526
|
||||
pendulum/locales/ru/locale.py,sha256=iRrqMMfWMThae3opA4Mnaz-36TxBnQhnKSLZBsnGp_0,9685
|
||||
pendulum/locales/zh/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/locales/zh/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/locales/zh/__pycache__/custom.cpython-311.pyc,,
|
||||
pendulum/locales/zh/__pycache__/locale.cpython-311.pyc,,
|
||||
pendulum/locales/zh/custom.py,sha256=Vmtm94Bqbn1vVgOq036Rl9DV__5D2uOnxyCD-XCFEo8,470
|
||||
pendulum/locales/zh/locale.py,sha256=lD_WDMQyI7dfftcZJv4it7HjhFoEfOTUWVpqdY_GvzM,3751
|
||||
pendulum/mixins/__init__.py,sha256=lVL4VPz3c4kWCgjPtL4uuQLNmgwK92q1ffAsv5El02k,25
|
||||
pendulum/mixins/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/mixins/__pycache__/default.cpython-311.pyc,,
|
||||
pendulum/mixins/default.py,sha256=JcuObnFwaFvmnQKRjw90lJSFYM_wsjAZppt5_rDC0hs,945
|
||||
pendulum/parser.py,sha256=-G-VT1vjGVzg1iEhp6_dcmi-SJ3RN6_x7oyatNzt6Bw,3593
|
||||
pendulum/parsing/__init__.py,sha256=QqkgrQDXb6S3kKwr5CYj2OV5vn6FlykFlOek4OXZRU8,5591
|
||||
pendulum/parsing/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/parsing/__pycache__/iso8601.cpython-311.pyc,,
|
||||
pendulum/parsing/_iso8601.c,sha256=mNSd5NwIRb_yBI8l_OuoZQRBkXevLrpsESRnjcKkiWg,38384
|
||||
pendulum/parsing/exceptions/__init__.py,sha256=HOFxWKLvXl8WGjVHe_IpmqXRI3zedWdTu_0eMuopioQ,44
|
||||
pendulum/parsing/exceptions/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/parsing/iso8601.py,sha256=Nan53RPxB60BUX_5tABS_qYo7pQIq6-e3HArYhQC_NY,14304
|
||||
pendulum/period.py,sha256=XAVl-W4jqVmSPSjlrL9i2ocomVncGfTGeQONjc9RIqE,11175
|
||||
pendulum/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/time.py,sha256=y5TwExt2L0qUzcCw5RYsMdBkpNXgPzRpR27y6cQd7R8,8125
|
||||
pendulum/tz/__init__.py,sha256=A-_5bN29l2MBXXJ6moSLOmDerTyCXLCIOqyFFHRxcfs,1369
|
||||
pendulum/tz/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/tz/__pycache__/exceptions.cpython-311.pyc,,
|
||||
pendulum/tz/__pycache__/local_timezone.cpython-311.pyc,,
|
||||
pendulum/tz/__pycache__/timezone.cpython-311.pyc,,
|
||||
pendulum/tz/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/tz/data/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/tz/data/__pycache__/windows.cpython-311.pyc,,
|
||||
pendulum/tz/data/windows.py,sha256=3wfke5bjhvmlqvVFJX4ZuQjBOqVBW5ybeS-yTrj5r58,6687
|
||||
pendulum/tz/exceptions.py,sha256=xQlROtKUV2xCbWYP0uNu3xLLA_HN_DT01iSxhibFvTQ,492
|
||||
pendulum/tz/local_timezone.py,sha256=D-vPQ3MkNFPZcmMRd7zuA4-8ooi2tkl8ENL8s6K58uw,8095
|
||||
pendulum/tz/timezone.py,sha256=UJi1hoFRDrmXU7hv6B8QSy-vfe-ZeeDNMwJHda36UG4,11528
|
||||
pendulum/tz/zoneinfo/__init__.py,sha256=tce8_9Rc3ELUXU0KAmUBC5-y4Duciu7wPkCrCgBSiYk,440
|
||||
pendulum/tz/zoneinfo/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/tz/zoneinfo/__pycache__/exceptions.cpython-311.pyc,,
|
||||
pendulum/tz/zoneinfo/__pycache__/posix_timezone.cpython-311.pyc,,
|
||||
pendulum/tz/zoneinfo/__pycache__/reader.cpython-311.pyc,,
|
||||
pendulum/tz/zoneinfo/__pycache__/timezone.cpython-311.pyc,,
|
||||
pendulum/tz/zoneinfo/__pycache__/transition.cpython-311.pyc,,
|
||||
pendulum/tz/zoneinfo/__pycache__/transition_type.cpython-311.pyc,,
|
||||
pendulum/tz/zoneinfo/exceptions.py,sha256=XfTTFMOg5bZCWR8eAgOLPoybO9lh8xfv3443936FW5g,425
|
||||
pendulum/tz/zoneinfo/posix_timezone.py,sha256=io9cLnibYatE8YyDuqEOcb2dlGjj8bZGEsXMBZesES8,7277
|
||||
pendulum/tz/zoneinfo/reader.py,sha256=wpTGU8ETc-mUAMBiZgTiUB4eDWaF_9HGLoppuBz1tjM,6852
|
||||
pendulum/tz/zoneinfo/timezone.py,sha256=rPz_6i032_p0ZmN8j9w_KVqbpZ3mQtQmlkz4vX3SB7s,4248
|
||||
pendulum/tz/zoneinfo/transition.py,sha256=kGFAVy-zejKgvZ2AJMEB6vaPO2PuZMyGs992GxEtQ9E,2055
|
||||
pendulum/tz/zoneinfo/transition_type.py,sha256=6mFOT4BDVTqLqH6b0bwxlz3BWHgH17SMk9QFEKSoMG8,894
|
||||
pendulum/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
pendulum/utils/__pycache__/__init__.cpython-311.pyc,,
|
||||
pendulum/utils/__pycache__/_compat.cpython-311.pyc,,
|
||||
pendulum/utils/_compat.py,sha256=bEkROlv5IBuz6RcSdgPxweNpjYvluBXvHt1qWGaS5T0,1263
|
@ -0,0 +1,4 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: poetry-core 1.6.0
|
||||
Root-Is-Purelib: false
|
||||
Tag: cp311-cp311-manylinux_2_36_x86_64
|
@ -0,0 +1,315 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import datetime as _datetime
|
||||
|
||||
from typing import Optional
|
||||
from typing import Union
|
||||
|
||||
from .__version__ import __version__
|
||||
from .constants import DAYS_PER_WEEK
|
||||
from .constants import FRIDAY
|
||||
from .constants import HOURS_PER_DAY
|
||||
from .constants import MINUTES_PER_HOUR
|
||||
from .constants import MONDAY
|
||||
from .constants import MONTHS_PER_YEAR
|
||||
from .constants import SATURDAY
|
||||
from .constants import SECONDS_PER_DAY
|
||||
from .constants import SECONDS_PER_HOUR
|
||||
from .constants import SECONDS_PER_MINUTE
|
||||
from .constants import SUNDAY
|
||||
from .constants import THURSDAY
|
||||
from .constants import TUESDAY
|
||||
from .constants import WEDNESDAY
|
||||
from .constants import WEEKS_PER_YEAR
|
||||
from .constants import YEARS_PER_CENTURY
|
||||
from .constants import YEARS_PER_DECADE
|
||||
from .date import Date
|
||||
from .datetime import DateTime
|
||||
from .duration import Duration
|
||||
from .formatting import Formatter
|
||||
from .helpers import format_diff
|
||||
from .helpers import get_locale
|
||||
from .helpers import get_test_now
|
||||
from .helpers import has_test_now
|
||||
from .helpers import locale
|
||||
from .helpers import set_locale
|
||||
from .helpers import set_test_now
|
||||
from .helpers import test
|
||||
from .helpers import week_ends_at
|
||||
from .helpers import week_starts_at
|
||||
from .parser import parse
|
||||
from .period import Period
|
||||
from .time import Time
|
||||
from .tz import POST_TRANSITION
|
||||
from .tz import PRE_TRANSITION
|
||||
from .tz import TRANSITION_ERROR
|
||||
from .tz import UTC
|
||||
from .tz import local_timezone
|
||||
from .tz import set_local_timezone
|
||||
from .tz import test_local_timezone
|
||||
from .tz import timezone
|
||||
from .tz import timezones
|
||||
from .tz.timezone import Timezone as _Timezone
|
||||
from .utils._compat import _HAS_FOLD
|
||||
|
||||
|
||||
_TEST_NOW = None # type: Optional[DateTime]
|
||||
_LOCALE = "en"
|
||||
_WEEK_STARTS_AT = MONDAY
|
||||
_WEEK_ENDS_AT = SUNDAY
|
||||
|
||||
_formatter = Formatter()
|
||||
|
||||
|
||||
def _safe_timezone(obj):
|
||||
# type: (Optional[Union[str, float, _datetime.tzinfo, _Timezone]]) -> _Timezone
|
||||
"""
|
||||
Creates a timezone instance
|
||||
from a string, Timezone, TimezoneInfo or integer offset.
|
||||
"""
|
||||
if isinstance(obj, _Timezone):
|
||||
return obj
|
||||
|
||||
if obj is None or obj == "local":
|
||||
return local_timezone()
|
||||
|
||||
if isinstance(obj, (int, float)):
|
||||
obj = int(obj * 60 * 60)
|
||||
elif isinstance(obj, _datetime.tzinfo):
|
||||
# pytz
|
||||
if hasattr(obj, "localize"):
|
||||
obj = obj.zone
|
||||
elif obj.tzname(None) == "UTC":
|
||||
return UTC
|
||||
else:
|
||||
offset = obj.utcoffset(None)
|
||||
|
||||
if offset is None:
|
||||
offset = _datetime.timedelta(0)
|
||||
|
||||
obj = int(offset.total_seconds())
|
||||
|
||||
return timezone(obj)
|
||||
|
||||
|
||||
# Public API
|
||||
def datetime(
|
||||
year, # type: int
|
||||
month, # type: int
|
||||
day, # type: int
|
||||
hour=0, # type: int
|
||||
minute=0, # type: int
|
||||
second=0, # type: int
|
||||
microsecond=0, # type: int
|
||||
tz=UTC, # type: Optional[Union[str, float, _Timezone]]
|
||||
dst_rule=POST_TRANSITION, # type: str
|
||||
): # type: (...) -> DateTime
|
||||
"""
|
||||
Creates a new DateTime instance from a specific date and time.
|
||||
"""
|
||||
if tz is not None:
|
||||
tz = _safe_timezone(tz)
|
||||
|
||||
if not _HAS_FOLD:
|
||||
dt = naive(year, month, day, hour, minute, second, microsecond)
|
||||
else:
|
||||
dt = _datetime.datetime(year, month, day, hour, minute, second, microsecond)
|
||||
if tz is not None:
|
||||
dt = tz.convert(dt, dst_rule=dst_rule)
|
||||
|
||||
return DateTime(
|
||||
dt.year,
|
||||
dt.month,
|
||||
dt.day,
|
||||
dt.hour,
|
||||
dt.minute,
|
||||
dt.second,
|
||||
dt.microsecond,
|
||||
tzinfo=dt.tzinfo,
|
||||
fold=dt.fold,
|
||||
)
|
||||
|
||||
|
||||
def local(
|
||||
year, month, day, hour=0, minute=0, second=0, microsecond=0
|
||||
): # type: (int, int, int, int, int, int, int) -> DateTime
|
||||
"""
|
||||
Return a DateTime in the local timezone.
|
||||
"""
|
||||
return datetime(
|
||||
year, month, day, hour, minute, second, microsecond, tz=local_timezone()
|
||||
)
|
||||
|
||||
|
||||
def naive(
|
||||
year, month, day, hour=0, minute=0, second=0, microsecond=0
|
||||
): # type: (int, int, int, int, int, int, int) -> DateTime
|
||||
"""
|
||||
Return a naive DateTime.
|
||||
"""
|
||||
return DateTime(year, month, day, hour, minute, second, microsecond)
|
||||
|
||||
|
||||
def date(year, month, day): # type: (int, int, int) -> Date
|
||||
"""
|
||||
Create a new Date instance.
|
||||
"""
|
||||
return Date(year, month, day)
|
||||
|
||||
|
||||
def time(hour, minute=0, second=0, microsecond=0): # type: (int, int, int, int) -> Time
|
||||
"""
|
||||
Create a new Time instance.
|
||||
"""
|
||||
return Time(hour, minute, second, microsecond)
|
||||
|
||||
|
||||
def instance(
|
||||
dt, tz=UTC
|
||||
): # type: (_datetime.datetime, Optional[Union[str, _Timezone]]) -> DateTime
|
||||
"""
|
||||
Create a DateTime instance from a datetime one.
|
||||
"""
|
||||
if not isinstance(dt, _datetime.datetime):
|
||||
raise ValueError("instance() only accepts datetime objects.")
|
||||
|
||||
if isinstance(dt, DateTime):
|
||||
return dt
|
||||
|
||||
tz = dt.tzinfo or tz
|
||||
|
||||
# Checking for pytz/tzinfo
|
||||
if isinstance(tz, _datetime.tzinfo) and not isinstance(tz, _Timezone):
|
||||
# pytz
|
||||
if hasattr(tz, "localize") and tz.zone:
|
||||
tz = tz.zone
|
||||
else:
|
||||
# We have no sure way to figure out
|
||||
# the timezone name, we fallback
|
||||
# on a fixed offset
|
||||
tz = tz.utcoffset(dt).total_seconds() / 3600
|
||||
|
||||
return datetime(
|
||||
dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, tz=tz
|
||||
)
|
||||
|
||||
|
||||
def now(tz=None): # type: (Optional[Union[str, _Timezone]]) -> DateTime
|
||||
"""
|
||||
Get a DateTime instance for the current date and time.
|
||||
"""
|
||||
if has_test_now():
|
||||
test_instance = get_test_now()
|
||||
_tz = _safe_timezone(tz)
|
||||
|
||||
if tz is not None and _tz != test_instance.timezone:
|
||||
test_instance = test_instance.in_tz(_tz)
|
||||
|
||||
return test_instance
|
||||
|
||||
if tz is None or tz == "local":
|
||||
dt = _datetime.datetime.now(local_timezone())
|
||||
elif tz is UTC or tz == "UTC":
|
||||
dt = _datetime.datetime.now(UTC)
|
||||
else:
|
||||
dt = _datetime.datetime.now(UTC)
|
||||
tz = _safe_timezone(tz)
|
||||
dt = tz.convert(dt)
|
||||
|
||||
return DateTime(
|
||||
dt.year,
|
||||
dt.month,
|
||||
dt.day,
|
||||
dt.hour,
|
||||
dt.minute,
|
||||
dt.second,
|
||||
dt.microsecond,
|
||||
tzinfo=dt.tzinfo,
|
||||
fold=dt.fold if _HAS_FOLD else 0,
|
||||
)
|
||||
|
||||
|
||||
def today(tz="local"): # type: (Union[str, _Timezone]) -> DateTime
|
||||
"""
|
||||
Create a DateTime instance for today.
|
||||
"""
|
||||
return now(tz).start_of("day")
|
||||
|
||||
|
||||
def tomorrow(tz="local"): # type: (Union[str, _Timezone]) -> DateTime
|
||||
"""
|
||||
Create a DateTime instance for today.
|
||||
"""
|
||||
return today(tz).add(days=1)
|
||||
|
||||
|
||||
def yesterday(tz="local"): # type: (Union[str, _Timezone]) -> DateTime
|
||||
"""
|
||||
Create a DateTime instance for today.
|
||||
"""
|
||||
return today(tz).subtract(days=1)
|
||||
|
||||
|
||||
def from_format(
|
||||
string, fmt, tz=UTC, locale=None, # noqa
|
||||
): # type: (str, str, Union[str, _Timezone], Optional[str]) -> DateTime
|
||||
"""
|
||||
Creates a DateTime instance from a specific format.
|
||||
"""
|
||||
parts = _formatter.parse(string, fmt, now(), locale=locale)
|
||||
if parts["tz"] is None:
|
||||
parts["tz"] = tz
|
||||
|
||||
return datetime(**parts)
|
||||
|
||||
|
||||
def from_timestamp(
|
||||
timestamp, tz=UTC
|
||||
): # type: (Union[int, float], Union[str, _Timezone]) -> DateTime
|
||||
"""
|
||||
Create a DateTime instance from a timestamp.
|
||||
"""
|
||||
dt = _datetime.datetime.utcfromtimestamp(timestamp)
|
||||
|
||||
dt = datetime(
|
||||
dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond
|
||||
)
|
||||
|
||||
if tz is not UTC or tz != "UTC":
|
||||
dt = dt.in_timezone(tz)
|
||||
|
||||
return dt
|
||||
|
||||
|
||||
def duration(
|
||||
days=0, # type: float
|
||||
seconds=0, # type: float
|
||||
microseconds=0, # type: float
|
||||
milliseconds=0, # type: float
|
||||
minutes=0, # type: float
|
||||
hours=0, # type: float
|
||||
weeks=0, # type: float
|
||||
years=0, # type: float
|
||||
months=0, # type: float
|
||||
): # type: (...) -> Duration
|
||||
"""
|
||||
Create a Duration instance.
|
||||
"""
|
||||
return Duration(
|
||||
days=days,
|
||||
seconds=seconds,
|
||||
microseconds=microseconds,
|
||||
milliseconds=milliseconds,
|
||||
minutes=minutes,
|
||||
hours=hours,
|
||||
weeks=weeks,
|
||||
years=years,
|
||||
months=months,
|
||||
)
|
||||
|
||||
|
||||
def period(start, end, absolute=False): # type: (DateTime, DateTime, bool) -> Period
|
||||
"""
|
||||
Create a Period instance.
|
||||
"""
|
||||
return Period(start, end, absolute=absolute)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
||||
__version__ = "2.1.2"
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,930 @@
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#include <Python.h>
|
||||
#include <datetime.h>
|
||||
#include <structmember.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define EPOCH_YEAR 1970
|
||||
|
||||
#define DAYS_PER_N_YEAR 365
|
||||
#define DAYS_PER_L_YEAR 366
|
||||
|
||||
#define USECS_PER_SEC 1000000
|
||||
|
||||
#define SECS_PER_MIN 60
|
||||
#define SECS_PER_HOUR (60 * SECS_PER_MIN)
|
||||
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
|
||||
|
||||
// 400-year chunks always have 146097 days (20871 weeks).
|
||||
#define DAYS_PER_400_YEARS 146097L
|
||||
#define SECS_PER_400_YEARS ((int64_t)DAYS_PER_400_YEARS * (int64_t)SECS_PER_DAY)
|
||||
|
||||
// The number of seconds in an aligned 100-year chunk, for those that
|
||||
// do not begin with a leap year and those that do respectively.
|
||||
const int64_t SECS_PER_100_YEARS[2] = {
|
||||
(uint64_t)(76L * DAYS_PER_N_YEAR + 24L * DAYS_PER_L_YEAR) * SECS_PER_DAY,
|
||||
(uint64_t)(75L * DAYS_PER_N_YEAR + 25L * DAYS_PER_L_YEAR) * SECS_PER_DAY};
|
||||
|
||||
// The number of seconds in an aligned 4-year chunk, for those that
|
||||
// do not begin with a leap year and those that do respectively.
|
||||
const int32_t SECS_PER_4_YEARS[2] = {
|
||||
(4 * DAYS_PER_N_YEAR + 0 * DAYS_PER_L_YEAR) * SECS_PER_DAY,
|
||||
(3 * DAYS_PER_N_YEAR + 1 * DAYS_PER_L_YEAR) * SECS_PER_DAY};
|
||||
|
||||
// The number of seconds in non-leap and leap years respectively.
|
||||
const int32_t SECS_PER_YEAR[2] = {
|
||||
DAYS_PER_N_YEAR * SECS_PER_DAY,
|
||||
DAYS_PER_L_YEAR *SECS_PER_DAY};
|
||||
|
||||
#define MONTHS_PER_YEAR 12
|
||||
|
||||
// The month lengths in non-leap and leap years respectively.
|
||||
const int32_t DAYS_PER_MONTHS[2][13] = {
|
||||
{-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
|
||||
{-1, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}};
|
||||
|
||||
// The day offsets of the beginning of each (1-based) month in non-leap
|
||||
// and leap years respectively.
|
||||
// For example, in a leap year there are 335 days before December.
|
||||
const int32_t MONTHS_OFFSETS[2][14] = {
|
||||
{-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
|
||||
{-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}};
|
||||
|
||||
const int DAY_OF_WEEK_TABLE[12] = {
|
||||
0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
|
||||
|
||||
#define TM_SUNDAY 0
|
||||
#define TM_MONDAY 1
|
||||
#define TM_TUESDAY 2
|
||||
#define TM_WEDNESDAY 3
|
||||
#define TM_THURSDAY 4
|
||||
#define TM_FRIDAY 5
|
||||
#define TM_SATURDAY 6
|
||||
|
||||
#define TM_JANUARY 0
|
||||
#define TM_FEBRUARY 1
|
||||
#define TM_MARCH 2
|
||||
#define TM_APRIL 3
|
||||
#define TM_MAY 4
|
||||
#define TM_JUNE 5
|
||||
#define TM_JULY 6
|
||||
#define TM_AUGUST 7
|
||||
#define TM_SEPTEMBER 8
|
||||
#define TM_OCTOBER 9
|
||||
#define TM_NOVEMBER 10
|
||||
#define TM_DECEMBER 11
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int _p(int y)
|
||||
{
|
||||
return y + y / 4 - y / 100 + y / 400;
|
||||
}
|
||||
|
||||
int _is_leap(int year)
|
||||
{
|
||||
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||
}
|
||||
|
||||
int _is_long_year(int year)
|
||||
{
|
||||
return (_p(year) % 7 == 4) || (_p(year - 1) % 7 == 3);
|
||||
}
|
||||
|
||||
int _week_day(int year, int month, int day)
|
||||
{
|
||||
int y;
|
||||
int w;
|
||||
|
||||
y = year - (month < 3);
|
||||
|
||||
w = (_p(y) + DAY_OF_WEEK_TABLE[month - 1] + day) % 7;
|
||||
|
||||
if (!w)
|
||||
{
|
||||
w = 7;
|
||||
}
|
||||
|
||||
return w;
|
||||
}
|
||||
|
||||
int _days_in_year(int year)
|
||||
{
|
||||
if (_is_leap(year))
|
||||
{
|
||||
return DAYS_PER_L_YEAR;
|
||||
}
|
||||
|
||||
return DAYS_PER_N_YEAR;
|
||||
}
|
||||
|
||||
int _day_number(int year, int month, int day)
|
||||
{
|
||||
month = (month + 9) % 12;
|
||||
year = year - month / 10;
|
||||
|
||||
return (
|
||||
365 * year + year / 4 - year / 100 + year / 400 + (month * 306 + 5) / 10 + (day - 1));
|
||||
}
|
||||
|
||||
int _get_offset(PyObject *dt)
|
||||
{
|
||||
PyObject *tzinfo;
|
||||
PyObject *offset;
|
||||
|
||||
tzinfo = ((PyDateTime_DateTime *)(dt))->tzinfo;
|
||||
|
||||
if (tzinfo != Py_None)
|
||||
{
|
||||
offset = PyObject_CallMethod(tzinfo, "utcoffset", "O", dt);
|
||||
|
||||
return PyDateTime_DELTA_GET_DAYS(offset) * SECS_PER_DAY + PyDateTime_DELTA_GET_SECONDS(offset);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _has_tzinfo(PyObject *dt)
|
||||
{
|
||||
return ((_PyDateTime_BaseTZInfo *)(dt))->hastzinfo;
|
||||
}
|
||||
|
||||
char *_get_tz_name(PyObject *dt)
|
||||
{
|
||||
PyObject *tzinfo;
|
||||
char *tz = "";
|
||||
|
||||
tzinfo = ((PyDateTime_DateTime *)(dt))->tzinfo;
|
||||
|
||||
if (tzinfo != Py_None)
|
||||
{
|
||||
if (PyObject_HasAttrString(tzinfo, "name"))
|
||||
{
|
||||
// Pendulum timezone
|
||||
tz = (char *)PyUnicode_AsUTF8(
|
||||
PyObject_GetAttrString(tzinfo, "name"));
|
||||
}
|
||||
else if (PyObject_HasAttrString(tzinfo, "zone"))
|
||||
{
|
||||
// pytz timezone
|
||||
tz = (char *)PyUnicode_AsUTF8(
|
||||
PyObject_GetAttrString(tzinfo, "zone"));
|
||||
}
|
||||
}
|
||||
|
||||
return tz;
|
||||
}
|
||||
|
||||
/* ------------------------ Custom Types ------------------------------- */
|
||||
|
||||
/*
|
||||
* class Diff():
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
PyObject_HEAD int years;
|
||||
int months;
|
||||
int days;
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
int microseconds;
|
||||
int total_days;
|
||||
} Diff;
|
||||
|
||||
/*
|
||||
* def __init__(self, years, months, days, hours, minutes, seconds, microseconds, total_days):
|
||||
* self.years = years
|
||||
* # ...
|
||||
*/
|
||||
static int Diff_init(Diff *self, PyObject *args, PyObject *kwargs)
|
||||
{
|
||||
int years;
|
||||
int months;
|
||||
int days;
|
||||
int hours;
|
||||
int minutes;
|
||||
int seconds;
|
||||
int microseconds;
|
||||
int total_days;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iiiiiii", &years, &months, &days, &hours, &minutes, &seconds, µseconds, &total_days))
|
||||
return -1;
|
||||
|
||||
self->years = years;
|
||||
self->months = months;
|
||||
self->days = days;
|
||||
self->hours = hours;
|
||||
self->minutes = minutes;
|
||||
self->seconds = seconds;
|
||||
self->microseconds = microseconds;
|
||||
self->total_days = total_days;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* def __repr__(self):
|
||||
* return '{} years {} months {} days {} hours {} minutes {} seconds {} microseconds'.format(
|
||||
* self.years, self.months, self.days, self.minutes, self.hours, self.seconds, self.microseconds
|
||||
* )
|
||||
*/
|
||||
static PyObject *Diff_repr(Diff *self)
|
||||
{
|
||||
char repr[82] = {0};
|
||||
|
||||
sprintf(
|
||||
repr,
|
||||
"%d years %d months %d days %d hours %d minutes %d seconds %d microseconds",
|
||||
self->years,
|
||||
self->months,
|
||||
self->days,
|
||||
self->hours,
|
||||
self->minutes,
|
||||
self->seconds,
|
||||
self->microseconds);
|
||||
|
||||
return PyUnicode_FromString(repr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Instantiate new Diff_type object
|
||||
* Skip overhead of calling PyObject_New and PyObject_Init.
|
||||
* Directly allocate object.
|
||||
*/
|
||||
static PyObject *new_diff_ex(int years, int months, int days, int hours, int minutes, int seconds, int microseconds, int total_days, PyTypeObject *type)
|
||||
{
|
||||
Diff *self = (Diff *)(type->tp_alloc(type, 0));
|
||||
|
||||
if (self != NULL)
|
||||
{
|
||||
self->years = years;
|
||||
self->months = months;
|
||||
self->days = days;
|
||||
self->hours = hours;
|
||||
self->minutes = minutes;
|
||||
self->seconds = seconds;
|
||||
self->microseconds = microseconds;
|
||||
self->total_days = total_days;
|
||||
}
|
||||
|
||||
return (PyObject *)self;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class member / class attributes
|
||||
*/
|
||||
static PyMemberDef Diff_members[] = {
|
||||
{"years", T_INT, offsetof(Diff, years), 0, "years in diff"},
|
||||
{"months", T_INT, offsetof(Diff, months), 0, "months in diff"},
|
||||
{"days", T_INT, offsetof(Diff, days), 0, "days in diff"},
|
||||
{"hours", T_INT, offsetof(Diff, hours), 0, "hours in diff"},
|
||||
{"minutes", T_INT, offsetof(Diff, minutes), 0, "minutes in diff"},
|
||||
{"seconds", T_INT, offsetof(Diff, seconds), 0, "seconds in diff"},
|
||||
{"microseconds", T_INT, offsetof(Diff, microseconds), 0, "microseconds in diff"},
|
||||
{"total_days", T_INT, offsetof(Diff, total_days), 0, "total days in diff"},
|
||||
{NULL}};
|
||||
|
||||
static PyTypeObject Diff_type = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0) "PreciseDiff", /* tp_name */
|
||||
sizeof(Diff), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
0, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_as_async */
|
||||
(reprfunc)Diff_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
(reprfunc)Diff_repr, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
"Precise difference between two datetime objects", /* tp_doc */
|
||||
};
|
||||
|
||||
#define new_diff(years, months, days, hours, minutes, seconds, microseconds, total_days) new_diff_ex(years, months, days, hours, minutes, seconds, microseconds, total_days, &Diff_type)
|
||||
|
||||
/* -------------------------- Functions --------------------------*/
|
||||
|
||||
PyObject *is_leap(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *leap;
|
||||
int year;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i", &year))
|
||||
{
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError, "Invalid parameters");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
leap = PyBool_FromLong(_is_leap(year));
|
||||
|
||||
return leap;
|
||||
}
|
||||
|
||||
PyObject *is_long_year(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *is_long;
|
||||
int year;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i", &year))
|
||||
{
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError, "Invalid parameters");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
is_long = PyBool_FromLong(_is_long_year(year));
|
||||
|
||||
return is_long;
|
||||
}
|
||||
|
||||
PyObject *week_day(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *wd;
|
||||
int year;
|
||||
int month;
|
||||
int day;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "iii", &year, &month, &day))
|
||||
{
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError, "Invalid parameters");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wd = PyLong_FromLong(_week_day(year, month, day));
|
||||
|
||||
return wd;
|
||||
}
|
||||
|
||||
PyObject *days_in_year(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *ndays;
|
||||
int year;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "i", &year))
|
||||
{
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError, "Invalid parameters");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ndays = PyLong_FromLong(_days_in_year(year));
|
||||
|
||||
return ndays;
|
||||
}
|
||||
|
||||
PyObject *timestamp(PyObject *self, PyObject *args)
|
||||
{
|
||||
int64_t result;
|
||||
PyObject *dt;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O", &dt))
|
||||
{
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError, "Invalid parameters");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int year = (double)PyDateTime_GET_YEAR(dt);
|
||||
int month = PyDateTime_GET_MONTH(dt);
|
||||
int day = PyDateTime_GET_DAY(dt);
|
||||
int hour = PyDateTime_DATE_GET_HOUR(dt);
|
||||
int minute = PyDateTime_DATE_GET_MINUTE(dt);
|
||||
int second = PyDateTime_DATE_GET_SECOND(dt);
|
||||
|
||||
result = (year - 1970) * 365 + MONTHS_OFFSETS[0][month];
|
||||
result += (int)floor((double)(year - 1968) / 4);
|
||||
result -= (year - 1900) / 100;
|
||||
result += (year - 1600) / 400;
|
||||
|
||||
if (_is_leap(year) && month < 3)
|
||||
{
|
||||
result -= 1;
|
||||
}
|
||||
|
||||
result += day - 1;
|
||||
result *= 24;
|
||||
result += hour;
|
||||
result *= 60;
|
||||
result += minute;
|
||||
result *= 60;
|
||||
result += second;
|
||||
|
||||
return PyLong_FromSsize_t(result);
|
||||
}
|
||||
|
||||
PyObject *local_time(PyObject *self, PyObject *args)
|
||||
{
|
||||
double unix_time;
|
||||
int32_t utc_offset;
|
||||
int32_t year;
|
||||
int32_t microsecond;
|
||||
int64_t seconds;
|
||||
int32_t leap_year;
|
||||
int64_t sec_per_100years;
|
||||
int64_t sec_per_4years;
|
||||
int32_t sec_per_year;
|
||||
int32_t month;
|
||||
int32_t day;
|
||||
int32_t month_offset;
|
||||
int32_t hour;
|
||||
int32_t minute;
|
||||
int32_t second;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "dii", &unix_time, &utc_offset, µsecond))
|
||||
{
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError, "Invalid parameters");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
year = EPOCH_YEAR;
|
||||
seconds = (int64_t)floor(unix_time);
|
||||
|
||||
// Shift to a base year that is 400-year aligned.
|
||||
if (seconds >= 0)
|
||||
{
|
||||
seconds -= 10957L * SECS_PER_DAY;
|
||||
year += 30; // == 2000;
|
||||
}
|
||||
else
|
||||
{
|
||||
seconds += (int64_t)(146097L - 10957L) * SECS_PER_DAY;
|
||||
year -= 370; // == 1600;
|
||||
}
|
||||
|
||||
seconds += utc_offset;
|
||||
|
||||
// Handle years in chunks of 400/100/4/1
|
||||
year += 400 * (seconds / SECS_PER_400_YEARS);
|
||||
seconds %= SECS_PER_400_YEARS;
|
||||
if (seconds < 0)
|
||||
{
|
||||
seconds += SECS_PER_400_YEARS;
|
||||
year -= 400;
|
||||
}
|
||||
|
||||
leap_year = 1; // 4-century aligned
|
||||
|
||||
sec_per_100years = SECS_PER_100_YEARS[leap_year];
|
||||
|
||||
while (seconds >= sec_per_100years)
|
||||
{
|
||||
seconds -= sec_per_100years;
|
||||
year += 100;
|
||||
leap_year = 0; // 1-century, non 4-century aligned
|
||||
sec_per_100years = SECS_PER_100_YEARS[leap_year];
|
||||
}
|
||||
|
||||
sec_per_4years = SECS_PER_4_YEARS[leap_year];
|
||||
while (seconds >= sec_per_4years)
|
||||
{
|
||||
seconds -= sec_per_4years;
|
||||
year += 4;
|
||||
leap_year = 1; // 4-year, non century aligned
|
||||
sec_per_4years = SECS_PER_4_YEARS[leap_year];
|
||||
}
|
||||
|
||||
sec_per_year = SECS_PER_YEAR[leap_year];
|
||||
while (seconds >= sec_per_year)
|
||||
{
|
||||
seconds -= sec_per_year;
|
||||
year += 1;
|
||||
leap_year = 0; // non 4-year aligned
|
||||
sec_per_year = SECS_PER_YEAR[leap_year];
|
||||
}
|
||||
|
||||
// Handle months and days
|
||||
month = TM_DECEMBER + 1;
|
||||
day = seconds / SECS_PER_DAY + 1;
|
||||
seconds %= SECS_PER_DAY;
|
||||
while (month != TM_JANUARY + 1)
|
||||
{
|
||||
month_offset = MONTHS_OFFSETS[leap_year][month];
|
||||
if (day > month_offset)
|
||||
{
|
||||
day -= month_offset;
|
||||
break;
|
||||
}
|
||||
|
||||
month -= 1;
|
||||
}
|
||||
|
||||
// Handle hours, minutes and seconds
|
||||
hour = seconds / SECS_PER_HOUR;
|
||||
seconds %= SECS_PER_HOUR;
|
||||
minute = seconds / SECS_PER_MIN;
|
||||
second = seconds % SECS_PER_MIN;
|
||||
|
||||
return Py_BuildValue("NNNNNNN",
|
||||
PyLong_FromLong(year),
|
||||
PyLong_FromLong(month),
|
||||
PyLong_FromLong(day),
|
||||
PyLong_FromLong(hour),
|
||||
PyLong_FromLong(minute),
|
||||
PyLong_FromLong(second),
|
||||
PyLong_FromLong(microsecond));
|
||||
}
|
||||
|
||||
// Calculate a precise difference between two datetimes.
|
||||
PyObject *precise_diff(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *dt1;
|
||||
PyObject *dt2;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "OO", &dt1, &dt2))
|
||||
{
|
||||
PyErr_SetString(
|
||||
PyExc_ValueError, "Invalid parameters");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int year_diff = 0;
|
||||
int month_diff = 0;
|
||||
int day_diff = 0;
|
||||
int hour_diff = 0;
|
||||
int minute_diff = 0;
|
||||
int second_diff = 0;
|
||||
int microsecond_diff = 0;
|
||||
int sign = 1;
|
||||
int year;
|
||||
int month;
|
||||
int leap;
|
||||
int days_in_last_month;
|
||||
int days_in_month;
|
||||
int dt1_year = PyDateTime_GET_YEAR(dt1);
|
||||
int dt2_year = PyDateTime_GET_YEAR(dt2);
|
||||
int dt1_month = PyDateTime_GET_MONTH(dt1);
|
||||
int dt2_month = PyDateTime_GET_MONTH(dt2);
|
||||
int dt1_day = PyDateTime_GET_DAY(dt1);
|
||||
int dt2_day = PyDateTime_GET_DAY(dt2);
|
||||
int dt1_hour = 0;
|
||||
int dt2_hour = 0;
|
||||
int dt1_minute = 0;
|
||||
int dt2_minute = 0;
|
||||
int dt1_second = 0;
|
||||
int dt2_second = 0;
|
||||
int dt1_microsecond = 0;
|
||||
int dt2_microsecond = 0;
|
||||
int dt1_total_seconds = 0;
|
||||
int dt2_total_seconds = 0;
|
||||
int dt1_offset = 0;
|
||||
int dt2_offset = 0;
|
||||
int dt1_is_datetime = PyDateTime_Check(dt1);
|
||||
int dt2_is_datetime = PyDateTime_Check(dt2);
|
||||
char *tz1 = "";
|
||||
char *tz2 = "";
|
||||
int in_same_tz = 0;
|
||||
int total_days = (_day_number(dt2_year, dt2_month, dt2_day) - _day_number(dt1_year, dt1_month, dt1_day));
|
||||
|
||||
// If both dates are datetimes, we check
|
||||
// If we are in the same timezone
|
||||
if (dt1_is_datetime && dt2_is_datetime)
|
||||
{
|
||||
if (_has_tzinfo(dt1))
|
||||
{
|
||||
tz1 = _get_tz_name(dt1);
|
||||
dt1_offset = _get_offset(dt1);
|
||||
}
|
||||
|
||||
if (_has_tzinfo(dt2))
|
||||
{
|
||||
tz2 = _get_tz_name(dt2);
|
||||
dt2_offset = _get_offset(dt2);
|
||||
}
|
||||
|
||||
in_same_tz = tz1 == tz2 && strncmp(tz1, "", 1);
|
||||
}
|
||||
|
||||
// If we have datetimes (and not only dates)
|
||||
// we get the information we need
|
||||
if (dt1_is_datetime)
|
||||
{
|
||||
dt1_hour = PyDateTime_DATE_GET_HOUR(dt1);
|
||||
dt1_minute = PyDateTime_DATE_GET_MINUTE(dt1);
|
||||
dt1_second = PyDateTime_DATE_GET_SECOND(dt1);
|
||||
dt1_microsecond = PyDateTime_DATE_GET_MICROSECOND(dt1);
|
||||
|
||||
if ((!in_same_tz && dt1_offset != 0) || total_days == 0)
|
||||
{
|
||||
dt1_hour -= dt1_offset / SECS_PER_HOUR;
|
||||
dt1_offset %= SECS_PER_HOUR;
|
||||
dt1_minute -= dt1_offset / SECS_PER_MIN;
|
||||
dt1_offset %= SECS_PER_MIN;
|
||||
dt1_second -= dt1_offset;
|
||||
|
||||
if (dt1_second < 0)
|
||||
{
|
||||
dt1_second += 60;
|
||||
dt1_minute -= 1;
|
||||
}
|
||||
else if (dt1_second > 60)
|
||||
{
|
||||
dt1_second -= 60;
|
||||
dt1_minute += 1;
|
||||
}
|
||||
|
||||
if (dt1_minute < 0)
|
||||
{
|
||||
dt1_minute += 60;
|
||||
dt1_hour -= 1;
|
||||
}
|
||||
else if (dt1_minute > 60)
|
||||
{
|
||||
dt1_minute -= 60;
|
||||
dt1_hour += 1;
|
||||
}
|
||||
|
||||
if (dt1_hour < 0)
|
||||
{
|
||||
dt1_hour += 24;
|
||||
dt1_day -= 1;
|
||||
}
|
||||
else if (dt1_hour > 24)
|
||||
{
|
||||
dt1_hour -= 24;
|
||||
dt1_day += 1;
|
||||
}
|
||||
}
|
||||
|
||||
dt1_total_seconds = (dt1_hour * SECS_PER_HOUR + dt1_minute * SECS_PER_MIN + dt1_second);
|
||||
}
|
||||
|
||||
if (dt2_is_datetime)
|
||||
{
|
||||
dt2_hour = PyDateTime_DATE_GET_HOUR(dt2);
|
||||
dt2_minute = PyDateTime_DATE_GET_MINUTE(dt2);
|
||||
dt2_second = PyDateTime_DATE_GET_SECOND(dt2);
|
||||
dt2_microsecond = PyDateTime_DATE_GET_MICROSECOND(dt2);
|
||||
|
||||
if ((!in_same_tz && dt2_offset != 0) || total_days == 0)
|
||||
{
|
||||
dt2_hour -= dt2_offset / SECS_PER_HOUR;
|
||||
dt2_offset %= SECS_PER_HOUR;
|
||||
dt2_minute -= dt2_offset / SECS_PER_MIN;
|
||||
dt2_offset %= SECS_PER_MIN;
|
||||
dt2_second -= dt2_offset;
|
||||
|
||||
if (dt2_second < 0)
|
||||
{
|
||||
dt2_second += 60;
|
||||
dt2_minute -= 1;
|
||||
}
|
||||
else if (dt2_second > 60)
|
||||
{
|
||||
dt2_second -= 60;
|
||||
dt2_minute += 1;
|
||||
}
|
||||
|
||||
if (dt2_minute < 0)
|
||||
{
|
||||
dt2_minute += 60;
|
||||
dt2_hour -= 1;
|
||||
}
|
||||
else if (dt2_minute > 60)
|
||||
{
|
||||
dt2_minute -= 60;
|
||||
dt2_hour += 1;
|
||||
}
|
||||
|
||||
if (dt2_hour < 0)
|
||||
{
|
||||
dt2_hour += 24;
|
||||
dt2_day -= 1;
|
||||
}
|
||||
else if (dt2_hour > 24)
|
||||
{
|
||||
dt2_hour -= 24;
|
||||
dt2_day += 1;
|
||||
}
|
||||
}
|
||||
|
||||
dt2_total_seconds = (dt2_hour * SECS_PER_HOUR + dt2_minute * SECS_PER_MIN + dt2_second);
|
||||
}
|
||||
|
||||
// Direct comparison between two datetimes does not work
|
||||
// so we need to check by properties
|
||||
int dt1_gt_dt2 = (dt1_year > dt2_year || (dt1_year == dt2_year && dt1_month > dt2_month) || (dt1_year == dt2_year && dt1_month == dt2_month && dt1_day > dt2_day) || (dt1_year == dt2_year && dt1_month == dt2_month && dt1_day == dt2_day && dt1_total_seconds > dt2_total_seconds) || (dt1_year == dt2_year && dt1_month == dt2_month && dt1_day == dt2_day && dt1_total_seconds == dt2_total_seconds && dt1_microsecond > dt2_microsecond));
|
||||
|
||||
if (dt1_gt_dt2)
|
||||
{
|
||||
PyObject *temp;
|
||||
temp = dt1;
|
||||
dt1 = dt2;
|
||||
dt2 = temp;
|
||||
sign = -1;
|
||||
|
||||
// Retrieving properties
|
||||
dt1_year = PyDateTime_GET_YEAR(dt1);
|
||||
dt2_year = PyDateTime_GET_YEAR(dt2);
|
||||
dt1_month = PyDateTime_GET_MONTH(dt1);
|
||||
dt2_month = PyDateTime_GET_MONTH(dt2);
|
||||
dt1_day = PyDateTime_GET_DAY(dt1);
|
||||
dt2_day = PyDateTime_GET_DAY(dt2);
|
||||
|
||||
if (dt2_is_datetime)
|
||||
{
|
||||
dt1_hour = PyDateTime_DATE_GET_HOUR(dt1);
|
||||
dt1_minute = PyDateTime_DATE_GET_MINUTE(dt1);
|
||||
dt1_second = PyDateTime_DATE_GET_SECOND(dt1);
|
||||
dt1_microsecond = PyDateTime_DATE_GET_MICROSECOND(dt1);
|
||||
}
|
||||
|
||||
if (dt1_is_datetime)
|
||||
{
|
||||
dt2_hour = PyDateTime_DATE_GET_HOUR(dt2);
|
||||
dt2_minute = PyDateTime_DATE_GET_MINUTE(dt2);
|
||||
dt2_second = PyDateTime_DATE_GET_SECOND(dt2);
|
||||
dt2_microsecond = PyDateTime_DATE_GET_MICROSECOND(dt2);
|
||||
}
|
||||
|
||||
total_days = (_day_number(dt2_year, dt2_month, dt2_day) - _day_number(dt1_year, dt1_month, dt1_day));
|
||||
}
|
||||
|
||||
year_diff = dt2_year - dt1_year;
|
||||
month_diff = dt2_month - dt1_month;
|
||||
day_diff = dt2_day - dt1_day;
|
||||
hour_diff = dt2_hour - dt1_hour;
|
||||
minute_diff = dt2_minute - dt1_minute;
|
||||
second_diff = dt2_second - dt1_second;
|
||||
microsecond_diff = dt2_microsecond - dt1_microsecond;
|
||||
|
||||
if (microsecond_diff < 0)
|
||||
{
|
||||
microsecond_diff += 1e6;
|
||||
second_diff -= 1;
|
||||
}
|
||||
|
||||
if (second_diff < 0)
|
||||
{
|
||||
second_diff += 60;
|
||||
minute_diff -= 1;
|
||||
}
|
||||
|
||||
if (minute_diff < 0)
|
||||
{
|
||||
minute_diff += 60;
|
||||
hour_diff -= 1;
|
||||
}
|
||||
|
||||
if (hour_diff < 0)
|
||||
{
|
||||
hour_diff += 24;
|
||||
day_diff -= 1;
|
||||
}
|
||||
|
||||
if (day_diff < 0)
|
||||
{
|
||||
// If we have a difference in days,
|
||||
// we have to check if they represent months
|
||||
year = dt2_year;
|
||||
month = dt2_month;
|
||||
|
||||
if (month == 1)
|
||||
{
|
||||
month = 12;
|
||||
year -= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
month -= 1;
|
||||
}
|
||||
|
||||
leap = _is_leap(year);
|
||||
|
||||
days_in_last_month = DAYS_PER_MONTHS[leap][month];
|
||||
days_in_month = DAYS_PER_MONTHS[_is_leap(dt2_year)][dt2_month];
|
||||
|
||||
if (day_diff < days_in_month - days_in_last_month)
|
||||
{
|
||||
// We don't have a full month, we calculate days
|
||||
if (days_in_last_month < dt1_day)
|
||||
{
|
||||
day_diff += dt1_day;
|
||||
}
|
||||
else
|
||||
{
|
||||
day_diff += days_in_last_month;
|
||||
}
|
||||
}
|
||||
else if (day_diff == days_in_month - days_in_last_month)
|
||||
{
|
||||
// We have exactly a full month
|
||||
// We remove the days difference
|
||||
// and add one to the months difference
|
||||
day_diff = 0;
|
||||
month_diff += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We have a full month
|
||||
day_diff += days_in_last_month;
|
||||
}
|
||||
|
||||
month_diff -= 1;
|
||||
}
|
||||
|
||||
if (month_diff < 0)
|
||||
{
|
||||
month_diff += 12;
|
||||
year_diff -= 1;
|
||||
}
|
||||
|
||||
return new_diff(
|
||||
year_diff * sign,
|
||||
month_diff * sign,
|
||||
day_diff * sign,
|
||||
hour_diff * sign,
|
||||
minute_diff * sign,
|
||||
second_diff * sign,
|
||||
microsecond_diff * sign,
|
||||
total_days * sign);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static PyMethodDef helpers_methods[] = {
|
||||
{"is_leap",
|
||||
(PyCFunction)is_leap,
|
||||
METH_VARARGS,
|
||||
PyDoc_STR("Checks if a year is a leap year.")},
|
||||
{"is_long_year",
|
||||
(PyCFunction)is_long_year,
|
||||
METH_VARARGS,
|
||||
PyDoc_STR("Checks if a year is a long year.")},
|
||||
{"week_day",
|
||||
(PyCFunction)week_day,
|
||||
METH_VARARGS,
|
||||
PyDoc_STR("Returns the weekday number.")},
|
||||
{"days_in_year",
|
||||
(PyCFunction)days_in_year,
|
||||
METH_VARARGS,
|
||||
PyDoc_STR("Returns the number of days in the given year.")},
|
||||
{"timestamp",
|
||||
(PyCFunction)timestamp,
|
||||
METH_VARARGS,
|
||||
PyDoc_STR("Returns the timestamp of the given datetime.")},
|
||||
{"local_time",
|
||||
(PyCFunction)local_time,
|
||||
METH_VARARGS,
|
||||
PyDoc_STR("Returns a UNIX time as a broken down time for a particular transition type.")},
|
||||
{"precise_diff",
|
||||
(PyCFunction)precise_diff,
|
||||
METH_VARARGS,
|
||||
PyDoc_STR("Calculate a precise difference between two datetimes.")},
|
||||
{NULL}};
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"_helpers",
|
||||
NULL,
|
||||
-1,
|
||||
helpers_methods,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit__helpers(void)
|
||||
{
|
||||
PyObject *module;
|
||||
|
||||
PyDateTime_IMPORT;
|
||||
|
||||
module = PyModule_Create(&moduledef);
|
||||
|
||||
if (module == NULL)
|
||||
return NULL;
|
||||
|
||||
// Diff declaration
|
||||
Diff_type.tp_new = PyType_GenericNew;
|
||||
Diff_type.tp_members = Diff_members;
|
||||
Diff_type.tp_init = (initproc)Diff_init;
|
||||
|
||||
if (PyType_Ready(&Diff_type) < 0)
|
||||
return NULL;
|
||||
|
||||
PyModule_AddObject(module, "PreciseDiff", (PyObject *)&Diff_type);
|
||||
|
||||
return module;
|
||||
}
|
@ -0,0 +1,358 @@
|
||||
import datetime
|
||||
import math
|
||||
import typing
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
from ..constants import DAY_OF_WEEK_TABLE
|
||||
from ..constants import DAYS_PER_L_YEAR
|
||||
from ..constants import DAYS_PER_MONTHS
|
||||
from ..constants import DAYS_PER_N_YEAR
|
||||
from ..constants import EPOCH_YEAR
|
||||
from ..constants import MONTHS_OFFSETS
|
||||
from ..constants import SECS_PER_4_YEARS
|
||||
from ..constants import SECS_PER_100_YEARS
|
||||
from ..constants import SECS_PER_400_YEARS
|
||||
from ..constants import SECS_PER_DAY
|
||||
from ..constants import SECS_PER_HOUR
|
||||
from ..constants import SECS_PER_MIN
|
||||
from ..constants import SECS_PER_YEAR
|
||||
from ..constants import TM_DECEMBER
|
||||
from ..constants import TM_JANUARY
|
||||
|
||||
|
||||
class PreciseDiff(
|
||||
namedtuple(
|
||||
"PreciseDiff",
|
||||
"years months days " "hours minutes seconds microseconds " "total_days",
|
||||
)
|
||||
):
|
||||
def __repr__(self):
|
||||
return (
|
||||
"{years} years "
|
||||
"{months} months "
|
||||
"{days} days "
|
||||
"{hours} hours "
|
||||
"{minutes} minutes "
|
||||
"{seconds} seconds "
|
||||
"{microseconds} microseconds"
|
||||
).format(
|
||||
years=self.years,
|
||||
months=self.months,
|
||||
days=self.days,
|
||||
hours=self.hours,
|
||||
minutes=self.minutes,
|
||||
seconds=self.seconds,
|
||||
microseconds=self.microseconds,
|
||||
)
|
||||
|
||||
|
||||
def is_leap(year): # type: (int) -> bool
|
||||
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
|
||||
|
||||
|
||||
def is_long_year(year): # type: (int) -> bool
|
||||
def p(y):
|
||||
return y + y // 4 - y // 100 + y // 400
|
||||
|
||||
return p(year) % 7 == 4 or p(year - 1) % 7 == 3
|
||||
|
||||
|
||||
def week_day(year, month, day): # type: (int, int, int) -> int
|
||||
if month < 3:
|
||||
year -= 1
|
||||
|
||||
w = (
|
||||
year
|
||||
+ year // 4
|
||||
- year // 100
|
||||
+ year // 400
|
||||
+ DAY_OF_WEEK_TABLE[month - 1]
|
||||
+ day
|
||||
) % 7
|
||||
|
||||
if not w:
|
||||
w = 7
|
||||
|
||||
return w
|
||||
|
||||
|
||||
def days_in_year(year): # type: (int) -> int
|
||||
if is_leap(year):
|
||||
return DAYS_PER_L_YEAR
|
||||
|
||||
return DAYS_PER_N_YEAR
|
||||
|
||||
|
||||
def timestamp(dt): # type: (datetime.datetime) -> int
|
||||
year = dt.year
|
||||
|
||||
result = (year - 1970) * 365 + MONTHS_OFFSETS[0][dt.month]
|
||||
result += (year - 1968) // 4
|
||||
result -= (year - 1900) // 100
|
||||
result += (year - 1600) // 400
|
||||
|
||||
if is_leap(year) and dt.month < 3:
|
||||
result -= 1
|
||||
|
||||
result += dt.day - 1
|
||||
result *= 24
|
||||
result += dt.hour
|
||||
result *= 60
|
||||
result += dt.minute
|
||||
result *= 60
|
||||
result += dt.second
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def local_time(
|
||||
unix_time, utc_offset, microseconds
|
||||
): # type: (int, int, int) -> typing.Tuple[int, int, int, int, int, int, int]
|
||||
"""
|
||||
Returns a UNIX time as a broken down time
|
||||
for a particular transition type.
|
||||
|
||||
:type unix_time: int
|
||||
:type utc_offset: int
|
||||
:type microseconds: int
|
||||
|
||||
:rtype: tuple
|
||||
"""
|
||||
year = EPOCH_YEAR
|
||||
seconds = int(math.floor(unix_time))
|
||||
|
||||
# Shift to a base year that is 400-year aligned.
|
||||
if seconds >= 0:
|
||||
seconds -= 10957 * SECS_PER_DAY
|
||||
year += 30 # == 2000
|
||||
else:
|
||||
seconds += (146097 - 10957) * SECS_PER_DAY
|
||||
year -= 370 # == 1600
|
||||
|
||||
seconds += utc_offset
|
||||
|
||||
# Handle years in chunks of 400/100/4/1
|
||||
year += 400 * (seconds // SECS_PER_400_YEARS)
|
||||
seconds %= SECS_PER_400_YEARS
|
||||
if seconds < 0:
|
||||
seconds += SECS_PER_400_YEARS
|
||||
year -= 400
|
||||
|
||||
leap_year = 1 # 4-century aligned
|
||||
|
||||
sec_per_100years = SECS_PER_100_YEARS[leap_year]
|
||||
while seconds >= sec_per_100years:
|
||||
seconds -= sec_per_100years
|
||||
year += 100
|
||||
leap_year = 0 # 1-century, non 4-century aligned
|
||||
sec_per_100years = SECS_PER_100_YEARS[leap_year]
|
||||
|
||||
sec_per_4years = SECS_PER_4_YEARS[leap_year]
|
||||
while seconds >= sec_per_4years:
|
||||
seconds -= sec_per_4years
|
||||
year += 4
|
||||
leap_year = 1 # 4-year, non century aligned
|
||||
sec_per_4years = SECS_PER_4_YEARS[leap_year]
|
||||
|
||||
sec_per_year = SECS_PER_YEAR[leap_year]
|
||||
while seconds >= sec_per_year:
|
||||
seconds -= sec_per_year
|
||||
year += 1
|
||||
leap_year = 0 # non 4-year aligned
|
||||
sec_per_year = SECS_PER_YEAR[leap_year]
|
||||
|
||||
# Handle months and days
|
||||
month = TM_DECEMBER + 1
|
||||
day = seconds // SECS_PER_DAY + 1
|
||||
seconds %= SECS_PER_DAY
|
||||
while month != TM_JANUARY + 1:
|
||||
month_offset = MONTHS_OFFSETS[leap_year][month]
|
||||
if day > month_offset:
|
||||
day -= month_offset
|
||||
break
|
||||
|
||||
month -= 1
|
||||
|
||||
# Handle hours, minutes, seconds and microseconds
|
||||
hour = seconds // SECS_PER_HOUR
|
||||
seconds %= SECS_PER_HOUR
|
||||
minute = seconds // SECS_PER_MIN
|
||||
second = seconds % SECS_PER_MIN
|
||||
|
||||
return (year, month, day, hour, minute, second, microseconds)
|
||||
|
||||
|
||||
def precise_diff(
|
||||
d1, d2
|
||||
): # type: (typing.Union[datetime.datetime, datetime.date], typing.Union[datetime.datetime, datetime.date]) -> PreciseDiff
|
||||
"""
|
||||
Calculate a precise difference between two datetimes.
|
||||
|
||||
:param d1: The first datetime
|
||||
:type d1: datetime.datetime or datetime.date
|
||||
|
||||
:param d2: The second datetime
|
||||
:type d2: datetime.datetime or datetime.date
|
||||
|
||||
:rtype: PreciseDiff
|
||||
"""
|
||||
sign = 1
|
||||
|
||||
if d1 == d2:
|
||||
return PreciseDiff(0, 0, 0, 0, 0, 0, 0, 0)
|
||||
|
||||
tzinfo1 = d1.tzinfo if isinstance(d1, datetime.datetime) else None
|
||||
tzinfo2 = d2.tzinfo if isinstance(d2, datetime.datetime) else None
|
||||
|
||||
if (
|
||||
tzinfo1 is None
|
||||
and tzinfo2 is not None
|
||||
or tzinfo2 is None
|
||||
and tzinfo1 is not None
|
||||
):
|
||||
raise ValueError(
|
||||
"Comparison between naive and aware datetimes is not supported"
|
||||
)
|
||||
|
||||
if d1 > d2:
|
||||
d1, d2 = d2, d1
|
||||
sign = -1
|
||||
|
||||
d_diff = 0
|
||||
hour_diff = 0
|
||||
min_diff = 0
|
||||
sec_diff = 0
|
||||
mic_diff = 0
|
||||
total_days = _day_number(d2.year, d2.month, d2.day) - _day_number(
|
||||
d1.year, d1.month, d1.day
|
||||
)
|
||||
in_same_tz = False
|
||||
tz1 = None
|
||||
tz2 = None
|
||||
|
||||
# Trying to figure out the timezone names
|
||||
# If we can't find them, we assume different timezones
|
||||
if tzinfo1 and tzinfo2:
|
||||
if hasattr(tzinfo1, "name"):
|
||||
# Pendulum timezone
|
||||
tz1 = tzinfo1.name
|
||||
elif hasattr(tzinfo1, "zone"):
|
||||
# pytz timezone
|
||||
tz1 = tzinfo1.zone
|
||||
|
||||
if hasattr(tzinfo2, "name"):
|
||||
tz2 = tzinfo2.name
|
||||
elif hasattr(tzinfo2, "zone"):
|
||||
tz2 = tzinfo2.zone
|
||||
|
||||
in_same_tz = tz1 == tz2 and tz1 is not None
|
||||
|
||||
if isinstance(d2, datetime.datetime):
|
||||
if isinstance(d1, datetime.datetime):
|
||||
# If we are not in the same timezone
|
||||
# we need to adjust
|
||||
#
|
||||
# We also need to adjust if we do not
|
||||
# have variable-length units
|
||||
if not in_same_tz or total_days == 0:
|
||||
offset1 = d1.utcoffset()
|
||||
offset2 = d2.utcoffset()
|
||||
|
||||
if offset1:
|
||||
d1 = d1 - offset1
|
||||
|
||||
if offset2:
|
||||
d2 = d2 - offset2
|
||||
|
||||
hour_diff = d2.hour - d1.hour
|
||||
min_diff = d2.minute - d1.minute
|
||||
sec_diff = d2.second - d1.second
|
||||
mic_diff = d2.microsecond - d1.microsecond
|
||||
else:
|
||||
hour_diff = d2.hour
|
||||
min_diff = d2.minute
|
||||
sec_diff = d2.second
|
||||
mic_diff = d2.microsecond
|
||||
|
||||
if mic_diff < 0:
|
||||
mic_diff += 1000000
|
||||
sec_diff -= 1
|
||||
|
||||
if sec_diff < 0:
|
||||
sec_diff += 60
|
||||
min_diff -= 1
|
||||
|
||||
if min_diff < 0:
|
||||
min_diff += 60
|
||||
hour_diff -= 1
|
||||
|
||||
if hour_diff < 0:
|
||||
hour_diff += 24
|
||||
d_diff -= 1
|
||||
|
||||
y_diff = d2.year - d1.year
|
||||
m_diff = d2.month - d1.month
|
||||
d_diff += d2.day - d1.day
|
||||
|
||||
if d_diff < 0:
|
||||
year = d2.year
|
||||
month = d2.month
|
||||
|
||||
if month == 1:
|
||||
month = 12
|
||||
year -= 1
|
||||
else:
|
||||
month -= 1
|
||||
|
||||
leap = int(is_leap(year))
|
||||
|
||||
days_in_last_month = DAYS_PER_MONTHS[leap][month]
|
||||
days_in_month = DAYS_PER_MONTHS[int(is_leap(d2.year))][d2.month]
|
||||
|
||||
if d_diff < days_in_month - days_in_last_month:
|
||||
# We don't have a full month, we calculate days
|
||||
if days_in_last_month < d1.day:
|
||||
d_diff += d1.day
|
||||
else:
|
||||
d_diff += days_in_last_month
|
||||
elif d_diff == days_in_month - days_in_last_month:
|
||||
# We have exactly a full month
|
||||
# We remove the days difference
|
||||
# and add one to the months difference
|
||||
d_diff = 0
|
||||
m_diff += 1
|
||||
else:
|
||||
# We have a full month
|
||||
d_diff += days_in_last_month
|
||||
|
||||
m_diff -= 1
|
||||
|
||||
if m_diff < 0:
|
||||
m_diff += 12
|
||||
y_diff -= 1
|
||||
|
||||
return PreciseDiff(
|
||||
sign * y_diff,
|
||||
sign * m_diff,
|
||||
sign * d_diff,
|
||||
sign * hour_diff,
|
||||
sign * min_diff,
|
||||
sign * sec_diff,
|
||||
sign * mic_diff,
|
||||
sign * total_days,
|
||||
)
|
||||
|
||||
|
||||
def _day_number(year, month, day): # type: (int, int, int) -> int
|
||||
month = (month + 9) % 12
|
||||
year = year - month // 10
|
||||
|
||||
return (
|
||||
365 * year
|
||||
+ year // 4
|
||||
- year // 100
|
||||
+ year // 400
|
||||
+ (month * 306 + 5) // 10
|
||||
+ (day - 1)
|
||||
)
|
@ -0,0 +1,107 @@
|
||||
# The day constants
|
||||
SUNDAY = 0
|
||||
MONDAY = 1
|
||||
TUESDAY = 2
|
||||
WEDNESDAY = 3
|
||||
THURSDAY = 4
|
||||
FRIDAY = 5
|
||||
SATURDAY = 6
|
||||
|
||||
# Number of X in Y.
|
||||
YEARS_PER_CENTURY = 100
|
||||
YEARS_PER_DECADE = 10
|
||||
MONTHS_PER_YEAR = 12
|
||||
WEEKS_PER_YEAR = 52
|
||||
DAYS_PER_WEEK = 7
|
||||
HOURS_PER_DAY = 24
|
||||
MINUTES_PER_HOUR = 60
|
||||
SECONDS_PER_MINUTE = 60
|
||||
SECONDS_PER_HOUR = MINUTES_PER_HOUR * SECONDS_PER_MINUTE
|
||||
SECONDS_PER_DAY = HOURS_PER_DAY * SECONDS_PER_HOUR
|
||||
US_PER_SECOND = 1000000
|
||||
|
||||
# Formats
|
||||
ATOM = "YYYY-MM-DDTHH:mm:ssZ"
|
||||
COOKIE = "dddd, DD-MMM-YYYY HH:mm:ss zz"
|
||||
ISO8601 = "YYYY-MM-DDTHH:mm:ssZ"
|
||||
ISO8601_EXTENDED = "YYYY-MM-DDTHH:mm:ss.SSSSSSZ"
|
||||
RFC822 = "ddd, DD MMM YY HH:mm:ss ZZ"
|
||||
RFC850 = "dddd, DD-MMM-YY HH:mm:ss zz"
|
||||
RFC1036 = "ddd, DD MMM YY HH:mm:ss ZZ"
|
||||
RFC1123 = "ddd, DD MMM YYYY HH:mm:ss ZZ"
|
||||
RFC2822 = "ddd, DD MMM YYYY HH:mm:ss ZZ"
|
||||
RFC3339 = ISO8601
|
||||
RFC3339_EXTENDED = ISO8601_EXTENDED
|
||||
RSS = "ddd, DD MMM YYYY HH:mm:ss ZZ"
|
||||
W3C = ISO8601
|
||||
|
||||
|
||||
EPOCH_YEAR = 1970
|
||||
|
||||
DAYS_PER_N_YEAR = 365
|
||||
DAYS_PER_L_YEAR = 366
|
||||
|
||||
USECS_PER_SEC = 1000000
|
||||
|
||||
SECS_PER_MIN = 60
|
||||
SECS_PER_HOUR = 60 * SECS_PER_MIN
|
||||
SECS_PER_DAY = SECS_PER_HOUR * 24
|
||||
|
||||
# 400-year chunks always have 146097 days (20871 weeks).
|
||||
SECS_PER_400_YEARS = 146097 * SECS_PER_DAY
|
||||
|
||||
# The number of seconds in an aligned 100-year chunk, for those that
|
||||
# do not begin with a leap year and those that do respectively.
|
||||
SECS_PER_100_YEARS = (
|
||||
(76 * DAYS_PER_N_YEAR + 24 * DAYS_PER_L_YEAR) * SECS_PER_DAY,
|
||||
(75 * DAYS_PER_N_YEAR + 25 * DAYS_PER_L_YEAR) * SECS_PER_DAY,
|
||||
)
|
||||
|
||||
# The number of seconds in an aligned 4-year chunk, for those that
|
||||
# do not begin with a leap year and those that do respectively.
|
||||
SECS_PER_4_YEARS = (
|
||||
(4 * DAYS_PER_N_YEAR + 0 * DAYS_PER_L_YEAR) * SECS_PER_DAY,
|
||||
(3 * DAYS_PER_N_YEAR + 1 * DAYS_PER_L_YEAR) * SECS_PER_DAY,
|
||||
)
|
||||
|
||||
# The number of seconds in non-leap and leap years respectively.
|
||||
SECS_PER_YEAR = (DAYS_PER_N_YEAR * SECS_PER_DAY, DAYS_PER_L_YEAR * SECS_PER_DAY)
|
||||
|
||||
DAYS_PER_YEAR = (DAYS_PER_N_YEAR, DAYS_PER_L_YEAR)
|
||||
|
||||
# The month lengths in non-leap and leap years respectively.
|
||||
DAYS_PER_MONTHS = (
|
||||
(-1, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),
|
||||
(-1, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31),
|
||||
)
|
||||
|
||||
# The day offsets of the beginning of each (1-based) month in non-leap
|
||||
# and leap years respectively.
|
||||
# For example, in a leap year there are 335 days before December.
|
||||
MONTHS_OFFSETS = (
|
||||
(-1, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365),
|
||||
(-1, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366),
|
||||
)
|
||||
|
||||
DAY_OF_WEEK_TABLE = (0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4)
|
||||
|
||||
TM_SUNDAY = 0
|
||||
TM_MONDAY = 1
|
||||
TM_TUESDAY = 2
|
||||
TM_WEDNESDAY = 3
|
||||
TM_THURSDAY = 4
|
||||
TM_FRIDAY = 5
|
||||
TM_SATURDAY = 6
|
||||
|
||||
TM_JANUARY = 0
|
||||
TM_FEBRUARY = 1
|
||||
TM_MARCH = 2
|
||||
TM_APRIL = 3
|
||||
TM_MAY = 4
|
||||
TM_JUNE = 5
|
||||
TM_JULY = 6
|
||||
TM_AUGUST = 7
|
||||
TM_SEPTEMBER = 8
|
||||
TM_OCTOBER = 9
|
||||
TM_NOVEMBER = 10
|
||||
TM_DECEMBER = 11
|
@ -0,0 +1,891 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
|
||||
import calendar
|
||||
import math
|
||||
|
||||
from datetime import date
|
||||
from datetime import timedelta
|
||||
|
||||
import pendulum
|
||||
|
||||
from .constants import FRIDAY
|
||||
from .constants import MONDAY
|
||||
from .constants import MONTHS_PER_YEAR
|
||||
from .constants import SATURDAY
|
||||
from .constants import SUNDAY
|
||||
from .constants import THURSDAY
|
||||
from .constants import TUESDAY
|
||||
from .constants import WEDNESDAY
|
||||
from .constants import YEARS_PER_CENTURY
|
||||
from .constants import YEARS_PER_DECADE
|
||||
from .exceptions import PendulumException
|
||||
from .helpers import add_duration
|
||||
from .mixins.default import FormattableMixin
|
||||
from .period import Period
|
||||
|
||||
|
||||
class Date(FormattableMixin, date):
|
||||
|
||||
# Names of days of the week
|
||||
_days = {
|
||||
SUNDAY: "Sunday",
|
||||
MONDAY: "Monday",
|
||||
TUESDAY: "Tuesday",
|
||||
WEDNESDAY: "Wednesday",
|
||||
THURSDAY: "Thursday",
|
||||
FRIDAY: "Friday",
|
||||
SATURDAY: "Saturday",
|
||||
}
|
||||
|
||||
_MODIFIERS_VALID_UNITS = ["day", "week", "month", "year", "decade", "century"]
|
||||
|
||||
# Getters/Setters
|
||||
|
||||
def set(self, year=None, month=None, day=None):
|
||||
return self.replace(year=year, month=month, day=day)
|
||||
|
||||
@property
|
||||
def day_of_week(self):
|
||||
"""
|
||||
Returns the day of the week (0-6).
|
||||
|
||||
:rtype: int
|
||||
"""
|
||||
return self.isoweekday() % 7
|
||||
|
||||
@property
|
||||
def day_of_year(self):
|
||||
"""
|
||||
Returns the day of the year (1-366).
|
||||
|
||||
:rtype: int
|
||||
"""
|
||||
k = 1 if self.is_leap_year() else 2
|
||||
|
||||
return (275 * self.month) // 9 - k * ((self.month + 9) // 12) + self.day - 30
|
||||
|
||||
@property
|
||||
def week_of_year(self):
|
||||
return self.isocalendar()[1]
|
||||
|
||||
@property
|
||||
def days_in_month(self):
|
||||
return calendar.monthrange(self.year, self.month)[1]
|
||||
|
||||
@property
|
||||
def week_of_month(self):
|
||||
first_day_of_month = self.replace(day=1)
|
||||
|
||||
return self.week_of_year - first_day_of_month.week_of_year + 1
|
||||
|
||||
@property
|
||||
def age(self):
|
||||
return self.diff(abs=False).in_years()
|
||||
|
||||
@property
|
||||
def quarter(self):
|
||||
return int(math.ceil(self.month / 3))
|
||||
|
||||
# String Formatting
|
||||
|
||||
def to_date_string(self):
|
||||
"""
|
||||
Format the instance as date.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return self.strftime("%Y-%m-%d")
|
||||
|
||||
def to_formatted_date_string(self):
|
||||
"""
|
||||
Format the instance as a readable date.
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
return self.strftime("%b %d, %Y")
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
"{klass}("
|
||||
"{year}, {month}, {day}"
|
||||
")".format(
|
||||
klass=self.__class__.__name__,
|
||||
year=self.year,
|
||||
month=self.month,
|
||||
day=self.day,
|
||||
)
|
||||
)
|
||||
|
||||
# COMPARISONS
|
||||
|
||||
def closest(self, dt1, dt2):
|
||||
"""
|
||||
Get the closest date from the instance.
|
||||
|
||||
:type dt1: Date or date
|
||||
:type dt2: Date or date
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
dt1 = self.__class__(dt1.year, dt1.month, dt1.day)
|
||||
dt2 = self.__class__(dt2.year, dt2.month, dt2.day)
|
||||
|
||||
if self.diff(dt1).in_seconds() < self.diff(dt2).in_seconds():
|
||||
return dt1
|
||||
|
||||
return dt2
|
||||
|
||||
def farthest(self, dt1, dt2):
|
||||
"""
|
||||
Get the farthest date from the instance.
|
||||
|
||||
:type dt1: Date or date
|
||||
:type dt2: Date or date
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
dt1 = self.__class__(dt1.year, dt1.month, dt1.day)
|
||||
dt2 = self.__class__(dt2.year, dt2.month, dt2.day)
|
||||
|
||||
if self.diff(dt1).in_seconds() > self.diff(dt2).in_seconds():
|
||||
return dt1
|
||||
|
||||
return dt2
|
||||
|
||||
def is_future(self):
|
||||
"""
|
||||
Determines if the instance is in the future, ie. greater than now.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return self > self.today()
|
||||
|
||||
def is_past(self):
|
||||
"""
|
||||
Determines if the instance is in the past, ie. less than now.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return self < self.today()
|
||||
|
||||
def is_leap_year(self):
|
||||
"""
|
||||
Determines if the instance is a leap year.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return calendar.isleap(self.year)
|
||||
|
||||
def is_long_year(self):
|
||||
"""
|
||||
Determines if the instance is a long year
|
||||
|
||||
See link `<https://en.wikipedia.org/wiki/ISO_8601#Week_dates>`_
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return Date(self.year, 12, 28).isocalendar()[1] == 53
|
||||
|
||||
def is_same_day(self, dt):
|
||||
"""
|
||||
Checks if the passed in date is the same day as the instance current day.
|
||||
|
||||
:type dt: Date or date
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
return self == dt
|
||||
|
||||
def is_anniversary(self, dt=None):
|
||||
"""
|
||||
Check if its the anniversary.
|
||||
|
||||
Compares the date/month values of the two dates.
|
||||
|
||||
:rtype: bool
|
||||
"""
|
||||
if dt is None:
|
||||
dt = Date.today()
|
||||
|
||||
instance = self.__class__(dt.year, dt.month, dt.day)
|
||||
|
||||
return (self.month, self.day) == (instance.month, instance.day)
|
||||
|
||||
# the additional method for checking if today is the anniversary day
|
||||
# the alias is provided to start using a new name and keep the backward compatibility
|
||||
# the old name can be completely replaced with the new in one of the future versions
|
||||
is_birthday = is_anniversary
|
||||
|
||||
# ADDITIONS AND SUBSTRACTIONS
|
||||
|
||||
def add(self, years=0, months=0, weeks=0, days=0):
|
||||
"""
|
||||
Add duration to the instance.
|
||||
|
||||
:param years: The number of years
|
||||
:type years: int
|
||||
|
||||
:param months: The number of months
|
||||
:type months: int
|
||||
|
||||
:param weeks: The number of weeks
|
||||
:type weeks: int
|
||||
|
||||
:param days: The number of days
|
||||
:type days: int
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
dt = add_duration(
|
||||
date(self.year, self.month, self.day),
|
||||
years=years,
|
||||
months=months,
|
||||
weeks=weeks,
|
||||
days=days,
|
||||
)
|
||||
|
||||
return self.__class__(dt.year, dt.month, dt.day)
|
||||
|
||||
def subtract(self, years=0, months=0, weeks=0, days=0):
|
||||
"""
|
||||
Remove duration from the instance.
|
||||
|
||||
:param years: The number of years
|
||||
:type years: int
|
||||
|
||||
:param months: The number of months
|
||||
:type months: int
|
||||
|
||||
:param weeks: The number of weeks
|
||||
:type weeks: int
|
||||
|
||||
:param days: The number of days
|
||||
:type days: int
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self.add(years=-years, months=-months, weeks=-weeks, days=-days)
|
||||
|
||||
def _add_timedelta(self, delta):
|
||||
"""
|
||||
Add timedelta duration to the instance.
|
||||
|
||||
:param delta: The timedelta instance
|
||||
:type delta: pendulum.Duration or datetime.timedelta
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if isinstance(delta, pendulum.Duration):
|
||||
return self.add(
|
||||
years=delta.years,
|
||||
months=delta.months,
|
||||
weeks=delta.weeks,
|
||||
days=delta.remaining_days,
|
||||
)
|
||||
|
||||
return self.add(days=delta.days)
|
||||
|
||||
def _subtract_timedelta(self, delta):
|
||||
"""
|
||||
Remove timedelta duration from the instance.
|
||||
|
||||
:param delta: The timedelta instance
|
||||
:type delta: pendulum.Duration or datetime.timedelta
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if isinstance(delta, pendulum.Duration):
|
||||
return self.subtract(
|
||||
years=delta.years,
|
||||
months=delta.months,
|
||||
weeks=delta.weeks,
|
||||
days=delta.remaining_days,
|
||||
)
|
||||
|
||||
return self.subtract(days=delta.days)
|
||||
|
||||
def __add__(self, other):
|
||||
if not isinstance(other, timedelta):
|
||||
return NotImplemented
|
||||
|
||||
return self._add_timedelta(other)
|
||||
|
||||
def __sub__(self, other):
|
||||
if isinstance(other, timedelta):
|
||||
return self._subtract_timedelta(other)
|
||||
|
||||
if not isinstance(other, date):
|
||||
return NotImplemented
|
||||
|
||||
dt = self.__class__(other.year, other.month, other.day)
|
||||
|
||||
return dt.diff(self, False)
|
||||
|
||||
# DIFFERENCES
|
||||
|
||||
def diff(self, dt=None, abs=True):
|
||||
"""
|
||||
Returns the difference between two Date objects as a Period.
|
||||
|
||||
:type dt: Date or None
|
||||
|
||||
:param abs: Whether to return an absolute interval or not
|
||||
:type abs: bool
|
||||
|
||||
:rtype: Period
|
||||
"""
|
||||
if dt is None:
|
||||
dt = self.today()
|
||||
|
||||
return Period(self, Date(dt.year, dt.month, dt.day), absolute=abs)
|
||||
|
||||
def diff_for_humans(self, other=None, absolute=False, locale=None):
|
||||
"""
|
||||
Get the difference in a human readable format in the current locale.
|
||||
|
||||
When comparing a value in the past to default now:
|
||||
1 day ago
|
||||
5 months ago
|
||||
|
||||
When comparing a value in the future to default now:
|
||||
1 day from now
|
||||
5 months from now
|
||||
|
||||
When comparing a value in the past to another value:
|
||||
1 day before
|
||||
5 months before
|
||||
|
||||
When comparing a value in the future to another value:
|
||||
1 day after
|
||||
5 months after
|
||||
|
||||
:type other: Date
|
||||
|
||||
:param absolute: removes time difference modifiers ago, after, etc
|
||||
:type absolute: bool
|
||||
|
||||
:param locale: The locale to use for localization
|
||||
:type locale: str
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
is_now = other is None
|
||||
|
||||
if is_now:
|
||||
other = self.today()
|
||||
|
||||
diff = self.diff(other)
|
||||
|
||||
return pendulum.format_diff(diff, is_now, absolute, locale)
|
||||
|
||||
# MODIFIERS
|
||||
|
||||
def start_of(self, unit):
|
||||
"""
|
||||
Returns a copy of the instance with the time reset
|
||||
with the following rules:
|
||||
|
||||
* day: time to 00:00:00
|
||||
* week: date to first day of the week and time to 00:00:00
|
||||
* month: date to first day of the month and time to 00:00:00
|
||||
* year: date to first day of the year and time to 00:00:00
|
||||
* decade: date to first day of the decade and time to 00:00:00
|
||||
* century: date to first day of century and time to 00:00:00
|
||||
|
||||
:param unit: The unit to reset to
|
||||
:type unit: str
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if unit not in self._MODIFIERS_VALID_UNITS:
|
||||
raise ValueError('Invalid unit "{}" for start_of()'.format(unit))
|
||||
|
||||
return getattr(self, "_start_of_{}".format(unit))()
|
||||
|
||||
def end_of(self, unit):
|
||||
"""
|
||||
Returns a copy of the instance with the time reset
|
||||
with the following rules:
|
||||
|
||||
* week: date to last day of the week
|
||||
* month: date to last day of the month
|
||||
* year: date to last day of the year
|
||||
* decade: date to last day of the decade
|
||||
* century: date to last day of century
|
||||
|
||||
:param unit: The unit to reset to
|
||||
:type unit: str
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if unit not in self._MODIFIERS_VALID_UNITS:
|
||||
raise ValueError('Invalid unit "%s" for end_of()' % unit)
|
||||
|
||||
return getattr(self, "_end_of_%s" % unit)()
|
||||
|
||||
def _start_of_day(self):
|
||||
"""
|
||||
Compatibility method.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self
|
||||
|
||||
def _end_of_day(self):
|
||||
"""
|
||||
Compatibility method
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self
|
||||
|
||||
def _start_of_month(self):
|
||||
"""
|
||||
Reset the date to the first day of the month.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self.set(self.year, self.month, 1)
|
||||
|
||||
def _end_of_month(self):
|
||||
"""
|
||||
Reset the date to the last day of the month.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self.set(self.year, self.month, self.days_in_month)
|
||||
|
||||
def _start_of_year(self):
|
||||
"""
|
||||
Reset the date to the first day of the year.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self.set(self.year, 1, 1)
|
||||
|
||||
def _end_of_year(self):
|
||||
"""
|
||||
Reset the date to the last day of the year.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self.set(self.year, 12, 31)
|
||||
|
||||
def _start_of_decade(self):
|
||||
"""
|
||||
Reset the date to the first day of the decade.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
year = self.year - self.year % YEARS_PER_DECADE
|
||||
|
||||
return self.set(year, 1, 1)
|
||||
|
||||
def _end_of_decade(self):
|
||||
"""
|
||||
Reset the date to the last day of the decade.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
year = self.year - self.year % YEARS_PER_DECADE + YEARS_PER_DECADE - 1
|
||||
|
||||
return self.set(year, 12, 31)
|
||||
|
||||
def _start_of_century(self):
|
||||
"""
|
||||
Reset the date to the first day of the century.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
year = self.year - 1 - (self.year - 1) % YEARS_PER_CENTURY + 1
|
||||
|
||||
return self.set(year, 1, 1)
|
||||
|
||||
def _end_of_century(self):
|
||||
"""
|
||||
Reset the date to the last day of the century.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
year = self.year - 1 - (self.year - 1) % YEARS_PER_CENTURY + YEARS_PER_CENTURY
|
||||
|
||||
return self.set(year, 12, 31)
|
||||
|
||||
def _start_of_week(self):
|
||||
"""
|
||||
Reset the date to the first day of the week.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
dt = self
|
||||
|
||||
if self.day_of_week != pendulum._WEEK_STARTS_AT:
|
||||
dt = self.previous(pendulum._WEEK_STARTS_AT)
|
||||
|
||||
return dt.start_of("day")
|
||||
|
||||
def _end_of_week(self):
|
||||
"""
|
||||
Reset the date to the last day of the week.
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
dt = self
|
||||
|
||||
if self.day_of_week != pendulum._WEEK_ENDS_AT:
|
||||
dt = self.next(pendulum._WEEK_ENDS_AT)
|
||||
|
||||
return dt.end_of("day")
|
||||
|
||||
def next(self, day_of_week=None):
|
||||
"""
|
||||
Modify to the next occurrence of a given day of the week.
|
||||
If no day_of_week is provided, modify to the next occurrence
|
||||
of the current day of the week. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:param day_of_week: The next day of week to reset to.
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if day_of_week is None:
|
||||
day_of_week = self.day_of_week
|
||||
|
||||
if day_of_week < SUNDAY or day_of_week > SATURDAY:
|
||||
raise ValueError("Invalid day of week")
|
||||
|
||||
dt = self.add(days=1)
|
||||
while dt.day_of_week != day_of_week:
|
||||
dt = dt.add(days=1)
|
||||
|
||||
return dt
|
||||
|
||||
def previous(self, day_of_week=None):
|
||||
"""
|
||||
Modify to the previous occurrence of a given day of the week.
|
||||
If no day_of_week is provided, modify to the previous occurrence
|
||||
of the current day of the week. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:param day_of_week: The previous day of week to reset to.
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if day_of_week is None:
|
||||
day_of_week = self.day_of_week
|
||||
|
||||
if day_of_week < SUNDAY or day_of_week > SATURDAY:
|
||||
raise ValueError("Invalid day of week")
|
||||
|
||||
dt = self.subtract(days=1)
|
||||
while dt.day_of_week != day_of_week:
|
||||
dt = dt.subtract(days=1)
|
||||
|
||||
return dt
|
||||
|
||||
def first_of(self, unit, day_of_week=None):
|
||||
"""
|
||||
Returns an instance set to the first occurrence
|
||||
of a given day of the week in the current unit.
|
||||
If no day_of_week is provided, modify to the first day of the unit.
|
||||
Use the supplied consts to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
Supported units are month, quarter and year.
|
||||
|
||||
:param unit: The unit to use
|
||||
:type unit: str
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if unit not in ["month", "quarter", "year"]:
|
||||
raise ValueError('Invalid unit "{}" for first_of()'.format(unit))
|
||||
|
||||
return getattr(self, "_first_of_{}".format(unit))(day_of_week)
|
||||
|
||||
def last_of(self, unit, day_of_week=None):
|
||||
"""
|
||||
Returns an instance set to the last occurrence
|
||||
of a given day of the week in the current unit.
|
||||
If no day_of_week is provided, modify to the last day of the unit.
|
||||
Use the supplied consts to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
Supported units are month, quarter and year.
|
||||
|
||||
:param unit: The unit to use
|
||||
:type unit: str
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if unit not in ["month", "quarter", "year"]:
|
||||
raise ValueError('Invalid unit "{}" for first_of()'.format(unit))
|
||||
|
||||
return getattr(self, "_last_of_{}".format(unit))(day_of_week)
|
||||
|
||||
def nth_of(self, unit, nth, day_of_week):
|
||||
"""
|
||||
Returns a new instance set to the given occurrence
|
||||
of a given day of the week in the current unit.
|
||||
If the calculated occurrence is outside the scope of the current unit,
|
||||
then raise an error. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
Supported units are month, quarter and year.
|
||||
|
||||
:param unit: The unit to use
|
||||
:type unit: str
|
||||
|
||||
:type nth: int
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if unit not in ["month", "quarter", "year"]:
|
||||
raise ValueError('Invalid unit "{}" for first_of()'.format(unit))
|
||||
|
||||
dt = getattr(self, "_nth_of_{}".format(unit))(nth, day_of_week)
|
||||
if dt is False:
|
||||
raise PendulumException(
|
||||
"Unable to find occurence {} of {} in {}".format(
|
||||
nth, self._days[day_of_week], unit
|
||||
)
|
||||
)
|
||||
|
||||
return dt
|
||||
|
||||
def _first_of_month(self, day_of_week):
|
||||
"""
|
||||
Modify to the first occurrence of a given day of the week
|
||||
in the current month. If no day_of_week is provided,
|
||||
modify to the first day of the month. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:type day_of_week: int
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
dt = self
|
||||
|
||||
if day_of_week is None:
|
||||
return dt.set(day=1)
|
||||
|
||||
month = calendar.monthcalendar(dt.year, dt.month)
|
||||
|
||||
calendar_day = (day_of_week - 1) % 7
|
||||
|
||||
if month[0][calendar_day] > 0:
|
||||
day_of_month = month[0][calendar_day]
|
||||
else:
|
||||
day_of_month = month[1][calendar_day]
|
||||
|
||||
return dt.set(day=day_of_month)
|
||||
|
||||
def _last_of_month(self, day_of_week=None):
|
||||
"""
|
||||
Modify to the last occurrence of a given day of the week
|
||||
in the current month. If no day_of_week is provided,
|
||||
modify to the last day of the month. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
dt = self
|
||||
|
||||
if day_of_week is None:
|
||||
return dt.set(day=self.days_in_month)
|
||||
|
||||
month = calendar.monthcalendar(dt.year, dt.month)
|
||||
|
||||
calendar_day = (day_of_week - 1) % 7
|
||||
|
||||
if month[-1][calendar_day] > 0:
|
||||
day_of_month = month[-1][calendar_day]
|
||||
else:
|
||||
day_of_month = month[-2][calendar_day]
|
||||
|
||||
return dt.set(day=day_of_month)
|
||||
|
||||
def _nth_of_month(self, nth, day_of_week):
|
||||
"""
|
||||
Modify to the given occurrence of a given day of the week
|
||||
in the current month. If the calculated occurrence is outside,
|
||||
the scope of the current month, then return False and no
|
||||
modifications are made. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:type nth: int
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if nth == 1:
|
||||
return self.first_of("month", day_of_week)
|
||||
|
||||
dt = self.first_of("month")
|
||||
check = dt.format("YYYY-MM")
|
||||
for i in range(nth - (1 if dt.day_of_week == day_of_week else 0)):
|
||||
dt = dt.next(day_of_week)
|
||||
|
||||
if dt.format("YYYY-MM") == check:
|
||||
return self.set(day=dt.day)
|
||||
|
||||
return False
|
||||
|
||||
def _first_of_quarter(self, day_of_week=None):
|
||||
"""
|
||||
Modify to the first occurrence of a given day of the week
|
||||
in the current quarter. If no day_of_week is provided,
|
||||
modify to the first day of the quarter. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self.set(self.year, self.quarter * 3 - 2, 1).first_of(
|
||||
"month", day_of_week
|
||||
)
|
||||
|
||||
def _last_of_quarter(self, day_of_week=None):
|
||||
"""
|
||||
Modify to the last occurrence of a given day of the week
|
||||
in the current quarter. If no day_of_week is provided,
|
||||
modify to the last day of the quarter. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self.set(self.year, self.quarter * 3, 1).last_of("month", day_of_week)
|
||||
|
||||
def _nth_of_quarter(self, nth, day_of_week):
|
||||
"""
|
||||
Modify to the given occurrence of a given day of the week
|
||||
in the current quarter. If the calculated occurrence is outside,
|
||||
the scope of the current quarter, then return False and no
|
||||
modifications are made. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:type nth: int
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if nth == 1:
|
||||
return self.first_of("quarter", day_of_week)
|
||||
|
||||
dt = self.replace(self.year, self.quarter * 3, 1)
|
||||
last_month = dt.month
|
||||
year = dt.year
|
||||
dt = dt.first_of("quarter")
|
||||
for i in range(nth - (1 if dt.day_of_week == day_of_week else 0)):
|
||||
dt = dt.next(day_of_week)
|
||||
|
||||
if last_month < dt.month or year != dt.year:
|
||||
return False
|
||||
|
||||
return self.set(self.year, dt.month, dt.day)
|
||||
|
||||
def _first_of_year(self, day_of_week=None):
|
||||
"""
|
||||
Modify to the first occurrence of a given day of the week
|
||||
in the current year. If no day_of_week is provided,
|
||||
modify to the first day of the year. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self.set(month=1).first_of("month", day_of_week)
|
||||
|
||||
def _last_of_year(self, day_of_week=None):
|
||||
"""
|
||||
Modify to the last occurrence of a given day of the week
|
||||
in the current year. If no day_of_week is provided,
|
||||
modify to the last day of the year. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
return self.set(month=MONTHS_PER_YEAR).last_of("month", day_of_week)
|
||||
|
||||
def _nth_of_year(self, nth, day_of_week):
|
||||
"""
|
||||
Modify to the given occurrence of a given day of the week
|
||||
in the current year. If the calculated occurrence is outside,
|
||||
the scope of the current year, then return False and no
|
||||
modifications are made. Use the supplied consts
|
||||
to indicate the desired day_of_week, ex. pendulum.MONDAY.
|
||||
|
||||
:type nth: int
|
||||
|
||||
:type day_of_week: int or None
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if nth == 1:
|
||||
return self.first_of("year", day_of_week)
|
||||
|
||||
dt = self.first_of("year")
|
||||
year = dt.year
|
||||
for i in range(nth - (1 if dt.day_of_week == day_of_week else 0)):
|
||||
dt = dt.next(day_of_week)
|
||||
|
||||
if year != dt.year:
|
||||
return False
|
||||
|
||||
return self.set(self.year, dt.month, dt.day)
|
||||
|
||||
def average(self, dt=None):
|
||||
"""
|
||||
Modify the current instance to the average
|
||||
of a given instance (default now) and the current instance.
|
||||
|
||||
:type dt: Date or date
|
||||
|
||||
:rtype: Date
|
||||
"""
|
||||
if dt is None:
|
||||
dt = Date.today()
|
||||
|
||||
return self.add(days=int(self.diff(dt, False).in_days() / 2))
|
||||
|
||||
# Native methods override
|
||||
|
||||
@classmethod
|
||||
def today(cls):
|
||||
return pendulum.today().date()
|
||||
|
||||
@classmethod
|
||||
def fromtimestamp(cls, t):
|
||||
dt = super(Date, cls).fromtimestamp(t)
|
||||
|
||||
return cls(dt.year, dt.month, dt.day)
|
||||
|
||||
@classmethod
|
||||
def fromordinal(cls, n):
|
||||
dt = super(Date, cls).fromordinal(n)
|
||||
|
||||
return cls(dt.year, dt.month, dt.day)
|
||||
|
||||
def replace(self, year=None, month=None, day=None):
|
||||
year = year if year is not None else self.year
|
||||
month = month if month is not None else self.month
|
||||
day = day if day is not None else self.day
|
||||
|
||||
return self.__class__(year, month, day)
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,479 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
|
||||
from datetime import timedelta
|
||||
|
||||
import pendulum
|
||||
|
||||
from pendulum.utils._compat import PYPY
|
||||
from pendulum.utils._compat import decode
|
||||
|
||||
from .constants import SECONDS_PER_DAY
|
||||
from .constants import SECONDS_PER_HOUR
|
||||
from .constants import SECONDS_PER_MINUTE
|
||||
from .constants import US_PER_SECOND
|
||||
|
||||
|
||||
def _divide_and_round(a, b):
|
||||
"""divide a by b and round result to the nearest integer
|
||||
|
||||
When the ratio is exactly half-way between two integers,
|
||||
the even integer is returned.
|
||||
"""
|
||||
# Based on the reference implementation for divmod_near
|
||||
# in Objects/longobject.c.
|
||||
q, r = divmod(a, b)
|
||||
# round up if either r / b > 0.5, or r / b == 0.5 and q is odd.
|
||||
# The expression r / b > 0.5 is equivalent to 2 * r > b if b is
|
||||
# positive, 2 * r < b if b negative.
|
||||
r *= 2
|
||||
greater_than_half = r > b if b > 0 else r < b
|
||||
if greater_than_half or r == b and q % 2 == 1:
|
||||
q += 1
|
||||
|
||||
return q
|
||||
|
||||
|
||||
class Duration(timedelta):
|
||||
"""
|
||||
Replacement for the standard timedelta class.
|
||||
|
||||
Provides several improvements over the base class.
|
||||
"""
|
||||
|
||||
_y = None
|
||||
_m = None
|
||||
_w = None
|
||||
_d = None
|
||||
_h = None
|
||||
_i = None
|
||||
_s = None
|
||||
_invert = None
|
||||
|
||||
def __new__(
|
||||
cls,
|
||||
days=0,
|
||||
seconds=0,
|
||||
microseconds=0,
|
||||
milliseconds=0,
|
||||
minutes=0,
|
||||
hours=0,
|
||||
weeks=0,
|
||||
years=0,
|
||||
months=0,
|
||||
):
|
||||
if not isinstance(years, int) or not isinstance(months, int):
|
||||
raise ValueError("Float year and months are not supported")
|
||||
|
||||
self = timedelta.__new__(
|
||||
cls,
|
||||
days + years * 365 + months * 30,
|
||||
seconds,
|
||||
microseconds,
|
||||
milliseconds,
|
||||
minutes,
|
||||
hours,
|
||||
weeks,
|
||||
)
|
||||
|
||||
# Intuitive normalization
|
||||
total = self.total_seconds() - (years * 365 + months * 30) * SECONDS_PER_DAY
|
||||
self._total = total
|
||||
|
||||
m = 1
|
||||
if total < 0:
|
||||
m = -1
|
||||
|
||||
self._microseconds = round(total % m * 1e6)
|
||||
self._seconds = abs(int(total)) % SECONDS_PER_DAY * m
|
||||
|
||||
_days = abs(int(total)) // SECONDS_PER_DAY * m
|
||||
self._days = _days
|
||||
self._remaining_days = abs(_days) % 7 * m
|
||||
self._weeks = abs(_days) // 7 * m
|
||||
self._months = months
|
||||
self._years = years
|
||||
|
||||
return self
|
||||
|
||||
def total_minutes(self):
|
||||
return self.total_seconds() / SECONDS_PER_MINUTE
|
||||
|
||||
def total_hours(self):
|
||||
return self.total_seconds() / SECONDS_PER_HOUR
|
||||
|
||||
def total_days(self):
|
||||
return self.total_seconds() / SECONDS_PER_DAY
|
||||
|
||||
def total_weeks(self):
|
||||
return self.total_days() / 7
|
||||
|
||||
if PYPY:
|
||||
|
||||
def total_seconds(self):
|
||||
days = 0
|
||||
|
||||
if hasattr(self, "_years"):
|
||||
days += self._years * 365
|
||||
|
||||
if hasattr(self, "_months"):
|
||||
days += self._months * 30
|
||||
|
||||
if hasattr(self, "_remaining_days"):
|
||||
days += self._weeks * 7 + self._remaining_days
|
||||
else:
|
||||
days += self._days
|
||||
|
||||
return (
|
||||
(days * SECONDS_PER_DAY + self._seconds) * US_PER_SECOND
|
||||
+ self._microseconds
|
||||
) / US_PER_SECOND
|
||||
|
||||
@property
|
||||
def years(self):
|
||||
return self._years
|
||||
|
||||
@property
|
||||
def months(self):
|
||||
return self._months
|
||||
|
||||
@property
|
||||
def weeks(self):
|
||||
return self._weeks
|
||||
|
||||
if PYPY:
|
||||
|
||||
@property
|
||||
def days(self):
|
||||
return self._years * 365 + self._months * 30 + self._days
|
||||
|
||||
@property
|
||||
def remaining_days(self):
|
||||
return self._remaining_days
|
||||
|
||||
@property
|
||||
def hours(self):
|
||||
if self._h is None:
|
||||
seconds = self._seconds
|
||||
self._h = 0
|
||||
if abs(seconds) >= 3600:
|
||||
self._h = (abs(seconds) // 3600 % 24) * self._sign(seconds)
|
||||
|
||||
return self._h
|
||||
|
||||
@property
|
||||
def minutes(self):
|
||||
if self._i is None:
|
||||
seconds = self._seconds
|
||||
self._i = 0
|
||||
if abs(seconds) >= 60:
|
||||
self._i = (abs(seconds) // 60 % 60) * self._sign(seconds)
|
||||
|
||||
return self._i
|
||||
|
||||
@property
|
||||
def seconds(self):
|
||||
return self._seconds
|
||||
|
||||
@property
|
||||
def remaining_seconds(self):
|
||||
if self._s is None:
|
||||
self._s = self._seconds
|
||||
self._s = abs(self._s) % 60 * self._sign(self._s)
|
||||
|
||||
return self._s
|
||||
|
||||
@property
|
||||
def microseconds(self):
|
||||
return self._microseconds
|
||||
|
||||
@property
|
||||
def invert(self):
|
||||
if self._invert is None:
|
||||
self._invert = self.total_seconds() < 0
|
||||
|
||||
return self._invert
|
||||
|
||||
def in_weeks(self):
|
||||
return int(self.total_weeks())
|
||||
|
||||
def in_days(self):
|
||||
return int(self.total_days())
|
||||
|
||||
def in_hours(self):
|
||||
return int(self.total_hours())
|
||||
|
||||
def in_minutes(self):
|
||||
return int(self.total_minutes())
|
||||
|
||||
def in_seconds(self):
|
||||
return int(self.total_seconds())
|
||||
|
||||
def in_words(self, locale=None, separator=" "):
|
||||
"""
|
||||
Get the current interval in words in the current locale.
|
||||
|
||||
Ex: 6 jours 23 heures 58 minutes
|
||||
|
||||
:param locale: The locale to use. Defaults to current locale.
|
||||
:type locale: str
|
||||
|
||||
:param separator: The separator to use between each unit
|
||||
:type separator: str
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
periods = [
|
||||
("year", self.years),
|
||||
("month", self.months),
|
||||
("week", self.weeks),
|
||||
("day", self.remaining_days),
|
||||
("hour", self.hours),
|
||||
("minute", self.minutes),
|
||||
("second", self.remaining_seconds),
|
||||
]
|
||||
|
||||
if locale is None:
|
||||
locale = pendulum.get_locale()
|
||||
|
||||
locale = pendulum.locale(locale)
|
||||
parts = []
|
||||
for period in periods:
|
||||
unit, count = period
|
||||
if abs(count) > 0:
|
||||
translation = locale.translation(
|
||||
"units.{}.{}".format(unit, locale.plural(abs(count)))
|
||||
)
|
||||
parts.append(translation.format(count))
|
||||
|
||||
if not parts:
|
||||
if abs(self.microseconds) > 0:
|
||||
unit = "units.second.{}".format(locale.plural(1))
|
||||
count = "{:.2f}".format(abs(self.microseconds) / 1e6)
|
||||
else:
|
||||
unit = "units.microsecond.{}".format(locale.plural(0))
|
||||
count = 0
|
||||
translation = locale.translation(unit)
|
||||
parts.append(translation.format(count))
|
||||
|
||||
return decode(separator.join(parts))
|
||||
|
||||
def _sign(self, value):
|
||||
if value < 0:
|
||||
return -1
|
||||
|
||||
return 1
|
||||
|
||||
def as_timedelta(self):
|
||||
"""
|
||||
Return the interval as a native timedelta.
|
||||
|
||||
:rtype: timedelta
|
||||
"""
|
||||
return timedelta(seconds=self.total_seconds())
|
||||
|
||||
def __str__(self):
|
||||
return self.in_words()
|
||||
|
||||
def __repr__(self):
|
||||
rep = "{}(".format(self.__class__.__name__)
|
||||
|
||||
if self._years:
|
||||
rep += "years={}, ".format(self._years)
|
||||
|
||||
if self._months:
|
||||
rep += "months={}, ".format(self._months)
|
||||
|
||||
if self._weeks:
|
||||
rep += "weeks={}, ".format(self._weeks)
|
||||
|
||||
if self._days:
|
||||
rep += "days={}, ".format(self._remaining_days)
|
||||
|
||||
if self.hours:
|
||||
rep += "hours={}, ".format(self.hours)
|
||||
|
||||
if self.minutes:
|
||||
rep += "minutes={}, ".format(self.minutes)
|
||||
|
||||
if self.remaining_seconds:
|
||||
rep += "seconds={}, ".format(self.remaining_seconds)
|
||||
|
||||
if self.microseconds:
|
||||
rep += "microseconds={}, ".format(self.microseconds)
|
||||
|
||||
rep += ")"
|
||||
|
||||
return rep.replace(", )", ")")
|
||||
|
||||
def __add__(self, other):
|
||||
if isinstance(other, timedelta):
|
||||
return self.__class__(seconds=self.total_seconds() + other.total_seconds())
|
||||
|
||||
return NotImplemented
|
||||
|
||||
__radd__ = __add__
|
||||
|
||||
def __sub__(self, other):
|
||||
if isinstance(other, timedelta):
|
||||
return self.__class__(seconds=self.total_seconds() - other.total_seconds())
|
||||
|
||||
return NotImplemented
|
||||
|
||||
def __neg__(self):
|
||||
return self.__class__(
|
||||
years=-self._years,
|
||||
months=-self._months,
|
||||
weeks=-self._weeks,
|
||||
days=-self._remaining_days,
|
||||
seconds=-self._seconds,
|
||||
microseconds=-self._microseconds,
|
||||
)
|
||||
|
||||
def _to_microseconds(self):
|
||||
return (self._days * (24 * 3600) + self._seconds) * 1000000 + self._microseconds
|
||||
|
||||
def __mul__(self, other):
|
||||
if isinstance(other, int):
|
||||
return self.__class__(
|
||||
years=self._years * other,
|
||||
months=self._months * other,
|
||||
seconds=self._total * other,
|
||||
)
|
||||
|
||||
if isinstance(other, float):
|
||||
usec = self._to_microseconds()
|
||||
a, b = other.as_integer_ratio()
|
||||
|
||||
return self.__class__(0, 0, _divide_and_round(usec * a, b))
|
||||
|
||||
return NotImplemented
|
||||
|
||||
__rmul__ = __mul__
|
||||
|
||||
def __floordiv__(self, other):
|
||||
if not isinstance(other, (int, timedelta)):
|
||||
return NotImplemented
|
||||
|
||||
usec = self._to_microseconds()
|
||||
if isinstance(other, timedelta):
|
||||
return usec // other._to_microseconds()
|
||||
|
||||
if isinstance(other, int):
|
||||
return self.__class__(
|
||||
0,
|
||||
0,
|
||||
usec // other,
|
||||
years=self._years // other,
|
||||
months=self._months // other,
|
||||
)
|
||||
|
||||
def __truediv__(self, other):
|
||||
if not isinstance(other, (int, float, timedelta)):
|
||||
return NotImplemented
|
||||
|
||||
usec = self._to_microseconds()
|
||||
if isinstance(other, timedelta):
|
||||
return usec / other._to_microseconds()
|
||||
|
||||
if isinstance(other, int):
|
||||
return self.__class__(
|
||||
0,
|
||||
0,
|
||||
_divide_and_round(usec, other),
|
||||
years=_divide_and_round(self._years, other),
|
||||
months=_divide_and_round(self._months, other),
|
||||
)
|
||||
|
||||
if isinstance(other, float):
|
||||
a, b = other.as_integer_ratio()
|
||||
|
||||
return self.__class__(
|
||||
0,
|
||||
0,
|
||||
_divide_and_round(b * usec, a),
|
||||
years=_divide_and_round(self._years * b, a),
|
||||
months=_divide_and_round(self._months, other),
|
||||
)
|
||||
|
||||
__div__ = __floordiv__
|
||||
|
||||
def __mod__(self, other):
|
||||
if isinstance(other, timedelta):
|
||||
r = self._to_microseconds() % other._to_microseconds()
|
||||
|
||||
return self.__class__(0, 0, r)
|
||||
|
||||
return NotImplemented
|
||||
|
||||
def __divmod__(self, other):
|
||||
if isinstance(other, timedelta):
|
||||
q, r = divmod(self._to_microseconds(), other._to_microseconds())
|
||||
|
||||
return q, self.__class__(0, 0, r)
|
||||
|
||||
return NotImplemented
|
||||
|
||||
|
||||
Duration.min = Duration(days=-999999999)
|
||||
Duration.max = Duration(
|
||||
days=999999999, hours=23, minutes=59, seconds=59, microseconds=999999
|
||||
)
|
||||
Duration.resolution = Duration(microseconds=1)
|
||||
|
||||
|
||||
class AbsoluteDuration(Duration):
|
||||
"""
|
||||
Duration that expresses a time difference in absolute values.
|
||||
"""
|
||||
|
||||
def __new__(
|
||||
cls,
|
||||
days=0,
|
||||
seconds=0,
|
||||
microseconds=0,
|
||||
milliseconds=0,
|
||||
minutes=0,
|
||||
hours=0,
|
||||
weeks=0,
|
||||
years=0,
|
||||
months=0,
|
||||
):
|
||||
if not isinstance(years, int) or not isinstance(months, int):
|
||||
raise ValueError("Float year and months are not supported")
|
||||
|
||||
self = timedelta.__new__(
|
||||
cls, days, seconds, microseconds, milliseconds, minutes, hours, weeks
|
||||
)
|
||||
|
||||
# We need to compute the total_seconds() value
|
||||
# on a native timedelta object
|
||||
delta = timedelta(
|
||||
days, seconds, microseconds, milliseconds, minutes, hours, weeks
|
||||
)
|
||||
|
||||
# Intuitive normalization
|
||||
self._total = delta.total_seconds()
|
||||
total = abs(self._total)
|
||||
|
||||
self._microseconds = round(total % 1 * 1e6)
|
||||
self._seconds = int(total) % SECONDS_PER_DAY
|
||||
|
||||
days = int(total) // SECONDS_PER_DAY
|
||||
self._days = abs(days + years * 365 + months * 30)
|
||||
self._remaining_days = days % 7
|
||||
self._weeks = days // 7
|
||||
self._months = abs(months)
|
||||
self._years = abs(years)
|
||||
|
||||
return self
|
||||
|
||||
def total_seconds(self):
|
||||
return abs(self._total)
|
||||
|
||||
@property
|
||||
def invert(self):
|
||||
if self._invert is None:
|
||||
self._invert = self._total < 0
|
||||
|
||||
return self._invert
|
@ -0,0 +1,6 @@
|
||||
from .parsing.exceptions import ParserError # noqa
|
||||
|
||||
|
||||
class PendulumException(Exception):
|
||||
|
||||
pass
|
@ -0,0 +1,4 @@
|
||||
from .formatter import Formatter
|
||||
|
||||
|
||||
__all__ = ["Formatter"]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,153 @@
|
||||
import typing
|
||||
|
||||
import pendulum
|
||||
|
||||
from pendulum.utils._compat import decode
|
||||
|
||||
from ..locales.locale import Locale
|
||||
|
||||
|
||||
class DifferenceFormatter(object):
|
||||
"""
|
||||
Handles formatting differences in text.
|
||||
"""
|
||||
|
||||
def __init__(self, locale="en"):
|
||||
self._locale = Locale.load(locale)
|
||||
|
||||
def format(
|
||||
self, diff, is_now=True, absolute=False, locale=None
|
||||
): # type: (pendulum.Period, bool, bool, typing.Optional[str]) -> str
|
||||
"""
|
||||
Formats a difference.
|
||||
|
||||
:param diff: The difference to format
|
||||
:type diff: pendulum.period.Period
|
||||
|
||||
:param is_now: Whether the difference includes now
|
||||
:type is_now: bool
|
||||
|
||||
:param absolute: Whether it's an absolute difference or not
|
||||
:type absolute: bool
|
||||
|
||||
:param locale: The locale to use
|
||||
:type locale: str or None
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
if locale is None:
|
||||
locale = self._locale
|
||||
else:
|
||||
locale = Locale.load(locale)
|
||||
|
||||
count = diff.remaining_seconds
|
||||
|
||||
if diff.years > 0:
|
||||
unit = "year"
|
||||
count = diff.years
|
||||
|
||||
if diff.months > 6:
|
||||
count += 1
|
||||
elif diff.months == 11 and (diff.weeks * 7 + diff.remaining_days) > 15:
|
||||
unit = "year"
|
||||
count = 1
|
||||
elif diff.months > 0:
|
||||
unit = "month"
|
||||
count = diff.months
|
||||
|
||||
if (diff.weeks * 7 + diff.remaining_days) >= 27:
|
||||
count += 1
|
||||
elif diff.weeks > 0:
|
||||
unit = "week"
|
||||
count = diff.weeks
|
||||
|
||||
if diff.remaining_days > 3:
|
||||
count += 1
|
||||
elif diff.remaining_days > 0:
|
||||
unit = "day"
|
||||
count = diff.remaining_days
|
||||
|
||||
if diff.hours >= 22:
|
||||
count += 1
|
||||
elif diff.hours > 0:
|
||||
unit = "hour"
|
||||
count = diff.hours
|
||||
elif diff.minutes > 0:
|
||||
unit = "minute"
|
||||
count = diff.minutes
|
||||
elif 10 < diff.remaining_seconds <= 59:
|
||||
unit = "second"
|
||||
count = diff.remaining_seconds
|
||||
else:
|
||||
# We check if the "a few seconds" unit exists
|
||||
time = locale.get("custom.units.few_second")
|
||||
if time is not None:
|
||||
if absolute:
|
||||
return time
|
||||
|
||||
key = "custom"
|
||||
is_future = diff.invert
|
||||
if is_now:
|
||||
if is_future:
|
||||
key += ".from_now"
|
||||
else:
|
||||
key += ".ago"
|
||||
else:
|
||||
if is_future:
|
||||
key += ".after"
|
||||
else:
|
||||
key += ".before"
|
||||
|
||||
return locale.get(key).format(time)
|
||||
else:
|
||||
unit = "second"
|
||||
count = diff.remaining_seconds
|
||||
|
||||
if count == 0:
|
||||
count = 1
|
||||
|
||||
if absolute:
|
||||
key = "translations.units.{}".format(unit)
|
||||
else:
|
||||
is_future = diff.invert
|
||||
|
||||
if is_now:
|
||||
# Relative to now, so we can use
|
||||
# the CLDR data
|
||||
key = "translations.relative.{}".format(unit)
|
||||
|
||||
if is_future:
|
||||
key += ".future"
|
||||
else:
|
||||
key += ".past"
|
||||
else:
|
||||
# Absolute comparison
|
||||
# So we have to use the custom locale data
|
||||
|
||||
# Checking for special pluralization rules
|
||||
key = "custom.units_relative"
|
||||
if is_future:
|
||||
key += ".{}.future".format(unit)
|
||||
else:
|
||||
key += ".{}.past".format(unit)
|
||||
|
||||
trans = locale.get(key)
|
||||
if not trans:
|
||||
# No special rule
|
||||
time = locale.get(
|
||||
"translations.units.{}.{}".format(unit, locale.plural(count))
|
||||
).format(count)
|
||||
else:
|
||||
time = trans[locale.plural(count)].format(count)
|
||||
|
||||
key = "custom"
|
||||
if is_future:
|
||||
key += ".after"
|
||||
else:
|
||||
key += ".before"
|
||||
|
||||
return locale.get(key).format(decode(time))
|
||||
|
||||
key += ".{}".format(locale.plural(count))
|
||||
|
||||
return decode(locale.get(key).format(count))
|
@ -0,0 +1,685 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
import re
|
||||
import typing
|
||||
|
||||
import pendulum
|
||||
|
||||
from pendulum.locales.locale import Locale
|
||||
from pendulum.utils._compat import decode
|
||||
|
||||
|
||||
_MATCH_1 = r"\d"
|
||||
_MATCH_2 = r"\d\d"
|
||||
_MATCH_3 = r"\d{3}"
|
||||
_MATCH_4 = r"\d{4}"
|
||||
_MATCH_6 = r"[+-]?\d{6}"
|
||||
_MATCH_1_TO_2 = r"\d\d?"
|
||||
_MATCH_1_TO_2_LEFT_PAD = r"[0-9 ]\d?"
|
||||
_MATCH_1_TO_3 = r"\d{1,3}"
|
||||
_MATCH_1_TO_4 = r"\d{1,4}"
|
||||
_MATCH_1_TO_6 = r"[+-]?\d{1,6}"
|
||||
_MATCH_3_TO_4 = r"\d{3}\d?"
|
||||
_MATCH_5_TO_6 = r"\d{5}\d?"
|
||||
_MATCH_UNSIGNED = r"\d+"
|
||||
_MATCH_SIGNED = r"[+-]?\d+"
|
||||
_MATCH_OFFSET = r"[Zz]|[+-]\d\d:?\d\d"
|
||||
_MATCH_SHORT_OFFSET = r"[Zz]|[+-]\d\d(?::?\d\d)?"
|
||||
_MATCH_TIMESTAMP = r"[+-]?\d+(\.\d{1,6})?"
|
||||
_MATCH_WORD = (
|
||||
"(?i)[0-9]*"
|
||||
"['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+"
|
||||
r"|[\u0600-\u06FF/]+(\s*?[\u0600-\u06FF]+){1,2}"
|
||||
)
|
||||
_MATCH_TIMEZONE = "[A-Za-z0-9-+]+(/[A-Za-z0-9-+_]+)?"
|
||||
|
||||
|
||||
class Formatter:
|
||||
|
||||
_TOKENS = (
|
||||
r"\[([^\[]*)\]|\\(.)|"
|
||||
"("
|
||||
"Mo|MM?M?M?"
|
||||
"|Do|DDDo|DD?D?D?|ddd?d?|do?"
|
||||
"|E{1,4}"
|
||||
"|w[o|w]?|W[o|W]?|Qo?"
|
||||
"|YYYY|YY|Y"
|
||||
"|gg(ggg?)?|GG(GGG?)?"
|
||||
"|a|A"
|
||||
"|hh?|HH?|kk?"
|
||||
"|mm?|ss?|S{1,9}"
|
||||
"|x|X"
|
||||
"|zz?|ZZ?"
|
||||
"|LTS|LT|LL?L?L?"
|
||||
")"
|
||||
)
|
||||
|
||||
_FORMAT_RE = re.compile(_TOKENS)
|
||||
|
||||
_FROM_FORMAT_RE = re.compile(r"(?<!\\\[)" + _TOKENS + r"(?!\\\])")
|
||||
|
||||
_LOCALIZABLE_TOKENS = {
|
||||
"Qo": None,
|
||||
"MMMM": "months.wide",
|
||||
"MMM": "months.abbreviated",
|
||||
"Mo": None,
|
||||
"DDDo": None,
|
||||
"Do": lambda locale: tuple(
|
||||
r"\d+{}".format(o) for o in locale.get("custom.ordinal").values()
|
||||
),
|
||||
"dddd": "days.wide",
|
||||
"ddd": "days.abbreviated",
|
||||
"dd": "days.short",
|
||||
"do": None,
|
||||
"Wo": None,
|
||||
"wo": None,
|
||||
"A": lambda locale: (
|
||||
locale.translation("day_periods.am"),
|
||||
locale.translation("day_periods.pm"),
|
||||
),
|
||||
"a": lambda locale: (
|
||||
locale.translation("day_periods.am").lower(),
|
||||
locale.translation("day_periods.pm").lower(),
|
||||
),
|
||||
}
|
||||
|
||||
_TOKENS_RULES = {
|
||||
# Year
|
||||
"YYYY": lambda dt: "{:d}".format(dt.year),
|
||||
"YY": lambda dt: "{:d}".format(dt.year)[2:],
|
||||
"Y": lambda dt: "{:d}".format(dt.year),
|
||||
# Quarter
|
||||
"Q": lambda dt: "{:d}".format(dt.quarter),
|
||||
# Month
|
||||
"MM": lambda dt: "{:02d}".format(dt.month),
|
||||
"M": lambda dt: "{:d}".format(dt.month),
|
||||
# Day
|
||||
"DD": lambda dt: "{:02d}".format(dt.day),
|
||||
"D": lambda dt: "{:d}".format(dt.day),
|
||||
# Day of Year
|
||||
"DDDD": lambda dt: "{:03d}".format(dt.day_of_year),
|
||||
"DDD": lambda dt: "{:d}".format(dt.day_of_year),
|
||||
# Day of Week
|
||||
"d": lambda dt: "{:d}".format(dt.day_of_week),
|
||||
# Day of ISO Week
|
||||
"E": lambda dt: "{:d}".format(dt.isoweekday()),
|
||||
# Hour
|
||||
"HH": lambda dt: "{:02d}".format(dt.hour),
|
||||
"H": lambda dt: "{:d}".format(dt.hour),
|
||||
"hh": lambda dt: "{:02d}".format(dt.hour % 12 or 12),
|
||||
"h": lambda dt: "{:d}".format(dt.hour % 12 or 12),
|
||||
# Minute
|
||||
"mm": lambda dt: "{:02d}".format(dt.minute),
|
||||
"m": lambda dt: "{:d}".format(dt.minute),
|
||||
# Second
|
||||
"ss": lambda dt: "{:02d}".format(dt.second),
|
||||
"s": lambda dt: "{:d}".format(dt.second),
|
||||
# Fractional second
|
||||
"S": lambda dt: "{:01d}".format(dt.microsecond // 100000),
|
||||
"SS": lambda dt: "{:02d}".format(dt.microsecond // 10000),
|
||||
"SSS": lambda dt: "{:03d}".format(dt.microsecond // 1000),
|
||||
"SSSS": lambda dt: "{:04d}".format(dt.microsecond // 100),
|
||||
"SSSSS": lambda dt: "{:05d}".format(dt.microsecond // 10),
|
||||
"SSSSSS": lambda dt: "{:06d}".format(dt.microsecond),
|
||||
# Timestamp
|
||||
"X": lambda dt: "{:d}".format(dt.int_timestamp),
|
||||
"x": lambda dt: "{:d}".format(dt.int_timestamp * 1000 + dt.microsecond // 1000),
|
||||
# Timezone
|
||||
"zz": lambda dt: "{}".format(dt.tzname() if dt.tzinfo is not None else ""),
|
||||
"z": lambda dt: "{}".format(dt.timezone_name or ""),
|
||||
}
|
||||
|
||||
_DATE_FORMATS = {
|
||||
"LTS": "formats.time.full",
|
||||
"LT": "formats.time.short",
|
||||
"L": "formats.date.short",
|
||||
"LL": "formats.date.long",
|
||||
"LLL": "formats.datetime.long",
|
||||
"LLLL": "formats.datetime.full",
|
||||
}
|
||||
|
||||
_DEFAULT_DATE_FORMATS = {
|
||||
"LTS": "h:mm:ss A",
|
||||
"LT": "h:mm A",
|
||||
"L": "MM/DD/YYYY",
|
||||
"LL": "MMMM D, YYYY",
|
||||
"LLL": "MMMM D, YYYY h:mm A",
|
||||
"LLLL": "dddd, MMMM D, YYYY h:mm A",
|
||||
}
|
||||
|
||||
_REGEX_TOKENS = {
|
||||
"Y": _MATCH_SIGNED,
|
||||
"YY": (_MATCH_1_TO_2, _MATCH_2),
|
||||
"YYYY": (_MATCH_1_TO_4, _MATCH_4),
|
||||
"Q": _MATCH_1,
|
||||
"Qo": None,
|
||||
"M": _MATCH_1_TO_2,
|
||||
"MM": (_MATCH_1_TO_2, _MATCH_2),
|
||||
"MMM": _MATCH_WORD,
|
||||
"MMMM": _MATCH_WORD,
|
||||
"D": _MATCH_1_TO_2,
|
||||
"DD": (_MATCH_1_TO_2_LEFT_PAD, _MATCH_2),
|
||||
"DDD": _MATCH_1_TO_3,
|
||||
"DDDD": _MATCH_3,
|
||||
"dddd": _MATCH_WORD,
|
||||
"ddd": _MATCH_WORD,
|
||||
"dd": _MATCH_WORD,
|
||||
"d": _MATCH_1,
|
||||
"E": _MATCH_1,
|
||||
"Do": None,
|
||||
"H": _MATCH_1_TO_2,
|
||||
"HH": (_MATCH_1_TO_2, _MATCH_2),
|
||||
"h": _MATCH_1_TO_2,
|
||||
"hh": (_MATCH_1_TO_2, _MATCH_2),
|
||||
"m": _MATCH_1_TO_2,
|
||||
"mm": (_MATCH_1_TO_2, _MATCH_2),
|
||||
"s": _MATCH_1_TO_2,
|
||||
"ss": (_MATCH_1_TO_2, _MATCH_2),
|
||||
"S": (_MATCH_1_TO_3, _MATCH_1),
|
||||
"SS": (_MATCH_1_TO_3, _MATCH_2),
|
||||
"SSS": (_MATCH_1_TO_3, _MATCH_3),
|
||||
"SSSS": _MATCH_UNSIGNED,
|
||||
"SSSSS": _MATCH_UNSIGNED,
|
||||
"SSSSSS": _MATCH_UNSIGNED,
|
||||
"x": _MATCH_SIGNED,
|
||||
"X": _MATCH_TIMESTAMP,
|
||||
"ZZ": _MATCH_SHORT_OFFSET,
|
||||
"Z": _MATCH_OFFSET,
|
||||
"z": _MATCH_TIMEZONE,
|
||||
}
|
||||
|
||||
_PARSE_TOKENS = {
|
||||
"YYYY": lambda year: int(year),
|
||||
"YY": lambda year: int(year),
|
||||
"Q": lambda quarter: int(quarter),
|
||||
"MMMM": lambda month: month,
|
||||
"MMM": lambda month: month,
|
||||
"MM": lambda month: int(month),
|
||||
"M": lambda month: int(month),
|
||||
"DDDD": lambda day: int(day),
|
||||
"DDD": lambda day: int(day),
|
||||
"DD": lambda day: int(day),
|
||||
"D": lambda day: int(day),
|
||||
"dddd": lambda weekday: weekday,
|
||||
"ddd": lambda weekday: weekday,
|
||||
"dd": lambda weekday: weekday,
|
||||
"d": lambda weekday: int(weekday) % 7,
|
||||
"E": lambda weekday: int(weekday),
|
||||
"HH": lambda hour: int(hour),
|
||||
"H": lambda hour: int(hour),
|
||||
"hh": lambda hour: int(hour),
|
||||
"h": lambda hour: int(hour),
|
||||
"mm": lambda minute: int(minute),
|
||||
"m": lambda minute: int(minute),
|
||||
"ss": lambda second: int(second),
|
||||
"s": lambda second: int(second),
|
||||
"S": lambda us: int(us) * 100000,
|
||||
"SS": lambda us: int(us) * 10000,
|
||||
"SSS": lambda us: int(us) * 1000,
|
||||
"SSSS": lambda us: int(us) * 100,
|
||||
"SSSSS": lambda us: int(us) * 10,
|
||||
"SSSSSS": lambda us: int(us),
|
||||
"a": lambda meridiem: meridiem,
|
||||
"X": lambda ts: float(ts),
|
||||
"x": lambda ts: float(ts) / 1e3,
|
||||
"ZZ": str,
|
||||
"Z": str,
|
||||
"z": str,
|
||||
}
|
||||
|
||||
def format(
|
||||
self, dt, fmt, locale=None
|
||||
): # type: (pendulum.DateTime, str, typing.Optional[typing.Union[str, Locale]]) -> str
|
||||
"""
|
||||
Formats a DateTime instance with a given format and locale.
|
||||
|
||||
:param dt: The instance to format
|
||||
:type dt: pendulum.DateTime
|
||||
|
||||
:param fmt: The format to use
|
||||
:type fmt: str
|
||||
|
||||
:param locale: The locale to use
|
||||
:type locale: str or Locale or None
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
if not locale:
|
||||
locale = pendulum.get_locale()
|
||||
|
||||
locale = Locale.load(locale)
|
||||
|
||||
result = self._FORMAT_RE.sub(
|
||||
lambda m: m.group(1)
|
||||
if m.group(1)
|
||||
else m.group(2)
|
||||
if m.group(2)
|
||||
else self._format_token(dt, m.group(3), locale),
|
||||
fmt,
|
||||
)
|
||||
|
||||
return decode(result)
|
||||
|
||||
def _format_token(
|
||||
self, dt, token, locale
|
||||
): # type: (pendulum.DateTime, str, Locale) -> str
|
||||
"""
|
||||
Formats a DateTime instance with a given token and locale.
|
||||
|
||||
:param dt: The instance to format
|
||||
:type dt: pendulum.DateTime
|
||||
|
||||
:param token: The token to use
|
||||
:type token: str
|
||||
|
||||
:param locale: The locale to use
|
||||
:type locale: Locale
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
if token in self._DATE_FORMATS:
|
||||
fmt = locale.get("custom.date_formats.{}".format(token))
|
||||
if fmt is None:
|
||||
fmt = self._DEFAULT_DATE_FORMATS[token]
|
||||
|
||||
return self.format(dt, fmt, locale)
|
||||
|
||||
if token in self._LOCALIZABLE_TOKENS:
|
||||
return self._format_localizable_token(dt, token, locale)
|
||||
|
||||
if token in self._TOKENS_RULES:
|
||||
return self._TOKENS_RULES[token](dt)
|
||||
|
||||
# Timezone
|
||||
if token in ["ZZ", "Z"]:
|
||||
if dt.tzinfo is None:
|
||||
return ""
|
||||
|
||||
separator = ":" if token == "Z" else ""
|
||||
offset = dt.utcoffset() or datetime.timedelta()
|
||||
minutes = offset.total_seconds() / 60
|
||||
|
||||
if minutes >= 0:
|
||||
sign = "+"
|
||||
else:
|
||||
sign = "-"
|
||||
|
||||
hour, minute = divmod(abs(int(minutes)), 60)
|
||||
|
||||
return "{}{:02d}{}{:02d}".format(sign, hour, separator, minute)
|
||||
|
||||
def _format_localizable_token(
|
||||
self, dt, token, locale
|
||||
): # type: (pendulum.DateTime, str, Locale) -> str
|
||||
"""
|
||||
Formats a DateTime instance
|
||||
with a given localizable token and locale.
|
||||
|
||||
:param dt: The instance to format
|
||||
:type dt: pendulum.DateTime
|
||||
|
||||
:param token: The token to use
|
||||
:type token: str
|
||||
|
||||
:param locale: The locale to use
|
||||
:type locale: Locale
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
if token == "MMM":
|
||||
return locale.get("translations.months.abbreviated")[dt.month]
|
||||
elif token == "MMMM":
|
||||
return locale.get("translations.months.wide")[dt.month]
|
||||
elif token == "dd":
|
||||
return locale.get("translations.days.short")[dt.day_of_week]
|
||||
elif token == "ddd":
|
||||
return locale.get("translations.days.abbreviated")[dt.day_of_week]
|
||||
elif token == "dddd":
|
||||
return locale.get("translations.days.wide")[dt.day_of_week]
|
||||
elif token == "Do":
|
||||
return locale.ordinalize(dt.day)
|
||||
elif token == "do":
|
||||
return locale.ordinalize(dt.day_of_week)
|
||||
elif token == "Mo":
|
||||
return locale.ordinalize(dt.month)
|
||||
elif token == "Qo":
|
||||
return locale.ordinalize(dt.quarter)
|
||||
elif token == "wo":
|
||||
return locale.ordinalize(dt.week_of_year)
|
||||
elif token == "DDDo":
|
||||
return locale.ordinalize(dt.day_of_year)
|
||||
elif token == "A":
|
||||
key = "translations.day_periods"
|
||||
if dt.hour >= 12:
|
||||
key += ".pm"
|
||||
else:
|
||||
key += ".am"
|
||||
|
||||
return locale.get(key)
|
||||
else:
|
||||
return token
|
||||
|
||||
def parse(
|
||||
self,
|
||||
time, # type: str
|
||||
fmt, # type: str
|
||||
now, # type: pendulum.DateTime
|
||||
locale=None, # type: typing.Optional[str]
|
||||
): # type: (...) -> typing.Dict[str, typing.Any]
|
||||
"""
|
||||
Parses a time string matching a given format as a tuple.
|
||||
|
||||
:param time: The timestring
|
||||
:param fmt: The format
|
||||
:param now: The datetime to use as "now"
|
||||
:param locale: The locale to use
|
||||
|
||||
:return: The parsed elements
|
||||
"""
|
||||
escaped_fmt = re.escape(fmt)
|
||||
|
||||
tokens = self._FROM_FORMAT_RE.findall(escaped_fmt)
|
||||
if not tokens:
|
||||
return time
|
||||
|
||||
if not locale:
|
||||
locale = pendulum.get_locale()
|
||||
|
||||
locale = Locale.load(locale)
|
||||
|
||||
parsed = {
|
||||
"year": None,
|
||||
"month": None,
|
||||
"day": None,
|
||||
"hour": None,
|
||||
"minute": None,
|
||||
"second": None,
|
||||
"microsecond": None,
|
||||
"tz": None,
|
||||
"quarter": None,
|
||||
"day_of_week": None,
|
||||
"day_of_year": None,
|
||||
"meridiem": None,
|
||||
"timestamp": None,
|
||||
}
|
||||
|
||||
pattern = self._FROM_FORMAT_RE.sub(
|
||||
lambda m: self._replace_tokens(m.group(0), locale), escaped_fmt
|
||||
)
|
||||
|
||||
if not re.search("^" + pattern + "$", time):
|
||||
raise ValueError("String does not match format {}".format(fmt))
|
||||
|
||||
re.sub(pattern, lambda m: self._get_parsed_values(m, parsed, locale, now), time)
|
||||
|
||||
return self._check_parsed(parsed, now)
|
||||
|
||||
def _check_parsed(
|
||||
self, parsed, now
|
||||
): # type: (typing.Dict[str, typing.Any], pendulum.DateTime) -> typing.Dict[str, typing.Any]
|
||||
"""
|
||||
Checks validity of parsed elements.
|
||||
|
||||
:param parsed: The elements to parse.
|
||||
|
||||
:return: The validated elements.
|
||||
"""
|
||||
validated = {
|
||||
"year": parsed["year"],
|
||||
"month": parsed["month"],
|
||||
"day": parsed["day"],
|
||||
"hour": parsed["hour"],
|
||||
"minute": parsed["minute"],
|
||||
"second": parsed["second"],
|
||||
"microsecond": parsed["microsecond"],
|
||||
"tz": None,
|
||||
}
|
||||
|
||||
# If timestamp has been specified
|
||||
# we use it and don't go any further
|
||||
if parsed["timestamp"] is not None:
|
||||
str_us = str(parsed["timestamp"])
|
||||
if "." in str_us:
|
||||
microseconds = int("{}".format(str_us.split(".")[1].ljust(6, "0")))
|
||||
else:
|
||||
microseconds = 0
|
||||
|
||||
from pendulum.helpers import local_time
|
||||
|
||||
time = local_time(parsed["timestamp"], 0, microseconds)
|
||||
validated["year"] = time[0]
|
||||
validated["month"] = time[1]
|
||||
validated["day"] = time[2]
|
||||
validated["hour"] = time[3]
|
||||
validated["minute"] = time[4]
|
||||
validated["second"] = time[5]
|
||||
validated["microsecond"] = time[6]
|
||||
|
||||
return validated
|
||||
|
||||
if parsed["quarter"] is not None:
|
||||
if validated["year"] is not None:
|
||||
dt = pendulum.datetime(validated["year"], 1, 1)
|
||||
else:
|
||||
dt = now
|
||||
|
||||
dt = dt.start_of("year")
|
||||
|
||||
while dt.quarter != parsed["quarter"]:
|
||||
dt = dt.add(months=3)
|
||||
|
||||
validated["year"] = dt.year
|
||||
validated["month"] = dt.month
|
||||
validated["day"] = dt.day
|
||||
|
||||
if validated["year"] is None:
|
||||
validated["year"] = now.year
|
||||
|
||||
if parsed["day_of_year"] is not None:
|
||||
dt = pendulum.parse(
|
||||
"{}-{:>03d}".format(validated["year"], parsed["day_of_year"])
|
||||
)
|
||||
|
||||
validated["month"] = dt.month
|
||||
validated["day"] = dt.day
|
||||
|
||||
if parsed["day_of_week"] is not None:
|
||||
dt = pendulum.datetime(
|
||||
validated["year"],
|
||||
validated["month"] or now.month,
|
||||
validated["day"] or now.day,
|
||||
)
|
||||
dt = dt.start_of("week").subtract(days=1)
|
||||
dt = dt.next(parsed["day_of_week"])
|
||||
validated["year"] = dt.year
|
||||
validated["month"] = dt.month
|
||||
validated["day"] = dt.day
|
||||
|
||||
# Meridiem
|
||||
if parsed["meridiem"] is not None:
|
||||
# If the time is greater than 13:00:00
|
||||
# This is not valid
|
||||
if validated["hour"] is None:
|
||||
raise ValueError("Invalid Date")
|
||||
|
||||
t = (
|
||||
validated["hour"],
|
||||
validated["minute"],
|
||||
validated["second"],
|
||||
validated["microsecond"],
|
||||
)
|
||||
if t >= (13, 0, 0, 0):
|
||||
raise ValueError("Invalid date")
|
||||
|
||||
pm = parsed["meridiem"] == "pm"
|
||||
validated["hour"] %= 12
|
||||
if pm:
|
||||
validated["hour"] += 12
|
||||
|
||||
if validated["month"] is None:
|
||||
if parsed["year"] is not None:
|
||||
validated["month"] = parsed["month"] or 1
|
||||
else:
|
||||
validated["month"] = parsed["month"] or now.month
|
||||
|
||||
if validated["day"] is None:
|
||||
if parsed["year"] is not None or parsed["month"] is not None:
|
||||
validated["day"] = parsed["day"] or 1
|
||||
else:
|
||||
validated["day"] = parsed["day"] or now.day
|
||||
|
||||
for part in ["hour", "minute", "second", "microsecond"]:
|
||||
if validated[part] is None:
|
||||
validated[part] = 0
|
||||
|
||||
validated["tz"] = parsed["tz"]
|
||||
|
||||
return validated
|
||||
|
||||
def _get_parsed_values(
|
||||
self, m, parsed, locale, now
|
||||
): # type: (typing.Match[str], typing.Dict[str, typing.Any], Locale, pendulum.DateTime) -> None
|
||||
for token, index in m.re.groupindex.items():
|
||||
if token in self._LOCALIZABLE_TOKENS:
|
||||
self._get_parsed_locale_value(token, m.group(index), parsed, locale)
|
||||
else:
|
||||
self._get_parsed_value(token, m.group(index), parsed, now)
|
||||
|
||||
def _get_parsed_value(
|
||||
self, token, value, parsed, now
|
||||
): # type: (str, str, typing.Dict[str, typing.Any], pendulum.DateTime) -> None
|
||||
parsed_token = self._PARSE_TOKENS[token](value)
|
||||
|
||||
if "Y" in token:
|
||||
if token == "YY":
|
||||
parsed_token = now.year // 100 * 100 + parsed_token
|
||||
|
||||
parsed["year"] = parsed_token
|
||||
elif "Q" == token:
|
||||
parsed["quarter"] = parsed_token
|
||||
elif token in ["MM", "M"]:
|
||||
parsed["month"] = parsed_token
|
||||
elif token in ["DDDD", "DDD"]:
|
||||
parsed["day_of_year"] = parsed_token
|
||||
elif "D" in token:
|
||||
parsed["day"] = parsed_token
|
||||
elif "H" in token:
|
||||
parsed["hour"] = parsed_token
|
||||
elif token in ["hh", "h"]:
|
||||
if parsed_token > 12:
|
||||
raise ValueError("Invalid date")
|
||||
|
||||
parsed["hour"] = parsed_token
|
||||
elif "m" in token:
|
||||
parsed["minute"] = parsed_token
|
||||
elif "s" in token:
|
||||
parsed["second"] = parsed_token
|
||||
elif "S" in token:
|
||||
parsed["microsecond"] = parsed_token
|
||||
elif token in ["d", "E"]:
|
||||
parsed["day_of_week"] = parsed_token
|
||||
elif token in ["X", "x"]:
|
||||
parsed["timestamp"] = parsed_token
|
||||
elif token in ["ZZ", "Z"]:
|
||||
negative = True if value.startswith("-") else False
|
||||
tz = value[1:]
|
||||
if ":" not in tz:
|
||||
if len(tz) == 2:
|
||||
tz = "{}00".format(tz)
|
||||
|
||||
off_hour = tz[0:2]
|
||||
off_minute = tz[2:4]
|
||||
else:
|
||||
off_hour, off_minute = tz.split(":")
|
||||
|
||||
offset = ((int(off_hour) * 60) + int(off_minute)) * 60
|
||||
|
||||
if negative:
|
||||
offset = -1 * offset
|
||||
|
||||
parsed["tz"] = pendulum.timezone(offset)
|
||||
elif token == "z":
|
||||
# Full timezone
|
||||
if value not in pendulum.timezones:
|
||||
raise ValueError("Invalid date")
|
||||
|
||||
parsed["tz"] = pendulum.timezone(value)
|
||||
|
||||
def _get_parsed_locale_value(
|
||||
self, token, value, parsed, locale
|
||||
): # type: (str, str, typing.Dict[str, typing.Any], Locale) -> None
|
||||
if token == "MMMM":
|
||||
unit = "month"
|
||||
match = "months.wide"
|
||||
elif token == "MMM":
|
||||
unit = "month"
|
||||
match = "months.abbreviated"
|
||||
elif token == "Do":
|
||||
parsed["day"] = int(re.match(r"(\d+)", value).group(1))
|
||||
|
||||
return
|
||||
elif token == "dddd":
|
||||
unit = "day_of_week"
|
||||
match = "days.wide"
|
||||
elif token == "ddd":
|
||||
unit = "day_of_week"
|
||||
match = "days.abbreviated"
|
||||
elif token == "dd":
|
||||
unit = "day_of_week"
|
||||
match = "days.short"
|
||||
elif token in ["a", "A"]:
|
||||
valid_values = [
|
||||
locale.translation("day_periods.am"),
|
||||
locale.translation("day_periods.pm"),
|
||||
]
|
||||
|
||||
if token == "a":
|
||||
value = value.lower()
|
||||
valid_values = list(map(lambda x: x.lower(), valid_values))
|
||||
|
||||
if value not in valid_values:
|
||||
raise ValueError("Invalid date")
|
||||
|
||||
parsed["meridiem"] = ["am", "pm"][valid_values.index(value)]
|
||||
|
||||
return
|
||||
else:
|
||||
raise ValueError('Invalid token "{}"'.format(token))
|
||||
|
||||
parsed[unit] = locale.match_translation(match, value)
|
||||
if value is None:
|
||||
raise ValueError("Invalid date")
|
||||
|
||||
def _replace_tokens(self, token, locale): # type: (str, Locale) -> str
|
||||
if token.startswith("[") and token.endswith("]"):
|
||||
return token[1:-1]
|
||||
elif token.startswith("\\"):
|
||||
if len(token) == 2 and token[1] in {"[", "]"}:
|
||||
return ""
|
||||
|
||||
return token
|
||||
elif token not in self._REGEX_TOKENS and token not in self._LOCALIZABLE_TOKENS:
|
||||
raise ValueError("Unsupported token: {}".format(token))
|
||||
|
||||
if token in self._LOCALIZABLE_TOKENS:
|
||||
values = self._LOCALIZABLE_TOKENS[token]
|
||||
if callable(values):
|
||||
candidates = values(locale)
|
||||
else:
|
||||
candidates = tuple(
|
||||
locale.translation(self._LOCALIZABLE_TOKENS[token]).values()
|
||||
)
|
||||
else:
|
||||
candidates = self._REGEX_TOKENS[token]
|
||||
|
||||
if not candidates:
|
||||
raise ValueError("Unsupported token: {}".format(token))
|
||||
|
||||
if not isinstance(candidates, tuple):
|
||||
candidates = (candidates,)
|
||||
|
||||
pattern = "(?P<{}>{})".format(token, "|".join([decode(p) for p in candidates]))
|
||||
|
||||
return pattern
|
@ -0,0 +1,224 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
import os
|
||||
import struct
|
||||
|
||||
from contextlib import contextmanager
|
||||
from datetime import date
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
from math import copysign
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import Iterator
|
||||
from typing import Optional
|
||||
from typing import TypeVar
|
||||
from typing import overload
|
||||
|
||||
import pendulum
|
||||
|
||||
from .constants import DAYS_PER_MONTHS
|
||||
from .formatting.difference_formatter import DifferenceFormatter
|
||||
from .locales.locale import Locale
|
||||
|
||||
|
||||
if TYPE_CHECKING:
|
||||
# Prevent import cycles
|
||||
from .period import Period
|
||||
|
||||
with_extensions = os.getenv("PENDULUM_EXTENSIONS", "1") == "1"
|
||||
|
||||
_DT = TypeVar("_DT", bound=datetime)
|
||||
_D = TypeVar("_D", bound=date)
|
||||
|
||||
try:
|
||||
if not with_extensions or struct.calcsize("P") == 4:
|
||||
raise ImportError()
|
||||
|
||||
from ._extensions._helpers import local_time
|
||||
from ._extensions._helpers import precise_diff
|
||||
from ._extensions._helpers import is_leap
|
||||
from ._extensions._helpers import is_long_year
|
||||
from ._extensions._helpers import week_day
|
||||
from ._extensions._helpers import days_in_year
|
||||
from ._extensions._helpers import timestamp
|
||||
except ImportError:
|
||||
from ._extensions.helpers import local_time # noqa
|
||||
from ._extensions.helpers import precise_diff # noqa
|
||||
from ._extensions.helpers import is_leap # noqa
|
||||
from ._extensions.helpers import is_long_year # noqa
|
||||
from ._extensions.helpers import week_day # noqa
|
||||
from ._extensions.helpers import days_in_year # noqa
|
||||
from ._extensions.helpers import timestamp # noqa
|
||||
|
||||
|
||||
difference_formatter = DifferenceFormatter()
|
||||
|
||||
|
||||
@overload
|
||||
def add_duration(
|
||||
dt, # type: _DT
|
||||
years=0, # type: int
|
||||
months=0, # type: int
|
||||
weeks=0, # type: int
|
||||
days=0, # type: int
|
||||
hours=0, # type: int
|
||||
minutes=0, # type: int
|
||||
seconds=0, # type: int
|
||||
microseconds=0, # type: int
|
||||
): # type: (...) -> _DT
|
||||
pass
|
||||
|
||||
|
||||
@overload
|
||||
def add_duration(
|
||||
dt, # type: _D
|
||||
years=0, # type: int
|
||||
months=0, # type: int
|
||||
weeks=0, # type: int
|
||||
days=0, # type: int
|
||||
): # type: (...) -> _D
|
||||
pass
|
||||
|
||||
|
||||
def add_duration(
|
||||
dt,
|
||||
years=0,
|
||||
months=0,
|
||||
weeks=0,
|
||||
days=0,
|
||||
hours=0,
|
||||
minutes=0,
|
||||
seconds=0,
|
||||
microseconds=0,
|
||||
):
|
||||
"""
|
||||
Adds a duration to a date/datetime instance.
|
||||
"""
|
||||
days += weeks * 7
|
||||
|
||||
if (
|
||||
isinstance(dt, date)
|
||||
and not isinstance(dt, datetime)
|
||||
and any([hours, minutes, seconds, microseconds])
|
||||
):
|
||||
raise RuntimeError("Time elements cannot be added to a date instance.")
|
||||
|
||||
# Normalizing
|
||||
if abs(microseconds) > 999999:
|
||||
s = _sign(microseconds)
|
||||
div, mod = divmod(microseconds * s, 1000000)
|
||||
microseconds = mod * s
|
||||
seconds += div * s
|
||||
|
||||
if abs(seconds) > 59:
|
||||
s = _sign(seconds)
|
||||
div, mod = divmod(seconds * s, 60)
|
||||
seconds = mod * s
|
||||
minutes += div * s
|
||||
|
||||
if abs(minutes) > 59:
|
||||
s = _sign(minutes)
|
||||
div, mod = divmod(minutes * s, 60)
|
||||
minutes = mod * s
|
||||
hours += div * s
|
||||
|
||||
if abs(hours) > 23:
|
||||
s = _sign(hours)
|
||||
div, mod = divmod(hours * s, 24)
|
||||
hours = mod * s
|
||||
days += div * s
|
||||
|
||||
if abs(months) > 11:
|
||||
s = _sign(months)
|
||||
div, mod = divmod(months * s, 12)
|
||||
months = mod * s
|
||||
years += div * s
|
||||
|
||||
year = dt.year + years
|
||||
month = dt.month
|
||||
|
||||
if months:
|
||||
month += months
|
||||
if month > 12:
|
||||
year += 1
|
||||
month -= 12
|
||||
elif month < 1:
|
||||
year -= 1
|
||||
month += 12
|
||||
|
||||
day = min(DAYS_PER_MONTHS[int(is_leap(year))][month], dt.day)
|
||||
|
||||
dt = dt.replace(year=year, month=month, day=day)
|
||||
|
||||
return dt + timedelta(
|
||||
days=days,
|
||||
hours=hours,
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
microseconds=microseconds,
|
||||
)
|
||||
|
||||
|
||||
def format_diff(
|
||||
diff, is_now=True, absolute=False, locale=None
|
||||
): # type: (Period, bool, bool, Optional[str]) -> str
|
||||
if locale is None:
|
||||
locale = get_locale()
|
||||
|
||||
return difference_formatter.format(diff, is_now, absolute, locale)
|
||||
|
||||
|
||||
def _sign(x):
|
||||
return int(copysign(1, x))
|
||||
|
||||
|
||||
# Global helpers
|
||||
|
||||
|
||||
@contextmanager
|
||||
def test(mock): # type: (pendulum.DateTime) -> Iterator[None]
|
||||
set_test_now(mock)
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
set_test_now()
|
||||
|
||||
|
||||
def set_test_now(test_now=None): # type: (Optional[pendulum.DateTime]) -> None
|
||||
pendulum._TEST_NOW = test_now
|
||||
|
||||
|
||||
def get_test_now(): # type: () -> Optional[pendulum.DateTime]
|
||||
return pendulum._TEST_NOW
|
||||
|
||||
|
||||
def has_test_now(): # type: () -> bool
|
||||
return pendulum._TEST_NOW is not None
|
||||
|
||||
|
||||
def locale(name): # type: (str) -> Locale
|
||||
return Locale.load(name)
|
||||
|
||||
|
||||
def set_locale(name): # type: (str) -> None
|
||||
locale(name)
|
||||
|
||||
pendulum._LOCALE = name
|
||||
|
||||
|
||||
def get_locale(): # type: () -> str
|
||||
return pendulum._LOCALE
|
||||
|
||||
|
||||
def week_starts_at(wday): # type: (int) -> None
|
||||
if wday < pendulum.SUNDAY or wday > pendulum.SATURDAY:
|
||||
raise ValueError("Invalid week day as start of week.")
|
||||
|
||||
pendulum._WEEK_STARTS_AT = wday
|
||||
|
||||
|
||||
def week_ends_at(wday): # type: (int) -> None
|
||||
if wday < pendulum.SUNDAY or wday > pendulum.SATURDAY:
|
||||
raise ValueError("Invalid week day as start of week.")
|
||||
|
||||
pendulum._WEEK_ENDS_AT = wday
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
"""
|
||||
da custom locale file.
|
||||
"""
|
||||
|
||||
translations = {
|
||||
# Relative time
|
||||
"after": "{0} efter",
|
||||
"before": "{0} før",
|
||||
# Date formats
|
||||
"date_formats": {
|
||||
"LTS": "HH:mm:ss",
|
||||
"LT": "HH:mm",
|
||||
"LLLL": "dddd [d.] D. MMMM YYYY HH:mm",
|
||||
"LLL": "D. MMMM YYYY HH:mm",
|
||||
"LL": "D. MMMM YYYY",
|
||||
"L": "DD/MM/YYYY",
|
||||
},
|
||||
}
|
@ -0,0 +1,150 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .custom import translations as custom_translations
|
||||
|
||||
|
||||
"""
|
||||
da locale file.
|
||||
|
||||
It has been generated automatically and must not be modified directly.
|
||||
"""
|
||||
|
||||
|
||||
locale = {
|
||||
"plural": lambda n: "one"
|
||||
if (
|
||||
(n == n and ((n == 1)))
|
||||
or ((not (0 == 0 and ((0 == 0)))) and (n == n and ((n == 0) or (n == 1))))
|
||||
)
|
||||
else "other",
|
||||
"ordinal": lambda n: "other",
|
||||
"translations": {
|
||||
"days": {
|
||||
"abbreviated": {
|
||||
0: "søn.",
|
||||
1: "man.",
|
||||
2: "tir.",
|
||||
3: "ons.",
|
||||
4: "tor.",
|
||||
5: "fre.",
|
||||
6: "lør.",
|
||||
},
|
||||
"narrow": {0: "S", 1: "M", 2: "T", 3: "O", 4: "T", 5: "F", 6: "L"},
|
||||
"short": {0: "sø", 1: "ma", 2: "ti", 3: "on", 4: "to", 5: "fr", 6: "lø"},
|
||||
"wide": {
|
||||
0: "søndag",
|
||||
1: "mandag",
|
||||
2: "tirsdag",
|
||||
3: "onsdag",
|
||||
4: "torsdag",
|
||||
5: "fredag",
|
||||
6: "lørdag",
|
||||
},
|
||||
},
|
||||
"months": {
|
||||
"abbreviated": {
|
||||
1: "jan.",
|
||||
2: "feb.",
|
||||
3: "mar.",
|
||||
4: "apr.",
|
||||
5: "maj",
|
||||
6: "jun.",
|
||||
7: "jul.",
|
||||
8: "aug.",
|
||||
9: "sep.",
|
||||
10: "okt.",
|
||||
11: "nov.",
|
||||
12: "dec.",
|
||||
},
|
||||
"narrow": {
|
||||
1: "J",
|
||||
2: "F",
|
||||
3: "M",
|
||||
4: "A",
|
||||
5: "M",
|
||||
6: "J",
|
||||
7: "J",
|
||||
8: "A",
|
||||
9: "S",
|
||||
10: "O",
|
||||
11: "N",
|
||||
12: "D",
|
||||
},
|
||||
"wide": {
|
||||
1: "januar",
|
||||
2: "februar",
|
||||
3: "marts",
|
||||
4: "april",
|
||||
5: "maj",
|
||||
6: "juni",
|
||||
7: "juli",
|
||||
8: "august",
|
||||
9: "september",
|
||||
10: "oktober",
|
||||
11: "november",
|
||||
12: "december",
|
||||
},
|
||||
},
|
||||
"units": {
|
||||
"year": {"one": "{0} år", "other": "{0} år"},
|
||||
"month": {"one": "{0} måned", "other": "{0} måneder"},
|
||||
"week": {"one": "{0} uge", "other": "{0} uger"},
|
||||
"day": {"one": "{0} dag", "other": "{0} dage"},
|
||||
"hour": {"one": "{0} time", "other": "{0} timer"},
|
||||
"minute": {"one": "{0} minut", "other": "{0} minutter"},
|
||||
"second": {"one": "{0} sekund", "other": "{0} sekunder"},
|
||||
"microsecond": {"one": "{0} mikrosekund", "other": "{0} mikrosekunder"},
|
||||
},
|
||||
"relative": {
|
||||
"year": {
|
||||
"future": {"other": "om {0} år", "one": "om {0} år"},
|
||||
"past": {"other": "for {0} år siden", "one": "for {0} år siden"},
|
||||
},
|
||||
"month": {
|
||||
"future": {"other": "om {0} måneder", "one": "om {0} måned"},
|
||||
"past": {
|
||||
"other": "for {0} måneder siden",
|
||||
"one": "for {0} måned siden",
|
||||
},
|
||||
},
|
||||
"week": {
|
||||
"future": {"other": "om {0} uger", "one": "om {0} uge"},
|
||||
"past": {"other": "for {0} uger siden", "one": "for {0} uge siden"},
|
||||
},
|
||||
"day": {
|
||||
"future": {"other": "om {0} dage", "one": "om {0} dag"},
|
||||
"past": {"other": "for {0} dage siden", "one": "for {0} dag siden"},
|
||||
},
|
||||
"hour": {
|
||||
"future": {"other": "om {0} timer", "one": "om {0} time"},
|
||||
"past": {"other": "for {0} timer siden", "one": "for {0} time siden"},
|
||||
},
|
||||
"minute": {
|
||||
"future": {"other": "om {0} minutter", "one": "om {0} minut"},
|
||||
"past": {
|
||||
"other": "for {0} minutter siden",
|
||||
"one": "for {0} minut siden",
|
||||
},
|
||||
},
|
||||
"second": {
|
||||
"future": {"other": "om {0} sekunder", "one": "om {0} sekund"},
|
||||
"past": {
|
||||
"other": "for {0} sekunder siden",
|
||||
"one": "for {0} sekund siden",
|
||||
},
|
||||
},
|
||||
},
|
||||
"day_periods": {
|
||||
"midnight": "midnat",
|
||||
"am": "AM",
|
||||
"pm": "PM",
|
||||
"morning1": "om morgenen",
|
||||
"morning2": "om formiddagen",
|
||||
"afternoon1": "om eftermiddagen",
|
||||
"evening1": "om aftenen",
|
||||
"night1": "om natten",
|
||||
},
|
||||
},
|
||||
"custom": custom_translations,
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,40 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
"""
|
||||
de custom locale file.
|
||||
"""
|
||||
|
||||
translations = {
|
||||
# Relative time
|
||||
"after": "{0} später",
|
||||
"before": "{0} zuvor",
|
||||
"units_relative": {
|
||||
"year": {
|
||||
"future": {"one": "{0} Jahr", "other": "{0} Jahren"},
|
||||
"past": {"one": "{0} Jahr", "other": "{0} Jahren"},
|
||||
},
|
||||
"month": {
|
||||
"future": {"one": "{0} Monat", "other": "{0} Monaten"},
|
||||
"past": {"one": "{0} Monat", "other": "{0} Monaten"},
|
||||
},
|
||||
"week": {
|
||||
"future": {"one": "{0} Woche", "other": "{0} Wochen"},
|
||||
"past": {"one": "{0} Woche", "other": "{0} Wochen"},
|
||||
},
|
||||
"day": {
|
||||
"future": {"one": "{0} Tag", "other": "{0} Tagen"},
|
||||
"past": {"one": "{0} Tag", "other": "{0} Tagen"},
|
||||
},
|
||||
},
|
||||
# Date formats
|
||||
"date_formats": {
|
||||
"LTS": "HH:mm:ss",
|
||||
"LT": "HH:mm",
|
||||
"LLLL": "dddd, D. MMMM YYYY HH:mm",
|
||||
"LLL": "D. MMMM YYYY HH:mm",
|
||||
"LL": "D. MMMM YYYY",
|
||||
"L": "DD.MM.YYYY",
|
||||
},
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .custom import translations as custom_translations
|
||||
|
||||
|
||||
"""
|
||||
de locale file.
|
||||
|
||||
It has been generated automatically and must not be modified directly.
|
||||
"""
|
||||
|
||||
|
||||
locale = {
|
||||
"plural": lambda n: "one"
|
||||
if ((n == n and ((n == 1))) and (0 == 0 and ((0 == 0))))
|
||||
else "other",
|
||||
"ordinal": lambda n: "other",
|
||||
"translations": {
|
||||
"days": {
|
||||
"abbreviated": {
|
||||
0: "So.",
|
||||
1: "Mo.",
|
||||
2: "Di.",
|
||||
3: "Mi.",
|
||||
4: "Do.",
|
||||
5: "Fr.",
|
||||
6: "Sa.",
|
||||
},
|
||||
"narrow": {0: "S", 1: "M", 2: "D", 3: "M", 4: "D", 5: "F", 6: "S"},
|
||||
"short": {
|
||||
0: "So.",
|
||||
1: "Mo.",
|
||||
2: "Di.",
|
||||
3: "Mi.",
|
||||
4: "Do.",
|
||||
5: "Fr.",
|
||||
6: "Sa.",
|
||||
},
|
||||
"wide": {
|
||||
0: "Sonntag",
|
||||
1: "Montag",
|
||||
2: "Dienstag",
|
||||
3: "Mittwoch",
|
||||
4: "Donnerstag",
|
||||
5: "Freitag",
|
||||
6: "Samstag",
|
||||
},
|
||||
},
|
||||
"months": {
|
||||
"abbreviated": {
|
||||
1: "Jan.",
|
||||
2: "Feb.",
|
||||
3: "März",
|
||||
4: "Apr.",
|
||||
5: "Mai",
|
||||
6: "Juni",
|
||||
7: "Juli",
|
||||
8: "Aug.",
|
||||
9: "Sep.",
|
||||
10: "Okt.",
|
||||
11: "Nov.",
|
||||
12: "Dez.",
|
||||
},
|
||||
"narrow": {
|
||||
1: "J",
|
||||
2: "F",
|
||||
3: "M",
|
||||
4: "A",
|
||||
5: "M",
|
||||
6: "J",
|
||||
7: "J",
|
||||
8: "A",
|
||||
9: "S",
|
||||
10: "O",
|
||||
11: "N",
|
||||
12: "D",
|
||||
},
|
||||
"wide": {
|
||||
1: "Januar",
|
||||
2: "Februar",
|
||||
3: "März",
|
||||
4: "April",
|
||||
5: "Mai",
|
||||
6: "Juni",
|
||||
7: "Juli",
|
||||
8: "August",
|
||||
9: "September",
|
||||
10: "Oktober",
|
||||
11: "November",
|
||||
12: "Dezember",
|
||||
},
|
||||
},
|
||||
"units": {
|
||||
"year": {"one": "{0} Jahr", "other": "{0} Jahre"},
|
||||
"month": {"one": "{0} Monat", "other": "{0} Monate"},
|
||||
"week": {"one": "{0} Woche", "other": "{0} Wochen"},
|
||||
"day": {"one": "{0} Tag", "other": "{0} Tage"},
|
||||
"hour": {"one": "{0} Stunde", "other": "{0} Stunden"},
|
||||
"minute": {"one": "{0} Minute", "other": "{0} Minuten"},
|
||||
"second": {"one": "{0} Sekunde", "other": "{0} Sekunden"},
|
||||
"microsecond": {"one": "{0} Mikrosekunde", "other": "{0} Mikrosekunden"},
|
||||
},
|
||||
"relative": {
|
||||
"year": {
|
||||
"future": {"other": "in {0} Jahren", "one": "in {0} Jahr"},
|
||||
"past": {"other": "vor {0} Jahren", "one": "vor {0} Jahr"},
|
||||
},
|
||||
"month": {
|
||||
"future": {"other": "in {0} Monaten", "one": "in {0} Monat"},
|
||||
"past": {"other": "vor {0} Monaten", "one": "vor {0} Monat"},
|
||||
},
|
||||
"week": {
|
||||
"future": {"other": "in {0} Wochen", "one": "in {0} Woche"},
|
||||
"past": {"other": "vor {0} Wochen", "one": "vor {0} Woche"},
|
||||
},
|
||||
"day": {
|
||||
"future": {"other": "in {0} Tagen", "one": "in {0} Tag"},
|
||||
"past": {"other": "vor {0} Tagen", "one": "vor {0} Tag"},
|
||||
},
|
||||
"hour": {
|
||||
"future": {"other": "in {0} Stunden", "one": "in {0} Stunde"},
|
||||
"past": {"other": "vor {0} Stunden", "one": "vor {0} Stunde"},
|
||||
},
|
||||
"minute": {
|
||||
"future": {"other": "in {0} Minuten", "one": "in {0} Minute"},
|
||||
"past": {"other": "vor {0} Minuten", "one": "vor {0} Minute"},
|
||||
},
|
||||
"second": {
|
||||
"future": {"other": "in {0} Sekunden", "one": "in {0} Sekunde"},
|
||||
"past": {"other": "vor {0} Sekunden", "one": "vor {0} Sekunde"},
|
||||
},
|
||||
},
|
||||
"day_periods": {
|
||||
"midnight": "Mitternacht",
|
||||
"am": "vorm.",
|
||||
"pm": "nachm.",
|
||||
"morning1": "morgens",
|
||||
"morning2": "vormittags",
|
||||
"afternoon1": "mittags",
|
||||
"afternoon2": "nachmittags",
|
||||
"evening1": "abends",
|
||||
"night1": "nachts",
|
||||
},
|
||||
},
|
||||
"custom": custom_translations,
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
"""
|
||||
en custom locale file.
|
||||
"""
|
||||
|
||||
translations = {
|
||||
"units": {"few_second": "a few seconds"},
|
||||
# Relative time
|
||||
"ago": "{} ago",
|
||||
"from_now": "in {}",
|
||||
"after": "{0} after",
|
||||
"before": "{0} before",
|
||||
# Ordinals
|
||||
"ordinal": {"one": "st", "two": "nd", "few": "rd", "other": "th"},
|
||||
# Date formats
|
||||
"date_formats": {
|
||||
"LTS": "h:mm:ss A",
|
||||
"LT": "h:mm A",
|
||||
"L": "MM/DD/YYYY",
|
||||
"LL": "MMMM D, YYYY",
|
||||
"LLL": "MMMM D, YYYY h:mm A",
|
||||
"LLLL": "dddd, MMMM D, YYYY h:mm A",
|
||||
},
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .custom import translations as custom_translations
|
||||
|
||||
|
||||
"""
|
||||
en locale file.
|
||||
|
||||
It has been generated automatically and must not be modified directly.
|
||||
"""
|
||||
|
||||
|
||||
locale = {
|
||||
"plural": lambda n: "one"
|
||||
if ((n == n and ((n == 1))) and (0 == 0 and ((0 == 0))))
|
||||
else "other",
|
||||
"ordinal": lambda n: "few"
|
||||
if (
|
||||
((n % 10) == (n % 10) and (((n % 10) == 3)))
|
||||
and (not ((n % 100) == (n % 100) and (((n % 100) == 13))))
|
||||
)
|
||||
else "one"
|
||||
if (
|
||||
((n % 10) == (n % 10) and (((n % 10) == 1)))
|
||||
and (not ((n % 100) == (n % 100) and (((n % 100) == 11))))
|
||||
)
|
||||
else "two"
|
||||
if (
|
||||
((n % 10) == (n % 10) and (((n % 10) == 2)))
|
||||
and (not ((n % 100) == (n % 100) and (((n % 100) == 12))))
|
||||
)
|
||||
else "other",
|
||||
"translations": {
|
||||
"days": {
|
||||
"abbreviated": {
|
||||
0: "Sun",
|
||||
1: "Mon",
|
||||
2: "Tue",
|
||||
3: "Wed",
|
||||
4: "Thu",
|
||||
5: "Fri",
|
||||
6: "Sat",
|
||||
},
|
||||
"narrow": {0: "S", 1: "M", 2: "T", 3: "W", 4: "T", 5: "F", 6: "S"},
|
||||
"short": {0: "Su", 1: "Mo", 2: "Tu", 3: "We", 4: "Th", 5: "Fr", 6: "Sa"},
|
||||
"wide": {
|
||||
0: "Sunday",
|
||||
1: "Monday",
|
||||
2: "Tuesday",
|
||||
3: "Wednesday",
|
||||
4: "Thursday",
|
||||
5: "Friday",
|
||||
6: "Saturday",
|
||||
},
|
||||
},
|
||||
"months": {
|
||||
"abbreviated": {
|
||||
1: "Jan",
|
||||
2: "Feb",
|
||||
3: "Mar",
|
||||
4: "Apr",
|
||||
5: "May",
|
||||
6: "Jun",
|
||||
7: "Jul",
|
||||
8: "Aug",
|
||||
9: "Sep",
|
||||
10: "Oct",
|
||||
11: "Nov",
|
||||
12: "Dec",
|
||||
},
|
||||
"narrow": {
|
||||
1: "J",
|
||||
2: "F",
|
||||
3: "M",
|
||||
4: "A",
|
||||
5: "M",
|
||||
6: "J",
|
||||
7: "J",
|
||||
8: "A",
|
||||
9: "S",
|
||||
10: "O",
|
||||
11: "N",
|
||||
12: "D",
|
||||
},
|
||||
"wide": {
|
||||
1: "January",
|
||||
2: "February",
|
||||
3: "March",
|
||||
4: "April",
|
||||
5: "May",
|
||||
6: "June",
|
||||
7: "July",
|
||||
8: "August",
|
||||
9: "September",
|
||||
10: "October",
|
||||
11: "November",
|
||||
12: "December",
|
||||
},
|
||||
},
|
||||
"units": {
|
||||
"year": {"one": "{0} year", "other": "{0} years"},
|
||||
"month": {"one": "{0} month", "other": "{0} months"},
|
||||
"week": {"one": "{0} week", "other": "{0} weeks"},
|
||||
"day": {"one": "{0} day", "other": "{0} days"},
|
||||
"hour": {"one": "{0} hour", "other": "{0} hours"},
|
||||
"minute": {"one": "{0} minute", "other": "{0} minutes"},
|
||||
"second": {"one": "{0} second", "other": "{0} seconds"},
|
||||
"microsecond": {"one": "{0} microsecond", "other": "{0} microseconds"},
|
||||
},
|
||||
"relative": {
|
||||
"year": {
|
||||
"future": {"other": "in {0} years", "one": "in {0} year"},
|
||||
"past": {"other": "{0} years ago", "one": "{0} year ago"},
|
||||
},
|
||||
"month": {
|
||||
"future": {"other": "in {0} months", "one": "in {0} month"},
|
||||
"past": {"other": "{0} months ago", "one": "{0} month ago"},
|
||||
},
|
||||
"week": {
|
||||
"future": {"other": "in {0} weeks", "one": "in {0} week"},
|
||||
"past": {"other": "{0} weeks ago", "one": "{0} week ago"},
|
||||
},
|
||||
"day": {
|
||||
"future": {"other": "in {0} days", "one": "in {0} day"},
|
||||
"past": {"other": "{0} days ago", "one": "{0} day ago"},
|
||||
},
|
||||
"hour": {
|
||||
"future": {"other": "in {0} hours", "one": "in {0} hour"},
|
||||
"past": {"other": "{0} hours ago", "one": "{0} hour ago"},
|
||||
},
|
||||
"minute": {
|
||||
"future": {"other": "in {0} minutes", "one": "in {0} minute"},
|
||||
"past": {"other": "{0} minutes ago", "one": "{0} minute ago"},
|
||||
},
|
||||
"second": {
|
||||
"future": {"other": "in {0} seconds", "one": "in {0} second"},
|
||||
"past": {"other": "{0} seconds ago", "one": "{0} second ago"},
|
||||
},
|
||||
},
|
||||
"day_periods": {
|
||||
"midnight": "midnight",
|
||||
"am": "AM",
|
||||
"noon": "noon",
|
||||
"pm": "PM",
|
||||
"morning1": "in the morning",
|
||||
"afternoon1": "in the afternoon",
|
||||
"evening1": "in the evening",
|
||||
"night1": "at night",
|
||||
},
|
||||
},
|
||||
"custom": custom_translations,
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
"""
|
||||
es custom locale file.
|
||||
"""
|
||||
|
||||
translations = {
|
||||
"units": {"few_second": "unos segundos"},
|
||||
# Relative time
|
||||
"ago": "hace {0}",
|
||||
"from_now": "dentro de {0}",
|
||||
"after": "{0} después",
|
||||
"before": "{0} antes",
|
||||
# Ordinals
|
||||
"ordinal": {"other": "º"},
|
||||
# Date formats
|
||||
"date_formats": {
|
||||
"LTS": "H:mm:ss",
|
||||
"LT": "H:mm",
|
||||
"LLLL": "dddd, D [de] MMMM [de] YYYY H:mm",
|
||||
"LLL": "D [de] MMMM [de] YYYY H:mm",
|
||||
"LL": "D [de] MMMM [de] YYYY",
|
||||
"L": "DD/MM/YYYY",
|
||||
},
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .custom import translations as custom_translations
|
||||
|
||||
|
||||
"""
|
||||
es locale file.
|
||||
|
||||
It has been generated automatically and must not be modified directly.
|
||||
"""
|
||||
|
||||
|
||||
locale = {
|
||||
"plural": lambda n: "one" if (n == n and ((n == 1))) else "other",
|
||||
"ordinal": lambda n: "other",
|
||||
"translations": {
|
||||
"days": {
|
||||
"abbreviated": {
|
||||
0: "dom.",
|
||||
1: "lun.",
|
||||
2: "mar.",
|
||||
3: "mié.",
|
||||
4: "jue.",
|
||||
5: "vie.",
|
||||
6: "sáb.",
|
||||
},
|
||||
"narrow": {0: "D", 1: "L", 2: "M", 3: "X", 4: "J", 5: "V", 6: "S"},
|
||||
"short": {0: "DO", 1: "LU", 2: "MA", 3: "MI", 4: "JU", 5: "VI", 6: "SA"},
|
||||
"wide": {
|
||||
0: "domingo",
|
||||
1: "lunes",
|
||||
2: "martes",
|
||||
3: "miércoles",
|
||||
4: "jueves",
|
||||
5: "viernes",
|
||||
6: "sábado",
|
||||
},
|
||||
},
|
||||
"months": {
|
||||
"abbreviated": {
|
||||
1: "ene.",
|
||||
2: "feb.",
|
||||
3: "mar.",
|
||||
4: "abr.",
|
||||
5: "may.",
|
||||
6: "jun.",
|
||||
7: "jul.",
|
||||
8: "ago.",
|
||||
9: "sept.",
|
||||
10: "oct.",
|
||||
11: "nov.",
|
||||
12: "dic.",
|
||||
},
|
||||
"narrow": {
|
||||
1: "E",
|
||||
2: "F",
|
||||
3: "M",
|
||||
4: "A",
|
||||
5: "M",
|
||||
6: "J",
|
||||
7: "J",
|
||||
8: "A",
|
||||
9: "S",
|
||||
10: "O",
|
||||
11: "N",
|
||||
12: "D",
|
||||
},
|
||||
"wide": {
|
||||
1: "enero",
|
||||
2: "febrero",
|
||||
3: "marzo",
|
||||
4: "abril",
|
||||
5: "mayo",
|
||||
6: "junio",
|
||||
7: "julio",
|
||||
8: "agosto",
|
||||
9: "septiembre",
|
||||
10: "octubre",
|
||||
11: "noviembre",
|
||||
12: "diciembre",
|
||||
},
|
||||
},
|
||||
"units": {
|
||||
"year": {"one": "{0} año", "other": "{0} años"},
|
||||
"month": {"one": "{0} mes", "other": "{0} meses"},
|
||||
"week": {"one": "{0} semana", "other": "{0} semanas"},
|
||||
"day": {"one": "{0} día", "other": "{0} días"},
|
||||
"hour": {"one": "{0} hora", "other": "{0} horas"},
|
||||
"minute": {"one": "{0} minuto", "other": "{0} minutos"},
|
||||
"second": {"one": "{0} segundo", "other": "{0} segundos"},
|
||||
"microsecond": {"one": "{0} microsegundo", "other": "{0} microsegundos"},
|
||||
},
|
||||
"relative": {
|
||||
"year": {
|
||||
"future": {"other": "dentro de {0} años", "one": "dentro de {0} año"},
|
||||
"past": {"other": "hace {0} años", "one": "hace {0} año"},
|
||||
},
|
||||
"month": {
|
||||
"future": {"other": "dentro de {0} meses", "one": "dentro de {0} mes"},
|
||||
"past": {"other": "hace {0} meses", "one": "hace {0} mes"},
|
||||
},
|
||||
"week": {
|
||||
"future": {
|
||||
"other": "dentro de {0} semanas",
|
||||
"one": "dentro de {0} semana",
|
||||
},
|
||||
"past": {"other": "hace {0} semanas", "one": "hace {0} semana"},
|
||||
},
|
||||
"day": {
|
||||
"future": {"other": "dentro de {0} días", "one": "dentro de {0} día"},
|
||||
"past": {"other": "hace {0} días", "one": "hace {0} día"},
|
||||
},
|
||||
"hour": {
|
||||
"future": {"other": "dentro de {0} horas", "one": "dentro de {0} hora"},
|
||||
"past": {"other": "hace {0} horas", "one": "hace {0} hora"},
|
||||
},
|
||||
"minute": {
|
||||
"future": {
|
||||
"other": "dentro de {0} minutos",
|
||||
"one": "dentro de {0} minuto",
|
||||
},
|
||||
"past": {"other": "hace {0} minutos", "one": "hace {0} minuto"},
|
||||
},
|
||||
"second": {
|
||||
"future": {
|
||||
"other": "dentro de {0} segundos",
|
||||
"one": "dentro de {0} segundo",
|
||||
},
|
||||
"past": {"other": "hace {0} segundos", "one": "hace {0} segundo"},
|
||||
},
|
||||
},
|
||||
"day_periods": {
|
||||
"am": "a. m.",
|
||||
"noon": "del mediodía",
|
||||
"pm": "p. m.",
|
||||
"morning1": "de la madrugada",
|
||||
"morning2": "de la mañana",
|
||||
"evening1": "de la tarde",
|
||||
"night1": "de la noche",
|
||||
},
|
||||
},
|
||||
"custom": custom_translations,
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
"""
|
||||
fa custom locale file.
|
||||
"""
|
||||
|
||||
translations = {
|
||||
# Relative time
|
||||
"after": "{0} پس از",
|
||||
"before": "{0} پیش از",
|
||||
# Date formats
|
||||
"date_formats": {
|
||||
"LTS": "HH:mm:ss",
|
||||
"LT": "HH:mm",
|
||||
"LLLL": "dddd, D MMMM YYYY HH:mm",
|
||||
"LLL": "D MMMM YYYY HH:mm",
|
||||
"LL": "D MMMM YYYY",
|
||||
"L": "DD/MM/YYYY",
|
||||
},
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .custom import translations as custom_translations
|
||||
|
||||
|
||||
"""
|
||||
fa locale file.
|
||||
|
||||
It has been generated automatically and must not be modified directly.
|
||||
"""
|
||||
|
||||
|
||||
locale = {
|
||||
"plural": lambda n: "one"
|
||||
if ((n == n and ((n == 0))) or (n == n and ((n == 1))))
|
||||
else "other",
|
||||
"ordinal": lambda n: "other",
|
||||
"translations": {
|
||||
"days": {
|
||||
"abbreviated": {
|
||||
0: "یکشنبه",
|
||||
1: "دوشنبه",
|
||||
2: "سه\u200cشنبه",
|
||||
3: "چهارشنبه",
|
||||
4: "پنجشنبه",
|
||||
5: "جمعه",
|
||||
6: "شنبه",
|
||||
},
|
||||
"narrow": {0: "ی", 1: "د", 2: "س", 3: "چ", 4: "پ", 5: "ج", 6: "ش"},
|
||||
"short": {0: "۱ش", 1: "۲ش", 2: "۳ش", 3: "۴ش", 4: "۵ش", 5: "ج", 6: "ش"},
|
||||
"wide": {
|
||||
0: "یکشنبه",
|
||||
1: "دوشنبه",
|
||||
2: "سه\u200cشنبه",
|
||||
3: "چهارشنبه",
|
||||
4: "پنجشنبه",
|
||||
5: "جمعه",
|
||||
6: "شنبه",
|
||||
},
|
||||
},
|
||||
"months": {
|
||||
"abbreviated": {
|
||||
1: "ژانویهٔ",
|
||||
2: "فوریهٔ",
|
||||
3: "مارس",
|
||||
4: "آوریل",
|
||||
5: "مهٔ",
|
||||
6: "ژوئن",
|
||||
7: "ژوئیهٔ",
|
||||
8: "اوت",
|
||||
9: "سپتامبر",
|
||||
10: "اکتبر",
|
||||
11: "نوامبر",
|
||||
12: "دسامبر",
|
||||
},
|
||||
"narrow": {
|
||||
1: "ژ",
|
||||
2: "ف",
|
||||
3: "م",
|
||||
4: "آ",
|
||||
5: "م",
|
||||
6: "ژ",
|
||||
7: "ژ",
|
||||
8: "ا",
|
||||
9: "س",
|
||||
10: "ا",
|
||||
11: "ن",
|
||||
12: "د",
|
||||
},
|
||||
"wide": {
|
||||
1: "ژانویهٔ",
|
||||
2: "فوریهٔ",
|
||||
3: "مارس",
|
||||
4: "آوریل",
|
||||
5: "مهٔ",
|
||||
6: "ژوئن",
|
||||
7: "ژوئیهٔ",
|
||||
8: "اوت",
|
||||
9: "سپتامبر",
|
||||
10: "اکتبر",
|
||||
11: "نوامبر",
|
||||
12: "دسامبر",
|
||||
},
|
||||
},
|
||||
"units": {
|
||||
"year": {"one": "{0} سال", "other": "{0} سال"},
|
||||
"month": {"one": "{0} ماه", "other": "{0} ماه"},
|
||||
"week": {"one": "{0} هفته", "other": "{0} هفته"},
|
||||
"day": {"one": "{0} روز", "other": "{0} روز"},
|
||||
"hour": {"one": "{0} ساعت", "other": "{0} ساعت"},
|
||||
"minute": {"one": "{0} دقیقه", "other": "{0} دقیقه"},
|
||||
"second": {"one": "{0} ثانیه", "other": "{0} ثانیه"},
|
||||
"microsecond": {"one": "{0} میکروثانیه", "other": "{0} میکروثانیه"},
|
||||
},
|
||||
"relative": {
|
||||
"year": {
|
||||
"future": {"other": "{0} سال بعد", "one": "{0} سال بعد"},
|
||||
"past": {"other": "{0} سال پیش", "one": "{0} سال پیش"},
|
||||
},
|
||||
"month": {
|
||||
"future": {"other": "{0} ماه بعد", "one": "{0} ماه بعد"},
|
||||
"past": {"other": "{0} ماه پیش", "one": "{0} ماه پیش"},
|
||||
},
|
||||
"week": {
|
||||
"future": {"other": "{0} هفته بعد", "one": "{0} هفته بعد"},
|
||||
"past": {"other": "{0} هفته پیش", "one": "{0} هفته پیش"},
|
||||
},
|
||||
"day": {
|
||||
"future": {"other": "{0} روز بعد", "one": "{0} روز بعد"},
|
||||
"past": {"other": "{0} روز پیش", "one": "{0} روز پیش"},
|
||||
},
|
||||
"hour": {
|
||||
"future": {"other": "{0} ساعت بعد", "one": "{0} ساعت بعد"},
|
||||
"past": {"other": "{0} ساعت پیش", "one": "{0} ساعت پیش"},
|
||||
},
|
||||
"minute": {
|
||||
"future": {"other": "{0} دقیقه بعد", "one": "{0} دقیقه بعد"},
|
||||
"past": {"other": "{0} دقیقه پیش", "one": "{0} دقیقه پیش"},
|
||||
},
|
||||
"second": {
|
||||
"future": {"other": "{0} ثانیه بعد", "one": "{0} ثانیه بعد"},
|
||||
"past": {"other": "{0} ثانیه پیش", "one": "{0} ثانیه پیش"},
|
||||
},
|
||||
},
|
||||
"day_periods": {
|
||||
"midnight": "نیمه\u200cشب",
|
||||
"am": "قبل\u200cازظهر",
|
||||
"noon": "ظهر",
|
||||
"pm": "بعدازظهر",
|
||||
"morning1": "صبح",
|
||||
"afternoon1": "عصر",
|
||||
"evening1": "عصر",
|
||||
"night1": "شب",
|
||||
},
|
||||
},
|
||||
"custom": custom_translations,
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,24 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
"""
|
||||
fo custom locale file.
|
||||
"""
|
||||
|
||||
translations = {
|
||||
# Relative time
|
||||
"after": "{0} aftaná",
|
||||
"before": "{0} áðrenn",
|
||||
# Ordinals
|
||||
"ordinal": {"other": "."},
|
||||
# Date formats
|
||||
"date_formats": {
|
||||
"LTS": "HH:mm:ss",
|
||||
"LT": "HH:mm",
|
||||
"LLLL": "dddd D. MMMM, YYYY HH:mm",
|
||||
"LLL": "D MMMM YYYY HH:mm",
|
||||
"LL": "D MMMM YYYY",
|
||||
"L": "DD/MM/YYYY",
|
||||
},
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .custom import translations as custom_translations
|
||||
|
||||
|
||||
"""
|
||||
fo locale file.
|
||||
|
||||
It has been generated automatically and must not be modified directly.
|
||||
"""
|
||||
|
||||
|
||||
locale = {
|
||||
"plural": lambda n: "one" if (n == n and ((n == 1))) else "other",
|
||||
"ordinal": lambda n: "other",
|
||||
"translations": {
|
||||
"days": {
|
||||
"abbreviated": {
|
||||
0: "sun.",
|
||||
1: "mán.",
|
||||
2: "týs.",
|
||||
3: "mik.",
|
||||
4: "hós.",
|
||||
5: "frí.",
|
||||
6: "ley.",
|
||||
},
|
||||
"narrow": {0: "S", 1: "M", 2: "T", 3: "M", 4: "H", 5: "F", 6: "L"},
|
||||
"short": {
|
||||
0: "su.",
|
||||
1: "má.",
|
||||
2: "tý.",
|
||||
3: "mi.",
|
||||
4: "hó.",
|
||||
5: "fr.",
|
||||
6: "le.",
|
||||
},
|
||||
"wide": {
|
||||
0: "sunnudagur",
|
||||
1: "mánadagur",
|
||||
2: "týsdagur",
|
||||
3: "mikudagur",
|
||||
4: "hósdagur",
|
||||
5: "fríggjadagur",
|
||||
6: "leygardagur",
|
||||
},
|
||||
},
|
||||
"months": {
|
||||
"abbreviated": {
|
||||
1: "jan.",
|
||||
2: "feb.",
|
||||
3: "mar.",
|
||||
4: "apr.",
|
||||
5: "mai",
|
||||
6: "jun.",
|
||||
7: "jul.",
|
||||
8: "aug.",
|
||||
9: "sep.",
|
||||
10: "okt.",
|
||||
11: "nov.",
|
||||
12: "des.",
|
||||
},
|
||||
"narrow": {
|
||||
1: "J",
|
||||
2: "F",
|
||||
3: "M",
|
||||
4: "A",
|
||||
5: "M",
|
||||
6: "J",
|
||||
7: "J",
|
||||
8: "A",
|
||||
9: "S",
|
||||
10: "O",
|
||||
11: "N",
|
||||
12: "D",
|
||||
},
|
||||
"wide": {
|
||||
1: "januar",
|
||||
2: "februar",
|
||||
3: "mars",
|
||||
4: "apríl",
|
||||
5: "mai",
|
||||
6: "juni",
|
||||
7: "juli",
|
||||
8: "august",
|
||||
9: "september",
|
||||
10: "oktober",
|
||||
11: "november",
|
||||
12: "desember",
|
||||
},
|
||||
},
|
||||
"units": {
|
||||
"year": {"one": "{0} ár", "other": "{0} ár"},
|
||||
"month": {"one": "{0} mánaður", "other": "{0} mánaðir"},
|
||||
"week": {"one": "{0} vika", "other": "{0} vikur"},
|
||||
"day": {"one": "{0} dagur", "other": "{0} dagar"},
|
||||
"hour": {"one": "{0} tími", "other": "{0} tímar"},
|
||||
"minute": {"one": "{0} minuttur", "other": "{0} minuttir"},
|
||||
"second": {"one": "{0} sekund", "other": "{0} sekundir"},
|
||||
"microsecond": {"one": "{0} mikrosekund", "other": "{0} mikrosekundir"},
|
||||
},
|
||||
"relative": {
|
||||
"year": {
|
||||
"future": {"other": "um {0} ár", "one": "um {0} ár"},
|
||||
"past": {"other": "{0} ár síðan", "one": "{0} ár síðan"},
|
||||
},
|
||||
"month": {
|
||||
"future": {"other": "um {0} mánaðir", "one": "um {0} mánað"},
|
||||
"past": {"other": "{0} mánaðir síðan", "one": "{0} mánað síðan"},
|
||||
},
|
||||
"week": {
|
||||
"future": {"other": "um {0} vikur", "one": "um {0} viku"},
|
||||
"past": {"other": "{0} vikur síðan", "one": "{0} vika síðan"},
|
||||
},
|
||||
"day": {
|
||||
"future": {"other": "um {0} dagar", "one": "um {0} dag"},
|
||||
"past": {"other": "{0} dagar síðan", "one": "{0} dagur síðan"},
|
||||
},
|
||||
"hour": {
|
||||
"future": {"other": "um {0} tímar", "one": "um {0} tíma"},
|
||||
"past": {"other": "{0} tímar síðan", "one": "{0} tími síðan"},
|
||||
},
|
||||
"minute": {
|
||||
"future": {"other": "um {0} minuttir", "one": "um {0} minutt"},
|
||||
"past": {"other": "{0} minuttir síðan", "one": "{0} minutt síðan"},
|
||||
},
|
||||
"second": {
|
||||
"future": {"other": "um {0} sekund", "one": "um {0} sekund"},
|
||||
"past": {"other": "{0} sekund síðan", "one": "{0} sekund síðan"},
|
||||
},
|
||||
},
|
||||
"day_periods": {"am": "AM", "pm": "PM"},
|
||||
},
|
||||
"custom": custom_translations,
|
||||
}
|
@ -0,0 +1 @@
|
||||
# -*- coding: utf-8 -*-
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,27 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
"""
|
||||
fr custom locale file.
|
||||
"""
|
||||
|
||||
translations = {
|
||||
"units": {"few_second": "quelques secondes"},
|
||||
# Relative Time
|
||||
"ago": "il y a {0}",
|
||||
"from_now": "dans {0}",
|
||||
"after": "{0} après",
|
||||
"before": "{0} avant",
|
||||
# Ordinals
|
||||
"ordinal": {"one": "er", "other": "e"},
|
||||
# Date formats
|
||||
"date_formats": {
|
||||
"LTS": "HH:mm:ss",
|
||||
"LT": "HH:mm",
|
||||
"LLLL": "dddd D MMMM YYYY HH:mm",
|
||||
"LLL": "D MMMM YYYY HH:mm",
|
||||
"LL": "D MMMM YYYY",
|
||||
"L": "DD/MM/YYYY",
|
||||
},
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .custom import translations as custom_translations
|
||||
|
||||
|
||||
"""
|
||||
fr locale file.
|
||||
|
||||
It has been generated automatically and must not be modified directly.
|
||||
"""
|
||||
|
||||
|
||||
locale = {
|
||||
"plural": lambda n: "one" if (n == n and ((n == 0) or (n == 1))) else "other",
|
||||
"ordinal": lambda n: "one" if (n == n and ((n == 1))) else "other",
|
||||
"translations": {
|
||||
"days": {
|
||||
"abbreviated": {
|
||||
0: "dim.",
|
||||
1: "lun.",
|
||||
2: "mar.",
|
||||
3: "mer.",
|
||||
4: "jeu.",
|
||||
5: "ven.",
|
||||
6: "sam.",
|
||||
},
|
||||
"narrow": {0: "D", 1: "L", 2: "M", 3: "M", 4: "J", 5: "V", 6: "S"},
|
||||
"short": {0: "di", 1: "lu", 2: "ma", 3: "me", 4: "je", 5: "ve", 6: "sa"},
|
||||
"wide": {
|
||||
0: "dimanche",
|
||||
1: "lundi",
|
||||
2: "mardi",
|
||||
3: "mercredi",
|
||||
4: "jeudi",
|
||||
5: "vendredi",
|
||||
6: "samedi",
|
||||
},
|
||||
},
|
||||
"months": {
|
||||
"abbreviated": {
|
||||
1: "janv.",
|
||||
2: "févr.",
|
||||
3: "mars",
|
||||
4: "avr.",
|
||||
5: "mai",
|
||||
6: "juin",
|
||||
7: "juil.",
|
||||
8: "août",
|
||||
9: "sept.",
|
||||
10: "oct.",
|
||||
11: "nov.",
|
||||
12: "déc.",
|
||||
},
|
||||
"narrow": {
|
||||
1: "J",
|
||||
2: "F",
|
||||
3: "M",
|
||||
4: "A",
|
||||
5: "M",
|
||||
6: "J",
|
||||
7: "J",
|
||||
8: "A",
|
||||
9: "S",
|
||||
10: "O",
|
||||
11: "N",
|
||||
12: "D",
|
||||
},
|
||||
"wide": {
|
||||
1: "janvier",
|
||||
2: "février",
|
||||
3: "mars",
|
||||
4: "avril",
|
||||
5: "mai",
|
||||
6: "juin",
|
||||
7: "juillet",
|
||||
8: "août",
|
||||
9: "septembre",
|
||||
10: "octobre",
|
||||
11: "novembre",
|
||||
12: "décembre",
|
||||
},
|
||||
},
|
||||
"units": {
|
||||
"year": {"one": "{0} an", "other": "{0} ans"},
|
||||
"month": {"one": "{0} mois", "other": "{0} mois"},
|
||||
"week": {"one": "{0} semaine", "other": "{0} semaines"},
|
||||
"day": {"one": "{0} jour", "other": "{0} jours"},
|
||||
"hour": {"one": "{0} heure", "other": "{0} heures"},
|
||||
"minute": {"one": "{0} minute", "other": "{0} minutes"},
|
||||
"second": {"one": "{0} seconde", "other": "{0} secondes"},
|
||||
"microsecond": {"one": "{0} microseconde", "other": "{0} microsecondes"},
|
||||
},
|
||||
"relative": {
|
||||
"year": {
|
||||
"future": {"other": "dans {0} ans", "one": "dans {0} an"},
|
||||
"past": {"other": "il y a {0} ans", "one": "il y a {0} an"},
|
||||
},
|
||||
"month": {
|
||||
"future": {"other": "dans {0} mois", "one": "dans {0} mois"},
|
||||
"past": {"other": "il y a {0} mois", "one": "il y a {0} mois"},
|
||||
},
|
||||
"week": {
|
||||
"future": {"other": "dans {0} semaines", "one": "dans {0} semaine"},
|
||||
"past": {"other": "il y a {0} semaines", "one": "il y a {0} semaine"},
|
||||
},
|
||||
"day": {
|
||||
"future": {"other": "dans {0} jours", "one": "dans {0} jour"},
|
||||
"past": {"other": "il y a {0} jours", "one": "il y a {0} jour"},
|
||||
},
|
||||
"hour": {
|
||||
"future": {"other": "dans {0} heures", "one": "dans {0} heure"},
|
||||
"past": {"other": "il y a {0} heures", "one": "il y a {0} heure"},
|
||||
},
|
||||
"minute": {
|
||||
"future": {"other": "dans {0} minutes", "one": "dans {0} minute"},
|
||||
"past": {"other": "il y a {0} minutes", "one": "il y a {0} minute"},
|
||||
},
|
||||
"second": {
|
||||
"future": {"other": "dans {0} secondes", "one": "dans {0} seconde"},
|
||||
"past": {"other": "il y a {0} secondes", "one": "il y a {0} seconde"},
|
||||
},
|
||||
},
|
||||
"day_periods": {
|
||||
"midnight": "minuit",
|
||||
"am": "AM",
|
||||
"noon": "midi",
|
||||
"pm": "PM",
|
||||
"morning1": "du matin",
|
||||
"afternoon1": "de l’après-midi",
|
||||
"evening1": "du soir",
|
||||
"night1": "de nuit",
|
||||
},
|
||||
},
|
||||
"custom": custom_translations,
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user