pax_global_header00006660000000000000000000000064146303750120014513gustar00rootroot0000000000000052 comment=9ec687ba37612bd12f9b736a6febba57d3b8bd41 cftime-1.6.4rel/000077500000000000000000000000001463037501200134755ustar00rootroot00000000000000cftime-1.6.4rel/.coveragerc000066400000000000000000000004461463037501200156220ustar00rootroot00000000000000# # .coveragerc to control coverage.py # [run] relative_files = True branch = True plugins = Cython.Coverage include = src/cftime/* omit = setup.py docs/* ci/* test/* .eggs [report] exclude_lines = pragma: no cover def __repr__ if __name__ == .__main__.: cftime-1.6.4rel/.github/000077500000000000000000000000001463037501200150355ustar00rootroot00000000000000cftime-1.6.4rel/.github/dependabot.yml000066400000000000000000000011031463037501200176600ustar00rootroot00000000000000# Keep GitHub Actions up to date with GitHub's Dependabot... # https://docs.github.com/en/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot # https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem version: 2 updates: - package-ecosystem: github-actions directory: / groups: github-actions: patterns: - "*" # Group all Actions updates into a single larger pull request schedule: interval: weekly cftime-1.6.4rel/.github/workflows/000077500000000000000000000000001463037501200170725ustar00rootroot00000000000000cftime-1.6.4rel/.github/workflows/cibuildwheel.yml000066400000000000000000000075601463037501200222650ustar00rootroot00000000000000name: Wheels on: pull_request: branches: - master push: tags: - "v*" jobs: build_bdist: name: "Build ${{ matrix.os }} (${{ matrix.arch }}) wheels" runs-on: ${{ matrix.os }} timeout-minutes: 60 # should be long enough even on tags, but let's prevent hangs strategy: fail-fast: false matrix: include: - os: ubuntu-22.04 arch: x86_64 - os: ubuntu-22.04 arch: aarch64 - os: windows-2022 arch: AMD64 - os: macos-14 arch: arm64 - os: macos-13 arch: x86_64 steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # For aarch64 support # https://cibuildwheel.pypa.io/en/stable/faq/#emulation - uses: docker/setup-qemu-action@v3 with: platforms: all if: runner.os == 'Linux' && matrix.arch == 'aarch64' - name: Build just oldest and newest on PRs, all on tags shell: bash # - Always omit musl 3.8 b/c NumPy does not provide wheels for it # - Always omit musllinux_aarch64 because it's slow and niche # - On PPs, omit musllinux for speed # - On PRs, run just oldest and newest Python versions (and omit 3.8 aarch64) run: | if [[ "${{ github.event_name }}" == "pull_request" ]]; then CIBW_SKIP="pp* cp36-* cp37-* cp38-musllinux* cp39-* cp310-* cp311-* cp38-*_aarch64 *musllinux*" else CIBW_SKIP="pp* cp36-* cp37-* cp38-musllinux* *musllinux_aarch64" fi echo "CIBW_SKIP=$CIBW_SKIP" >> $GITHUB_ENV echo "Setting CIBW_SKIP=$CIBW_SKIP" - name: "Building ${{ matrix.os }} (${{ matrix.arch }}) wheels" uses: pypa/cibuildwheel@v2.18.1 env: # Skips pypy py36,37 CIBW_SKIP: ${{ env.CIBW_SKIP }} CIBW_ARCHS: ${{ matrix.arch }} CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 CIBW_MANYLINUX_AARCH64_IMAGE: manylinux2014 # Emulated testing is slow, so trust that the Python 3.12 test is good enough on aarch64 # (takes about 5 minutes per wheel to build, and 5 minutes to test) CIBW_TEST_SKIP: "cp38-*_aarch64 cp39-*_aarch64 cp310-*_aarch64 cp311-*_aarch64" CIBW_TEST_REQUIRES: pytest CIBW_TEST_COMMAND: > python -c "import cftime; print(f'cftime v{cftime.__version__}')" && python -m pip install check-manifest cython pytest pytest-cov && python -m pytest -vv {package}/test - uses: actions/upload-artifact@v4 with: name: pypi-artifacts-${{ matrix.os }}-${{ matrix.arch }} path: ${{ github.workspace }}/wheelhouse/*.whl build_sdist: name: Build source distribution runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Build sdist run: > pip install build && python -m build --sdist . --outdir dist - uses: actions/upload-artifact@v4 with: path: dist/*.tar.gz show-artifacts: needs: [build_bdist, build_sdist] name: "Show artifacts" runs-on: ubuntu-22.04 steps: - uses: actions/download-artifact@v4 with: pattern: pypi-artifacts* path: ${{ github.workspace }}/dist merge-multiple: true - shell: bash run: | ls -l ${{ github.workspace }}/dist publish-artifacts-pypi: needs: [build_bdist, build_sdist] name: "Publish to PyPI" runs-on: ubuntu-22.04 # upload to PyPI for every tag starting with 'v' if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v') steps: - uses: actions/download-artifact@v4 with: pattern: pypi-artifacts* path: ${{ github.workspace }}/dist merge-multiple: true - uses: pypa/gh-action-pypi-publish@release/v1 with: user: __token__ password: ${{ secrets.PYPI_PASSWORD }} print_hash: true cftime-1.6.4rel/.github/workflows/deploy-docs.yml000066400000000000000000000017631463037501200220460ustar00rootroot00000000000000name: Build and Deploy docs on: push: branches: - master jobs: build-docs: runs-on: ubuntu-latest steps: - name: checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Mamba uses: mamba-org/setup-micromamba@v1 with: environment-name: TEST create-args: >- python=3 numpy>1.13.3 sphinx - name: Build environment shell: bash -l {0} run: | python -m pip install -e . --no-deps --force-reinstall - name: Get the version shell: bash -l {0} id: get_version run: echo "name=VERSION::$(python setup.py --version)" >> $GITHUB_OUTPUT - name: Build documentation shell: bash -l {0} run: | set -e pushd docs make html linkcheck O=-W popd - name: Deploy uses: peaceiris/actions-gh-pages@v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: docs/_build/html cftime-1.6.4rel/.github/workflows/publish.yml000066400000000000000000000021531463037501200212640ustar00rootroot00000000000000name: Publish to PyPI on: ["push", "pull_request"] jobs: packages: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: 3.x - name: Get tags run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* shell: bash - name: Install build tools run: | python -m pip install --upgrade pip wheel setuptools setuptools_scm build twine check-manifest numpy shell: bash - name: Build binary wheel run: python -m build --sdist --wheel . --outdir dist - name: CheckFiles run: | ls dist shell: bash - name: Test wheels and sdist run: | python setup.py --version check-manifest --verbose cd dist && python -m pip install cftime*.whl python -m twine check * shell: bash - name: Publish a Python distribution to PyPI if: ${{ github.event_name == 'release' }} uses: pypa/gh-action-pypi-publish@master with: user: __token__ password: ${{ secrets.PYPI_PASSWORD }} cftime-1.6.4rel/.github/workflows/tests_conda.yml000066400000000000000000000030631463037501200221250ustar00rootroot00000000000000name: TESTS-CONDA-ENV on: pull_request: push: branches: [master] jobs: run: runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.experimental }} strategy: fail-fast: false matrix: python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ] os: [windows-latest, ubuntu-latest, macos-latest] platform: [x64, x32] experimental: [false] exclude: - os: macos-latest platform: x32 include: - python-version: "3.12" os: "ubuntu-latest" experimental: true steps: - uses: actions/checkout@v4 - name: Setup micromamba Env uses: mamba-org/setup-micromamba@v1 with: environment-name: TEST create-args: >- python=${{ matrix.python-version }} numpy>1.13.3 cython>=0.29.20 pytest pytest-cov - name: Install unstable dependencies if: matrix.experimental == true shell: bash -l {0} run: | python -m pip install \ --index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple/ \ --trusted-host pypi.anaconda.org \ --no-deps --pre --upgrade \ numpy; python -m pip install -v -e . --no-deps --no-build-isolation --force-reinstall - name: Install cftime if: matrix.experimental != true shell: bash -l {0} run: | python -m pip install -v -e . --no-deps --force-reinstall - name: Run Tests shell: bash -l {0} run: | pytest -vv test cftime-1.6.4rel/.github/workflows/tests_latest.yml000066400000000000000000000020261463037501200223330ustar00rootroot00000000000000name: Build and test with development python on: [push, pull_request] jobs: build-linux: name: Python (${{ matrix.python-version }}) runs-on: ubuntu-latest strategy: matrix: python-version: ["3.13.0-alpha.1"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Update Pip run: | python -m pip install --upgrade pip - name: Install unstable cftime dependencies via pip run: | python -m pip install --pre -r requirements-dev.txt # get nightly wheels for numpy python -m pip install \ --index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple/ \ --trusted-host pypi.anaconda.org \ --no-deps --pre --upgrade \ numpy - name: Install cftime run: | python -m pip install . - name: Test cftime run: | pytest -vv test cftime-1.6.4rel/.gitignore000066400000000000000000000001321463037501200154610ustar00rootroot00000000000000*.so *.py[co] *.c build/ *.egg? *.egg-info __pycache__ .pytest_cache/ dist/ docs/_build/* cftime-1.6.4rel/Changelog000066400000000000000000000243301463037501200153110ustar00rootroot00000000000000version 1.6.4 (release tag v1.6.4rel) ===================================== * build aarch64 linux wheels (issue #333). * build musllinux wheels (issue #307). * return empty array if one provided to date2num (issue #315). * numpy 2.0 compatibility (issue #325). * handle nan/inf in num2date (issue #328). version 1.6.3 (release tag v1.6.3rel) ===================================== * add support for formats without separators in strptime (e.g. '20200229', issue #301). This required removing support for > 4 digit years. * set the c_api_binop_methods compiler directive to True to retain Cython 0.x behavior for arithmetic operators for Cython >= 3.0.0 (issue #271). * support for python 3.12. version 1.6.2 (release tag v1.6.2rel) ===================================== * num2date should not fail on an empty integer array (issue #287). * longdouble keyword in date2num so that a roundtrip from a time to a date and back again does not lose microsecond precision when the units require the times be encoded as floating point values (PR #284) * added strptime method (issue #277). * cibuildwheel wheel-building workflow added to github actions by @ocefpaf (triggers binary wheel builds and uploads to pypi automatically when GH release created). PR #290. version 1.6.1 (release tag v1.6.1rel) ===================================== * fix failing tests on windows with numpy 1.23.0 (issue #278) * expose to_tuple module function in public API. version 1.6.0 (release tag v1.6.0rel) ===================================== * fix for masked array inputs (issue #267). * improved performance of the num2date algorithm, in some cases providing an over 100x speedup (issue #269, PR#270). * fix for date2index for select != 'exact' when select='exact' works (issue #272, PR#273) version 1.5.2 (release tag v1.5.2rel) ===================================== * silently change calendar='gregorian' to 'standard' internally, since 'gregorian' deprecated in CF v1.9 (issue #256). * add "is_leap_year" function (issue #259). * wheels that work on Apple M1 (arm64) available on pypi. version 1.5.1.1 =============== * no code changes, just new binary wheels for python 3.10. version 1.5.1 (release tag v1.5.1.rel) ====================================== * added support for "common_year" and "common_years" units for "noleap" and "365_day" calendars (issue #5, PR #246) * check consistency of year arg and has_year_zero kwarg in cftime.datetime (issue #248). Also assume if has_year_zero not specified it should be True if year=0. Allow replace method to change has_year_zero. Issue UserWarning if year set to zero and calendar default is changed from False to True (so that user is aware the resulting instance will not be CF compliant). * '360_day' was missing from list of 'idealized' calendars. * fixed a bug that led to subclasses losing their type identity upon pickling (issue #251, PR #252). * Change default behavior of proleptic_gregorian to has_year_zero=T (to be consistent with ISO-8601 since CF does not specify the year zero convention for this calendar). Issue warning when trying to to create a cftime.datetime instance that is not allowed in CF (PR #238). version 1.5.0 (release tag v1.5.0.rel) ====================================== * clean-up deprecated calendar specific subclasses (PR #231). * added string formatting support to `cftime.datetime` objects (via `cftime.datetime.__format__`) PR #232. * add support for astronomical year numbering (including year zero) for real-world calendars using 'has_year_zero' cftime.datetime kwarg (PR #234). Default is False for 'real-world' calendars ('julian', 'gregorian'/'standard', 'proleptic_gregorian'). Ignored for idealized calendars like '360_day (they always have year zero). * add "change_calendar" cftime.datetime method to switch to another 'real-world' calendar. Enable comparison of cftime.datetime instances with different 'real-world' calendars (using the new change_calendar method) * remove legacy `utime` class, and legacy `JulianDayFromDate` and `DateFromJulianDay` functions (replaced by `cftime.datetime.toordinal` and `cftime.datetime.fromordinal`). PR #235. * Change ValueError to TypeError in __sub__ (issue #236, PR #236). version 1.4.1 (release tag v1.4.1.rel) ====================================== * Restore use of calendar-specific sub-classes in `cftime.num2date`, `cftime.datetime.__add__`, and `cftime.datetime.__sub__`. The use of them will be removed in a later release. * add 'fromordinal' static method to create a cftime.datetime instance from a julian day ordinal and calendar (inverse of 'toordinal'). version 1.4.0 (release tag v1.4.0.rel) ====================================== * `cftime.date2num` will now always return an array of integers, if the units and times allow. Previously this would only be true if the units were 'microseconds' (PR #225). In other circumstances, as before, `cftime.date2num` will return an array of floats. * Rewrite of julian day/calendar functions (_IntJulianDayToCalendar and _IntJulianDayFromCalendar) to remove GPL'ed code. cftime license changed to MIT (to be consistent with netcdf4-python). * Added datetime.toordinal() (returns julian day, kwarg 'fractional' can be used to include fractional day). * cftime.datetime no longer uses calendar-specific sub-classes. version 1.3.1 (release tag v1.3.1rel) ===================================== * fix for issue #211 (PR #212) bug in masked array handling in date2num) * switch from travis/appveyor to github actions for CI/CD (PR #215). * switch to cython language_level=3 (no more support for python 2) (PR #217). * add __init__.py to test dir so pytest coverage works again. Add Coveralls step to github actions workflow to upload coverage data to coveralls.io (PR #217). * move package under 'src' directory so cftime can be imported from install dir (PR #218 - see https://blog.ionelmc.ro/2014/05/25/python-packaging/#the-structure). version 1.3.0 (release tag v1.3.0rel) ===================================== * zero pad years in strtime (issue #194) * have cftime.datetime constructor create 'calendar-aware' instances (default is 'standard' calendar, if calendar='' or None the instance is not calendar aware and some methods, like dayofwk, dayofyr, __add__ and __sub__, will not work). Fixes issue #198. The calendar specific sub-classes are now deprecated, but remain for now as stubs that just instantiate the base class and override __repr__. * update regex in _cpdef _parse_date so reference years with more than four digits can be handled. * Change default calendar in cftime.date2num from 'standard' to None (calendar associated with first input datetime object is used). * add `cftime.datetime.tzinfo=None` for compatibility with python datetime (issue #208). version 1.2.1 (release tag v1.2.1rel) ===================================== * num2date uses 'proleptic_gregorian' scheme when basedate is post-Gregorian but date is pre-Gregorian (issue #182). * fix 1.2.0 regression (date2num no longer works with numpy scalar array inputs, issue #185). * Fix for issue #187 (have date2num round to the nearest second when within 1 microsecond). * Fix for issue #189 (leap years calculated incorrectly for negative years in proleptic_gregorian calendar). version 1.2.0 (release tag v1.2.0rel) ===================================== * Return the default values of dayofwk and dayofyr when calendar is '' (issue #173). * fix treatment of masked arrays in num2date and date2num (issue #175). Also make sure masked arrays are output from num2date/date2num if masked arrays are input. * Where possible, use timedelta arithmetic to decode times exactly within num2date (issue #171). * Make taking the difference between two cftime datetimes to produce a timedelta exact to the microsecond; depending on the units encoding, this enables date2num to be exact as well (issue #109). * utime.date2num/utime.num2date now just call module level functions. JulianDayFromDate/DateFromJulianDay no longer used internally (PR #180). version 1.1.3 (release tag v1.1.3rel) ===================================== * add isoformat method for compatibility with python datetime (issue #152). * make 'standard' default calendar for cftime.datetime so that dayofwk,dayofyr methods don't fail (issue #169). version 1.1.2 (release tag v1.1.2rel) ===================================== * change dayofwk and dayofyr attributes into properties (issue #158) * fix for issue #165 (python datetime should be returned when only_use_cftime_datetimes=False). version 1.1.1.2 (release tag v1.1.1.2rel) ========================================= * include pyproject.toml in MANIFEST.in so it gets included in source tarball (issue #154). version 1.1.1.1 (release tag v1.1.1.1rel) ========================================= * Fix error installing with pip on python 3.8 by following PEP 517 (issue #148, PR #149) version 1.1.1 (release tag v1.1.1rel) ===================================== * fix microsecond formatting issue, ensure identical results computed for arrays and scales (issue #143, PR #146). version 1.1.0 (release tag v1.1.0rel) ===================================== * improved exceptions for time differences (issue #128, PR #131). * fix intersphinx entries (issue #133, PR #133) * make only_use_cftime_datetimes=True by default, so cftime datetime instances are returned by default by num2date (instead of returning python datetime instances where possible). Issue #136, PR #135. * Add daysinmonth attribute (issue #137, PR #138). * If only_use_python_datetimes=True and only_use_cftime_datetimes=False, num2date only returns python datetime instances and raises an exception if this is not possible. num2pydate convenience function added which just calls num2date with only_use_python_datetimes=True and only_use_cftime_datetimes=False. Remove positive times check, raise ValueError if python datetime tries to compute a date before MINYEAR (issue #134, PR #139) * Fix for fractional seconds in reference date in units string (issue #140, PR # 141). version 1.0.4.2 release ======================= * fix for issue #126 (date2num error when converting a DatetimeProlepticGregorian object). PR #127. cftime-1.6.4rel/LICENSE000066400000000000000000000020401463037501200144760ustar00rootroot00000000000000Copyright 2008 Jeffrey Whitaker 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. cftime-1.6.4rel/MANIFEST.in000066400000000000000000000002751463037501200152370ustar00rootroot00000000000000include *.txt include README.md include LICENSE include pyproject.toml include Changelog exclude *.legacy recursive-include src *.py recursive-include src *.pyx recursive-include test *.py cftime-1.6.4rel/README.md000066400000000000000000000167361463037501200147710ustar00rootroot00000000000000# cftime Time-handling functionality from netcdf4-python [![Build status](https://github.com/Unidata/cftime/workflows/cftime%20test/badge.svg)](https://github.com/Unidata/cftime/actions) [![PyPI package](https://badge.fury.io/py/cftime.svg)](http://python.org/pypi/cftime) [![Coverage Status](https://coveralls.io/repos/github/Unidata/cftime/badge.svg?branch=master)](https://coveralls.io/github/Unidata/cftime?branch=master) [![Tag Status](https://img.shields.io/github/tag/UniData/cftime.svg)](https://github.com/Unidata/cftime/tags) [![Release Status](https://img.shields.io/github/release/UniData/cftime.svg)](https://github.com/Unidata/cftime/releases) [![Commits Status](https://img.shields.io/github/commits-since/UniData/cftime/latest.svg)](https://github.com/UniData/cftime/commits/master) [![DOI](https://zenodo.org/badge/73107250.svg)](https://zenodo.org/badge/latestdoi/73107250) ## News For details on the latest updates, see the [Changelog](https://github.com/Unidata/cftime/blob/master/Changelog). 6/7/2024: Version 1.6.4 release. Wheels for muslinux and aarch64, numpy 2.0 compatibility. 10/20/2023: Version 1.6.3 released. Support for python 3.12, cython 3.0, strptime formats without separators. 9/18/2022: Version 1.6.2 released. strptime method added, fix for num2date failure on empty integer array, date2num 'longdouble' keyword added. New wheel building workflow. 6/30/2022: Version 1.6.1 released. Fixes for numpy 1.23.0, updated CI/CD. 3/4/2022: Version 1.6.0 released. Big speed-ups for num2date, date2index bugfix for select != 'exact' when select='exact' works, fix for date2num with masked array inputs. 1/22/2022: Version 1.5.2 released (wheels for Apple M1 available on pypi for python 3.8,3.9 and 3.10). is_leap_year function added (issue #259). 10/31/2021: Version 1.5.1.1 released (new binary wheels for python 3.10). 10/1/2021: Version 1.5.1 released. Changed default behavior of ``proleptic_gregorian`` to has_year_zero=T (since it is allowed in ISO-8601 and CF does not specify the year zero convention for this calendar). Raise warning message when trying to create a calendar that is not supported by CF version 1.9 (no years < 1 allowed for 'standard'/'gregorian' or 'julian' calendars). Added support for "common_year" and "common_years" units for "noleap" and "365_day" calendars. 5/20/2021: Version 1.5.0 released. Includes support for astronomical year numbering (including the year zero) for real-world calendars ('julian', 'gregorian'/'standard', and 'proleptic_gregorian') using 'has_year_zero' `cftime.datetime` kwarg. Added a 'change_calendar' `cftime.datetime` method to switch to another 'real-world' calendar to enable comparison of instances with different calendars. Some legacy classes and functions removed (`utime`, `JulianDayFromDate` and `DateFromJulianDay`). The functionality of `JulianDayFromDate` and `DateFromJulianDay` is now available from the methods `cftime.datetime.toordinal` and `cftime.datetime.fromordinal`. 2/2/2021: Version 1.4.1 released. Restore use of calendar-specific subclasses in `cftime.num2date`, `cftime.datetime.__add__`, and `cftime.datetime.__sub__`. The use of this will be removed in a later release. Add 'fromordinal' static method to create a cftime.datetime instance from a julian day ordinal and calendar (inverse of 'toordinal'). 2/1/2021: Version 1.4.0 released. License changed to MIT (GPL'ed code replaced). Roundtrip accuracy improved for units other than microseconds. Added cftime.datetime.toordinal method, returns integer julian day number. 1/17/2021: Version 1.3.1 released. 11/16/2020: Version 1.3.0 released. **API change**: The `cftime.datetime` constructor now creates 'calendar-aware' instances (default is `'standard'` calendar, if `calendar=''` or `None` the instance is not calendar aware and some methods, like `dayofwk`, `dayofyr`, `__add__` and `__sub__`, will not work) See discussion for issue [#198](https://github.com/Unidata/cftime/issues/198). The calendar specific sub-classes are now deprecated, but remain for now as stubs that just instantiate the base class and override `__repr__`. The default calendar in `cftime.date2num` has been changed from `'standard'` to `None` (the calendar associated with first input datetime object is used to define the calendar). 07/20/2020: Version 1.2.1 released. Fixes a couple of regressions introduced in 1.2.0. See Changelog for details. 7/06/2020: version 1.2.0 released. New microsecond accurate algorithm for date2num/num2date contributed by [spencerkclark](https://github.com/spencerkclark). Bugs fixed in masked array handling. 5/12/2020: version 1.1.3 released. Add isoformat method for compatibility with python datetime (issue #152). Make 'standard' default calendar for cftime.datetime so that dayofwk,dayofyr methods don't fail (issue #169). 4/20/2020: version 1.1.2 released. Code optimization, fix logic so `only_use_cftime_datetimes=False` works as expected (issues [#158](https://github.com/Unidata/cftime/issues/158) and [#165](https://github.com/Unidata/cftime/issues/165)). 3/16/2020: version 1.1.1 released. Fix bug in microsecond formatting, ensure identical num2date results if input is an array of times, or a single scalar ([issue #143](https://github.com/Unidata/cftime/issues/143)). 2/12/2020: version 1.1.0 released. `cftime.datetime` instances are returned by default from `num2date` (instead of returning python datetime instances where possible ([issue #136](https://github.com/Unidata/cftime/issues/136))). `num2pydate` convenience function added (always returns python datetime instances, [issue #134](https://github.com/Unidata/cftime/issues/134)). Fix for fraction seconds in reference date string ([issue #140](https://github.com/Unidata/cftime/issues/140)). Added `daysinmonth` attribute ([issue #137](https://github.com/Unidata/cftime/issues/137)). 10/25/2019: version 1.0.4.2 released (fix for [issue #126](https://github.com/Unidata/cftime/issues/126)). 10/21/2019: version 1.0.4 released. 12/05/2018: version 1.0.3.4 released (just to fix a problem with the source tarball on pypi). 12/05/2018: version 1.0.3.1 released. Bugfix release (fixed issue with installation when cython not installed, regression on 32-bit platforms, workaround for pandas compatibility). 12/01/2018: version 1.0.3 released. Test coverage with coveralls.io, improved round-tripping accuracy for non-real world calendars (like `360_day`). 10/27/2018: version 1.0.2 released. Improved accuracy (from approximately 1000 microseconds to 10 microseconds on x86 platforms). Refactored calendar calculations now allow for negative reference years. num2date function now more than an order of magnitude faster. `months since` units now allowed, but only for `360_day` calendar. 08/15/2018: version 1.0.1 released. 11/8/2016: `cftime` was split out of the [netcdf4-python](https://github.com/Unidata/netcdf4-python) package. ## Quick Start * Clone GitHub repository (`git clone https://github.com/Unidata/cftime.git`), or get source tarball from [PyPI](https://pypi.python.org/pypi/cftime). Links to Windows and OS X precompiled binary packages are also available on [PyPI](https://pypi.python.org/pypi/cftime). * Make sure [numpy](http://www.numpy.org/) and [Cython](http://cython.org/) are installed and you have [Python](https://www.python.org) 2.7 or newer. * Run `python setup.py build`, then `python setup.py install` (with `sudo` if necessary). * To run all the tests, execute `py.test`. ## Documentation See the online [docs](http://unidata.github.io/cftime) for more details. cftime-1.6.4rel/README.release000066400000000000000000000021601463037501200157730ustar00rootroot00000000000000* create a release branch ('vX.Y.Zrel'). In the release branch... * make sure version number in cftime/_cftime.pyx is correct. * update README.md as needed. * commit and push all of the above changes. * create a pull request for the release branch. * After release branch has been merged, tag a release % git tag -a vX.Y.Zrel -m "version X.Y.Z release" % git push origin --tags Then create a release on github from that tag. * Update the BUILD_COMMIT variable in .travis.yml and appveyor.yml in https://github.com/MacPython/cftime-wheels. Push those changes to trigger the binary wheel builds (for macos x, linux and windows). * run check-manifest --verbose to check that source tarball will be OK. * Download the binary wheels from wheels.scipy.org, put them in a directory called 'upload'. Create a source tarball using % python setup.py clean % python setup.py clean_cython % python setup.py sdist Add the source tarball to the 'upload' directory. * upload the release files to pypi with twine (twine upload upload/*). This will require creating a ~/.pypirc file with your pypi login credentials. cftime-1.6.4rel/ci/000077500000000000000000000000001463037501200140705ustar00rootroot00000000000000cftime-1.6.4rel/ci/deploy_docs.sh000077500000000000000000000022321463037501200167320ustar00rootroot00000000000000#!/bin/bash set -e # exit with nonzero exit code if anything fails export GH_PAGES_DIR="$HOME/gh-pages" # Decrypt and activate the deploy key echo Setting up access... openssl aes-256-cbc -K $encrypted_2f711532c6dd_key -iv $encrypted_2f711532c6dd_iv -in ${TRAVIS_BUILD_DIR}/ci/deploy_key.enc -out ${TRAVIS_BUILD_DIR}/ci/deploy_key -d chmod 600 ${TRAVIS_BUILD_DIR}/ci/deploy_key eval `ssh-agent -s` ssh-add ${TRAVIS_BUILD_DIR}/ci/deploy_key # Clone *this* git repo, but only the gh-pages branch. echo Cloning gh-pages... if [[ ! -d $GH_PAGES_DIR ]]; then git clone -q -b gh-pages --single-branch git@github.com:${TRAVIS_REPO_SLUG}.git $GH_PAGES_DIR fi cd $GH_PAGES_DIR # inside this git repo we'll pretend to be a new user git config user.name "Travis CI" git config user.email "travis@nobody.org" # The first and only commit to this new Git repo contains all the # files present with the commit message "Deploy to GitHub Pages". echo Updating docs... rm -rf * cp -R ${TRAVIS_BUILD_DIR}/docs/_build/html/* ./ touch .nojekyll echo Staging... git add -A . git commit --amend --reset-author --no-edit # Push up to gh-pages echo Pushing... git push --force origin gh-pages cftime-1.6.4rel/ci/deploy_key.enc000066400000000000000000000062601463037501200167270ustar00rootroot00000000000000 >r$xI{C~.g|˜@΀? e/uAv k3$I$O*x9U 0@#V| g3CEZvܮbP- 9\:X&:=Ć]W1\VL9W+!&&7>ojmW/tQp`i+(=4N>-ao40cŭH=r6eymw{BIfin-8835:FOf9y3=wp%L )@P5*X=i5,tt,-V*RԐiNM$m ^ Ccj~TG)ViWq`Ctn#I%;LA6{"ehr)8poUo0R7 ,Zi!Zmjr[W\uqpxD;p y+Ї Zolt(*>sEke Kƅ kPIFQ=p7QCWohz[- 6 xf+%0GGBu;oŨ)աFuB{%ơ''b~Eh )2)PJA0G̅ BuQD2~恆[3ysI";Mb62bub/PԂ#{ ǷcG2%<j %𒔌<_.lQ&NJo=k}u[a@xb- [Fi ɵJ#S*gn,R9,˯AeDEdYsY+կBHģ4(y :n"+ERr ,0Oqd-,@d=ϵE$yIƍ#묣=Ns^50ްǟ"lu#mgaCy!ۃܔ*nod@AWwƆR¯Um!y :;7pYbwCaWao_ʹnm/GUдM^\w:p 4ln6g#PԠ{doc(_H'ip=K3'8,h}ZL2X%P1?u]nLq>sX$!Cgr`rT1c~3mcy"vr9v"y݈Bɡ[@\줚*IJ6_黑Vx7@̺a &@!4 t9Sȵiڰ"lZ8MZJFzffIWp onb1)| g62PR9EB˶}av(ljg?9î2/mK7;t_Cng3-б0mHㄸNU~R ;1o1dR nA`QJGA'A9! fYLGrN[%J(yg}a㸥˜tp}#BMSrPwuvlPDZ71viw;tF]ZhYP-:]?d={ѵVUPKO ŔlےY+l9#`Dz$!(BUumdmIG~96A)|,!ddIv]M[nv1L`NO;܃dX1U֥ɨT rϺ Xl|z'{£WQKZ4Cwdᒧ;tƝ9c7фғ*:pLטب3Nt}QShi=@-B(EHޯKX)RrSGߐ*V%㖝&1&)+8.TqoTH53?&Z>`O|\ #,o)8ǮVY2(nh#t߰#ngՒ`"O''5[dTQ"}H<$ݒ7h9Sx .mC)g:{&o]L"KZ+{yy1}MTGO>_j5?WԱ? {!M|u78M/%QrKwFly}P۲s1Mj R.LdDjVhgؔą[( +@ǡnG;0^Qׅ% ixq-0t+8sZu qg}>:Ka,K:VTc\=iJ{7&  7TG]d\5J:50ob&Q2a/J؊S h`$Iй W$0r=" zS R,j!r_q\j?9Zcŭwq͉^J4Ui /ޣra~ncftime-1.6.4rel/docs/000077500000000000000000000000001463037501200144255ustar00rootroot00000000000000cftime-1.6.4rel/docs/Makefile000066400000000000000000000011341463037501200160640ustar00rootroot00000000000000# Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SPHINXPROJ = cftime SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) cftime-1.6.4rel/docs/api.rst000066400000000000000000000002341463037501200157270ustar00rootroot00000000000000API === .. automodule:: cftime :members: datetime, date2num, num2date, num2pydate, date2index, time2index, is_leap_year, to_tuple :show-inheritance: cftime-1.6.4rel/docs/conf.py000066400000000000000000000117361463037501200157340ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/stable/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- Project information ----------------------------------------------------- project = 'cftime' copyright = '2018, Jeff Whitaker' author = 'Jeff Whitaker' # The short X.Y version version = '' # The full version, including alpha/beta/rc tags release = '1.0' # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # # source_suffix = ['.rst', '.md'] source_suffix = '.rst' # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = 'en' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # html_theme = 'alabaster' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. # # html_theme_options = {} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". # html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. # # The default sidebars (for documents that don't match any pattern) are # defined by theme itself. Builtin themes are using these templates by # default: ``['localtoc.html', 'relations.html', 'sourcelink.html', # 'searchbox.html']``. # # html_sidebars = {} # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'cftimedoc' # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'cftime.tex', 'cftime Documentation', 'Jeff Whitaker', 'manual'), ] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'cftime', 'cftime Documentation', [author], 1) ] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'cftime', 'cftime Documentation', author, 'cftime', 'One line description of project.', 'Miscellaneous'), ] # -- Extension configuration ------------------------------------------------- # -- Options for intersphinx extension --------------------------------------- # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} cftime-1.6.4rel/docs/index.html000066400000000000000000000001101463037501200164120ustar00rootroot00000000000000 cftime-1.6.4rel/docs/index.rst000066400000000000000000000006161463037501200162710ustar00rootroot00000000000000cftime ====== Python library for decoding time units and variable values in a netCDF file conforming to the `Climate and Forecasting (CF) netCDF conventions `__. Contents -------- .. toctree:: :maxdepth: 2 installing api Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` cftime-1.6.4rel/docs/installing.rst000066400000000000000000000021071463037501200173230ustar00rootroot00000000000000Installation ============ Required dependencies --------------------- - Python: >=3.7 - `numpy `__ (1.13.3 or later) Instructions ------------ The easiest way to get everything installed is to use conda_ command line tool:: $ conda install cftime .. _conda: https://docs.conda.io/en/latest/ We recommend using the community maintained `conda-forge `__ channel if you need difficult\-to\-build dependencies such as cartopy or pynio:: $ conda install -c conda-forge cftime New releases may also appear in conda-forge before being updated in the default channel. If you don't use conda, be sure you have the required dependencies (numpy and cython) installed first. Then, install cftime with pip:: $ pip install cftime Developing ---------- When developing we recommend cloning the GitHub repository, building the extension in-place with `cython `__ 0.19 or later ``python setup.py build_ext --inplace`` and running the test suite to check if the changes are passing the tests ``pytest --pyargs test`` cftime-1.6.4rel/docs/make.bat000066400000000000000000000014521463037501200160340ustar00rootroot00000000000000@ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. set BUILDDIR=_build set SPHINXPROJ=cftime if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% :end popd cftime-1.6.4rel/pyproject.toml000066400000000000000000000003551463037501200164140ustar00rootroot00000000000000[build-system] requires = [ "setuptools>=41.2", "cython>=0.29.20", "wheel", "oldest-supported-numpy ; python_version < '3.9'", "numpy>=2.0.0rc1,<3 ; python_version >= '3.9'", ] build-backend = "setuptools.build_meta" cftime-1.6.4rel/requirements-dev.txt000066400000000000000000000001271463037501200175350ustar00rootroot00000000000000check-manifest coverage coveralls cython>=0.29.20 pytest pytest-cov sphinx twine wheel cftime-1.6.4rel/requirements.txt000066400000000000000000000001301463037501200167530ustar00rootroot00000000000000numpy>1.13.3; python_version<'3.12.0.rc1' numpy>=1.26.0b1; python_version>='3.12.0.rc1' cftime-1.6.4rel/setup.cfg000066400000000000000000000005361463037501200153220ustar00rootroot00000000000000[tool:pytest] testpaths = test addopts = -ra -v --doctest-modules --cov-config .coveragerc --cov=cftime --cov-report term-missing doctest_optionflags = NORMALIZE_WHITESPACE ELLIPSIS [check-manifest] ignore = *.yml .coveragerc .gitignore README.release ci ci/* docs docs/* test test/* cftime-1.6.4rel/setup.py000066400000000000000000000112721463037501200152120ustar00rootroot00000000000000import os import sys import numpy from setuptools import Command, Extension, setup # https://github.com/Unidata/cftime/issues/34 try: from Cython.Build import cythonize except ImportError: cythonize = False BASEDIR = os.path.abspath(os.path.dirname(__file__)) SRCDIR = os.path.join(BASEDIR,'src') CMDS_NOCYTHONIZE = ['clean','clean_cython','sdist'] COMPILER_DIRECTIVES = { # Cython 3.0.0 changes the default of the c_api_binop_methods directive to # False, resulting in errors in datetime and timedelta arithmetic: # https://github.com/Unidata/cftime/issues/271. We explicitly set it to # True to retain Cython 0.x behavior for future Cython versions. This # directive was added in Cython version 0.29.20. "c_api_binop_methods": True } COVERAGE_COMPILER_DIRECTIVES = { "linetrace": True, "warn.maybe_uninitialized": False, "warn.unreachable": False, "warn.unused": False, } DEFINE_MACROS = [("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")] FLAG_COVERAGE = '--cython-coverage' # custom flag enabling Cython line tracing NAME = 'cftime' CFTIME_DIR = os.path.join(SRCDIR, NAME) CYTHON_FNAME = os.path.join(CFTIME_DIR, '_{}.pyx'.format(NAME)) class CleanCython(Command): description = 'Purge artifacts built by Cython' user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): for rpath, _, fnames in os.walk(CFTIME_DIR): for fname in fnames: _, ext = os.path.splitext(fname) if ext in ('.pyc', '.pyo', '.c', '.so'): artifact = os.path.join(rpath, fname) if os.path.exists(artifact): print('clean: removing file {!r}'.format(artifact)) os.remove(artifact) else: print('clean: skipping file {!r}'.format(artifact)) def extract_version(): version = None with open(CYTHON_FNAME) as fi: for line in fi: if (line.startswith('__version__')): _, version = line.split('=') version = version.strip()[1:-1] # Remove quotation characters. break return version def load(fname): result = [] with open(fname, 'r') as fi: result = [package.strip() for package in fi.readlines()] return result def description(): fname = os.path.join(BASEDIR, 'README.md') with open(fname, 'r') as fi: result = ''.join(fi.readlines()) return result if ((FLAG_COVERAGE in sys.argv or os.environ.get('CYTHON_COVERAGE', None)) and cythonize): COMPILER_DIRECTIVES = { **COMPILER_DIRECTIVES, **COVERAGE_COMPILER_DIRECTIVES } DEFINE_MACROS += [('CYTHON_TRACE', '1'), ('CYTHON_TRACE_NOGIL', '1')] if FLAG_COVERAGE in sys.argv: sys.argv.remove(FLAG_COVERAGE) print('enable: "linetrace" Cython compiler directive') # See https://github.com/Unidata/cftime/issues/91 if any([arg in CMDS_NOCYTHONIZE for arg in sys.argv]): ext_modules = [] else: extension = Extension('{}._{}'.format(NAME, NAME), sources=[CYTHON_FNAME], define_macros=DEFINE_MACROS, include_dirs=[numpy.get_include(),]) ext_modules = [extension] if cythonize: ext_modules = cythonize(extension, compiler_directives=COMPILER_DIRECTIVES, language_level=3) setup( name=NAME, author='Jeff Whitaker', author_email='jeffrey.s.whitaker@noaa.gov', description='Time-handling functionality from netcdf4-python', long_description=description(), long_description_content_type='text/markdown', cmdclass={'clean_cython': CleanCython}, packages=[NAME], package_dir={'':'src'}, version=extract_version(), ext_modules=ext_modules, install_requires=load('requirements.txt'), tests_require=load('requirements-dev.txt'), license='License :: OSI Approved :: MIT License', python_requires=">=3.8", classifiers=[ 'Development Status :: 5 - Production/Stable', 'Operating System :: MacOS :: MacOS X', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Topic :: Scientific/Engineering', 'License :: OSI Approved :: MIT License'], ) cftime-1.6.4rel/src/000077500000000000000000000000001463037501200142645ustar00rootroot00000000000000cftime-1.6.4rel/src/cftime/000077500000000000000000000000001463037501200155335ustar00rootroot00000000000000cftime-1.6.4rel/src/cftime/__init__.py000066400000000000000000000012131463037501200176410ustar00rootroot00000000000000from ._cftime import (datetime, real_datetime, _parse_date, _dateparse, _datesplit, is_leap_year) from ._cftime import num2date, date2num, date2index, time2index, num2pydate, to_tuple from ._cftime import (microsec_units, millisec_units, sec_units, hr_units, day_units, min_units, UNIT_CONVERSION_FACTORS) from ._cftime import __version__, CFWarning # these will be removed in a future release from ._cftime import (DatetimeNoLeap, DatetimeAllLeap, Datetime360Day, Datetime360Day, DatetimeJulian, DatetimeGregorian, DatetimeProlepticGregorian) cftime-1.6.4rel/src/cftime/_cftime.pyx000066400000000000000000002663241463037501200177200ustar00rootroot00000000000000""" Performs conversions of netCDF time coordinate data to/from datetime objects. """ from cpython.object cimport (PyObject_RichCompare, Py_LT, Py_LE, Py_EQ, Py_NE, Py_GT, Py_GE) from numpy cimport int64_t, int32_t import cython import numpy as np cimport numpy as np import re import time from datetime import datetime as datetime_python from datetime import timedelta, MINYEAR, MAXYEAR import warnings from ._strptime import _strptime np.import_array() microsec_units = ['microseconds','microsecond', 'microsec', 'microsecs'] millisec_units = ['milliseconds', 'millisecond', 'millisec', 'millisecs', 'msec', 'msecs', 'ms'] sec_units = ['second', 'seconds', 'sec', 'secs', 's'] min_units = ['minute', 'minutes', 'min', 'mins'] hr_units = ['hour', 'hours', 'hr', 'hrs', 'h'] day_units = ['day', 'days', 'd'] month_units = ['month', 'months'] # only allowed for 360_day calendar year_units = ['common_year', 'common_years'] # only allowed for 365_day and noleap calendars _units = microsec_units+millisec_units+sec_units+min_units+hr_units+day_units # supported calendars. Includes synonyms ('standard'=='gregorian', # '366_day'=='all_leap','365_day'=='noleap') # see http://cfconventions.org/cf-conventions/cf-conventions#calendar # for definitions. _calendars = ['standard', 'gregorian', 'proleptic_gregorian', 'noleap', 'julian', 'all_leap', '365_day', '366_day', '360_day'] _idealized_calendars= ['all_leap','noleap','366_day','365_day','360_day'] # Following are number of days per month cdef int[12] _dayspermonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] cdef int[12] _dayspermonth_leap = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] # same as above, but including accumulated days of previous months. cdef int[13] _cumdayspermonth = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365] cdef int[13] _cumdayspermonth_leap = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366] __version__ = '1.6.4' # Adapted from http://delete.me.uk/2005/03/iso8601.html # Note: This regex ensures that all ISO8601 timezone formats are accepted - but, due to legacy support for other timestrings, not all incorrect formats can be rejected. # For example, the TZ spec "+01:0" will still work even though the minutes value is only one character long. ISO8601_REGEX = re.compile(r"(?P[+-]?[0-9]+)(-(?P[0-9]{1,2})(-(?P[0-9]{1,2})" r"(((?P.)(?P[0-9]{1,2}):(?P[0-9]{1,2})(:(?P[0-9]{1,2})(\.(?P[0-9]+))?)?)?" r"((?P.?)(?PZ|(([-+])([0-9]{2})((:([0-9]{2}))|([0-9]{2}))?)))?)?)?)?" ) # Note: The re module apparently does not support branch reset groups that allow redefinition of the same group name in alternative branches as PCRE does. # Using two different group names is also somewhat ugly, but other solutions might hugely inflate the expression. feel free to contribute a better solution. TIMEZONE_REGEX = re.compile( "(?P[+-])(?P[0-9]{2})(?:(?::(?P[0-9]{2}))|(?P[0-9]{2}))?") class real_datetime(datetime_python): """add dayofwk, dayofyr, daysinmonth attributes to python datetime instance""" @property def dayofwk(self): # 0=Monday, 6=Sunday return self.weekday() @property def dayofyr(self): return self.timetuple().tm_yday @property def daysinmonth(self): if _is_leap(self.year,'proleptic_gregorian'): return _dayspermonth_leap[self.month-1] else: return _dayspermonth[self.month-1] nanosecond = 0 # workaround for pandas bug (cftime issue #77) def _datesplit(timestr): """split a time string into two components, units and the remainder after 'since' """ try: (units, sincestring, remainder) = timestr.split(None,2) except ValueError as e: raise ValueError('Incorrectly formatted CF date-time unit_string') if sincestring.lower() != 'since': raise ValueError("no 'since' in unit_string") return units.lower(), remainder def _dateparse(timestr,calendar,has_year_zero=None): """parse a string of the form time-units since yyyy-mm-dd hh:mm:ss, return a datetime instance""" # same as version in cftime, but returns a timezone naive # python datetime instance with the utc_offset included. calendar = calendar.lower() # set calendar-specific defaults for has_year_zero if has_year_zero is None: has_year_zero = _year_zero_defaults(calendar) (units, isostring) = _datesplit(timestr) if not ((units in month_units and calendar=='360_day') or (units in year_units and calendar in {'365_day', 'noleap'}) or units in _units): if units in month_units and calendar != '360_day': raise ValueError("'months since' units only allowed for '360_day' calendar") if units in year_units and calendar not in {'365_day', 'noleap'}: raise ValueError("'%s' units only allowed for '365_day' and 'noleap' calendars" % units) else: raise ValueError( "In general, units must be one of 'microseconds', 'milliseconds', " "'seconds', 'minutes', 'hours', or 'days' (or select abbreviated " "versions of these). For the '360_day' calendar, " "'months' can also be used, or for the 'noleap' calendar 'common_years' " "can also be used. Got '%s' instead, which are not recognized." % units) # parse the date string. year, month, day, hour, minute, second, microsecond, utc_offset =\ _parse_date( isostring.strip() ) if year == 0 and not has_year_zero and calendar in ['julian', 'standard', 'gregorian', 'proleptic_gregorian']: msg='zero not allowed as a reference year when has_year_zero=False' raise ValueError(msg) if calendar in ['noleap', '365_day'] and month == 2 and day == 29: raise ValueError( 'cannot specify a leap day as the reference time with the noleap calendar') if calendar == '360_day' and day > 30: raise ValueError( 'there are only 30 days in every month with the 360_day calendar') basedate = datetime(year, month, day, hour, minute, second, microsecond,calendar=calendar,has_year_zero=has_year_zero) # subtract utc_offset from basedate time instance (which is timezone naive) if utc_offset: basedate -= timedelta(days=utc_offset/1440.) return basedate def _can_use_python_datetime(date,calendar): #gregorian = datetime(1582,10,15,calendar=calendar,has_year_zero=date.has_year_zero) #return ((calendar == 'proleptic_gregorian' and date.year >= MINYEAR and date.year <= MAXYEAR) or \ # (calendar in ['gregorian','standard'] and date > gregorian and date.year <= MAXYEAR)) return (calendar == 'proleptic_gregorian' and date.year >= MINYEAR and date.year <= MAXYEAR) or \ ((calendar in ['gregorian','standard'] and date.year <= MAXYEAR) and (date.year > 1582 or \ (date.year == 1582 and date.month >= 10 and date.day > 15))) @cython.embedsignature(True) def date2num(dates, units, calendar=None, has_year_zero=None, longdouble=False): """ Return numeric time values given datetime objects. The units of the numeric time values are described by the **units** argument and the **calendar** keyword. The datetime objects must be in UTC with no time-zone offset. If there is a time-zone offset in **units**, it will be applied to the returned numeric values. **dates**: A datetime object or a sequence of datetime objects. The datetime objects should not include a time-zone offset. They can be either native python datetime instances (which use the proleptic gregorian calendar) or cftime.datetime instances. **units**: a string of the form **