[Git][debian-gis-team/cftime][upstream] 2 commits: New upstream version 1.1.0
Bas Couwenberg
gitlab at salsa.debian.org
Fri Feb 14 06:08:41 GMT 2020
Bas Couwenberg pushed to branch upstream at Debian GIS Project / cftime
Commits:
aec29138 by Bas Couwenberg at 2020-02-14T06:45:42+01:00
New upstream version 1.1.0
- - - - -
3b9efa37 by Bas Couwenberg at 2020-02-14T06:54:23+01:00
New upstream version 1.1.0+ds
- - - - -
11 changed files:
- .appveyor.yml
- .gitignore
- .travis.yml
- + Changelog
- README.md
- cftime/__init__.py
- cftime/_cftime.pyx
- docs/api.rst
- + docs/index.html
- setup.py
- test/test_cftime.py
Changes:
=====================================
.appveyor.yml
=====================================
@@ -1,16 +1,17 @@
environment:
- CONDA_INSTALL_LOCN: C:\\Miniconda36-x64
+ PYTHON: "C:\\myminiconda3"
matrix:
- - TARGET_ARCH: x64
- NPY: 1.16
- PY: 3.6
- TARGET_ARCH: x64
- NPY: 1.16
+ NPY: 1.17
PY: 3.7
-platform:
- - x64
+ - TARGET_ARCH: x64
+ NPY: 1.17
+ PY: 3.8
+
+init:
+ - "ECHO %PYTHON_VERSION% %MINICONDA%"
install:
# If there is a newer build queued for the same PR, cancel this one.
@@ -24,18 +25,19 @@ install:
throw "There are newer queued builds for this pull request, failing early." }
# Add path, activate `conda` and update conda.
- - cmd: call %CONDA_INSTALL_LOCN%\Scripts\activate.bat
- - cmd: conda config --set always_yes yes --set changeps1 no --set show_channel_urls true
- - cmd: conda update conda
- - cmd: conda config --add channels conda-forge --force
- - cmd: conda config --set channel_priority strict
- - cmd: set PYTHONUNBUFFERED=1
- - cmd: conda install conda-build vs2008_express_vc_python_patch
- - cmd: call setup_x64
-
- - cmd: conda.exe create --name TEST python=%PY% numpy=%NPY% cython pip pytest pytest-cov
- - cmd: conda info --all
- - cmd: conda activate TEST
+
+ - set URL="https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe"
+ - curl -fsS -o miniconda3.exe %URL%
+ - start /wait "" miniconda3.exe /InstallationType=JustMe /RegisterPython=0 /S /D=%PYTHON%
+ - "set PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
+ - call %PYTHON%\Scripts\activate
+ - conda config --set always_yes yes --set changeps1 no --set show_channel_urls true
+ - conda config --add channels conda-forge --force
+ - set PYTHONUNBUFFERED=1
+ - conda install conda-build vs2008_express_vc_python_patch
+ - call setup_x64
+ - conda create --name TEST python=%PY% numpy=%NPY% cython pip pytest pytest-cov
+ - conda activate TEST
# Skip .NET project specific build phase.
build: off
=====================================
.gitignore
=====================================
@@ -4,6 +4,5 @@
build/
*.egg?
*.egg-info
-_build/
__pycache__
.pytest_cache/
=====================================
.travis.yml
=====================================
@@ -8,8 +8,8 @@ notifications:
env:
- PYTHON_VERSION=2.7
- - PYTHON_VERSION=3.6
- PYTHON_VERSION=3.7
+ - PYTHON_VERSION=3.8
matrix:
include:
=====================================
Changelog
=====================================
@@ -0,0 +1,29 @@
+version 1.1.0 (not yet released)
+================================
+
+ * 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.
=====================================
README.md
=====================================
@@ -10,6 +10,14 @@ Time-handling functionality from netcdf4-python
[![Commits Status](https://img.shields.io/github/commits-since/UniData/cftime/latest.svg)](https://github.com/UniData/cftime/commits/master)
## News
+For details on the latest updates, see the [Changelog](https://github.com/Unidata/cftime/blob/master/Changelog).
+
+2/12/2019: 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.
=====================================
cftime/__init__.py
=====================================
@@ -5,5 +5,5 @@ from ._cftime import DatetimeNoLeap, DatetimeAllLeap, Datetime360Day, DatetimeJu
DatetimeGregorian, DatetimeProlepticGregorian
from ._cftime import microsec_units, millisec_units, \
sec_units, hr_units, day_units, min_units
-from ._cftime import num2date, date2num, date2index
+from ._cftime import num2date, date2num, date2index, num2pydate
from ._cftime import __version__
=====================================
cftime/_cftime.pyx
=====================================
@@ -4,6 +4,7 @@ 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
import re
@@ -28,7 +29,7 @@ month_units = ['month', 'months'] # only allowed for 360_day calendar
_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.html#calendar
+# see http://cfconventions.org/cf-conventions/cf-conventions.html#calendar
# for definitions.
_calendars = ['standard', 'gregorian', 'proleptic_gregorian',
'noleap', 'julian', 'all_leap', '365_day', '366_day', '360_day']
@@ -39,11 +40,19 @@ cdef int[12] _dpm_360 = [30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30]
# Same as above, but SUM of previous months (no leap years).
cdef int[13] _spm_365day = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]
cdef int[13] _spm_366day = [0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366]
+
+# Slightly more performant cython lookups than a 2D table
+# The first 12 entries correspond to month lengths for non-leap years.
+# The remaining 12 entries give month lengths for leap years
+cdef int32_t* days_per_month_array = [
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31,
+ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
+
# Reverse operator lookup for datetime.__richcmp__
_rop_lookup = {Py_LT: '__gt__', Py_LE: '__ge__', Py_EQ: '__eq__',
Py_GT: '__lt__', Py_GE: '__le__', Py_NE: '__ne__'}
-__version__ = '1.0.4.2'
+__version__ = '1.1.0'
# 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.
@@ -57,8 +66,31 @@ ISO8601_REGEX = re.compile(r"(?P<year>[+-]?[0-9]{1,4})(-(?P<month>[0-9]{1,2})(-(
TIMEZONE_REGEX = re.compile(
"(?P<prefix>[+-])(?P<hours>[0-9]{2})(?:(?::(?P<minutes1>[0-9]{2}))|(?P<minutes2>[0-9]{2}))?")
+
+# Taken from pandas ccalendar.pyx
+ at cython.wraparound(False)
+ at cython.boundscheck(False)
+cpdef int32_t get_days_in_month(bint isleap, int month) nogil:
+ """
+ Return the number of days in the given month of the given year.
+ Parameters
+ ----------
+ leap : int [0,1]
+ month : int
+
+ Returns
+ -------
+ days_in_month : int
+ Notes
+ -----
+ Assumes that the arguments are valid. Passing a month not between 1 and 12
+ risks a segfault.
+ """
+ return days_per_month_array[12 * isleap + month - 1]
+
+
class real_datetime(datetime_python):
- """add dayofwk and dayofyr attributes to python datetime instance"""
+ """add dayofwk, dayofyr attributes to python datetime instance"""
@property
def dayofwk(self):
# 0=Monday, 6=Sunday
@@ -72,7 +104,7 @@ class real_datetime(datetime_python):
gregorian = real_datetime(1582,10,15)
def _datesplit(timestr):
- """split a time string into two components, units and the remainder
+ """split a time string into two components, units and the remainder
after 'since'
"""
try:
@@ -97,12 +129,14 @@ def _dateparse(timestr):
year, month, day, hour, minute, second, microsecond, utc_offset =\
_parse_date( isostring.strip() )
if year >= MINYEAR:
- basedate = real_datetime(year, month, day, hour, minute, second)
+ basedate = real_datetime(year, month, day, hour, minute, second,
+ microsecond)
# subtract utc_offset from basedate time instance (which is timezone naive)
basedate -= timedelta(days=utc_offset/1440.)
else:
if not utc_offset:
- basedate = datetime(year, month, day, hour, minute, second)
+ basedate = datetime(year, month, day, hour, minute, second,
+ microsecond)
else:
raise ValueError('cannot use utc_offset for reference years <= 0')
return basedate
@@ -215,8 +249,19 @@ def date2num(dates,units,calendar='standard'):
return cdftime.date2num(dates)
-def num2date(times,units,calendar='standard',only_use_cftime_datetimes=False):
- """num2date(times,units,calendar='standard')
+def num2pydate(times,units,calendar='standard'):
+ """num2pydate(times,units,calendar='standard')
+ Always returns python datetime.datetime
+ objects and raise an error if this is not possible.
+
+ Same as
+ num2date(times,units,calendar,only_use_cftime_datetimes=False,only_use_python_datetimes=True)
+ """
+ return num2date(times,units,calendar,only_use_cftime_datetimes=False,only_use_python_datetimes=True)
+
+def num2date(times,units,calendar='standard',\
+ only_use_cftime_datetimes=True,only_use_python_datetimes=False):
+ """num2date(times,units,calendar='standard',only_use_cftime_datetimes=True,only_use_python_datetimes=False)
Return datetime objects given numeric time values. The units
of the numeric time values are described by the `units` argument
@@ -238,40 +283,54 @@ def num2date(times,units,calendar='standard',only_use_cftime_datetimes=False):
'noleap', '365_day', '360_day', 'julian', 'all_leap', '366_day'`.
Default is `'standard'`, which is a mixed Julian/Gregorian calendar.
- **`only_use_cftime_datetimes`**: if False (default), datetime.datetime
+ **`only_use_cftime_datetimes`**: if False, python datetime.datetime
objects are returned from num2date where possible; if True dates which
- subclass cftime.datetime are returned for all calendars.
+ subclass cftime.datetime are returned for all calendars. Default `True`.
+
+ **`only_use_python_datetimes`**: always return python datetime.datetime
+ objects and raise an error if this is not possible. Ignored unless
+ `only_use_cftime_datetimes=False`. Default `False`.
returns a datetime instance, or an array of datetime instances with
approximately 100 microsecond accuracy.
- ***Note***: The datetime instances returned are 'real' python datetime
+ ***Note***: If only_use_cftime_datetimes=False and
+ use_only_python_datetimes=False, the datetime instances
+ returned are 'real' python datetime
objects if `calendar='proleptic_gregorian'`, or
`calendar='standard'` or `'gregorian'`
and the date is after the breakpoint between the Julian and
- Gregorian calendars (1582-10-15). Otherwise, they are 'phony' datetime
- objects which support some but not all the methods of 'real' python
+ Gregorian calendars (1582-10-15). Otherwise, they are ctime.datetime
+ objects which support some but not all the methods of native python
datetime objects. The datetime instances
do not contain a time-zone offset, even if the specified `units`
contains one.
"""
calendar = calendar.lower()
basedate = _dateparse(units)
+
+ can_use_python_datetime=\
+ ((calendar == 'proleptic_gregorian' and basedate.year >= MINYEAR) or \
+ (calendar in ['gregorian','standard'] and basedate > gregorian))
+ if not only_use_cftime_datetimes and only_use_python_datetimes:
+ if not can_use_python_datetime:
+ msg='illegal calendar or reference date for python datetime'
+ raise ValueError(msg)
+
(unit, ignore) = _datesplit(units)
+
# real-world calendars limited to positive reference years.
if calendar in ['julian', 'standard', 'gregorian', 'proleptic_gregorian']:
if basedate.year == 0:
msg='zero not allowed as a reference year, does not exist in Julian or Gregorian calendars'
raise ValueError(msg)
- postimes = (np.asarray(times) > 0).all() # netcdf4-python issue #659
- if only_use_cftime_datetimes:
+ if only_use_cftime_datetimes or not \
+ (only_use_python_datetimes and can_use_python_datetime):
cdftime = utime(units, calendar=calendar,
only_use_cftime_datetimes=only_use_cftime_datetimes)
return cdftime.num2date(times)
- elif postimes and ((calendar == 'proleptic_gregorian' and basedate.year >= MINYEAR) or \
- (calendar in ['gregorian','standard'] and basedate > gregorian)):
- # use python datetime module,
+ else: # use python datetime module
isscalar = False
try:
times[0]
@@ -313,15 +372,17 @@ def num2date(times,units,calendar='standard',only_use_cftime_datetimes=False):
msecs = np.round(msecsd - secs*1.e6)
td = timedelta(days=days,seconds=secs,microseconds=msecs)
# add time delta to base date.
- date = basedate + td
+ try:
+ date = basedate + td
+ except OverflowError:
+ msg="""
+OverflowError in python datetime, probably because year < datetime.MINYEAR"""
+ raise ValueError(msg)
dates.append(date)
if isscalar:
return dates[0]
else:
return np.reshape(np.array(dates), shape)
- else: # use cftime for other calendars
- cdftime = utime(units,calendar=calendar)
- return cdftime.num2date(times)
def date2index(dates, nctime, calendar=None, select='exact'):
@@ -435,7 +496,7 @@ def JulianDayFromDate(date, calendar='standard'):
else:
return jd
-def DateFromJulianDay(JD, calendar='standard', only_use_cftime_datetimes=False,
+def DateFromJulianDay(JD, calendar='standard', only_use_cftime_datetimes=True,
return_tuple=False):
"""
@@ -451,10 +512,9 @@ def DateFromJulianDay(JD, calendar='standard', only_use_cftime_datetimes=False,
If only_use_cftime_datetimes is set to True, then cftime.datetime
objects are returned for all calendars. Otherwise the datetime object is a
- 'real' datetime object if the date falls in the Gregorian calendar
+ native python datetime object if the date falls in the Gregorian calendar
(i.e. calendar='proleptic_gregorian', or calendar = 'standard'/'gregorian'
- and the date is after 1582-10-15). In all other cases a 'phony' datetime
- objects are used, which are actually instances of cftime.datetime.
+ and the date is after 1582-10-15).
"""
julian = np.atleast_1d(np.array(JD, dtype=np.longdouble))
@@ -640,16 +700,15 @@ leap year if it is divisible by 4.
The C{L{num2date}} and C{L{date2num}} class methods can used to convert datetime
instances to/from the specified time units using the specified calendar.
-The datetime instances returned by C{num2date} are 'real' python datetime
+The datetime instances returned by C{num2date} are native python datetime
objects if the date falls in the Gregorian calendar (i.e.
C{calendar='proleptic_gregorian', 'standard'} or C{'gregorian'} and
-the date is after 1582-10-15). Otherwise, they are 'phony' datetime
+the date is after 1582-10-15). Otherwise, they are native datetime
objects which are actually instances of C{L{cftime.datetime}}. This is
because the python datetime module cannot handle the weird dates in some
calendars (such as C{'360_day'} and C{'all_leap'}) which don't exist in any real
world calendar.
-
Example usage:
>>> from cftime import utime
@@ -690,7 +749,7 @@ it should be noted that udunits treats 0 AD as identical to 1 AD."
"""
def __init__(self, unit_string, calendar='standard',
- only_use_cftime_datetimes=False):
+ only_use_cftime_datetimes=True):
"""
@param unit_string: a string of the form
C{'time-units since <time-origin>'} defining the time units.
@@ -723,9 +782,9 @@ are:
Proleptic Julian calendar, extended to dates after 1582-10-5. A year is a
leap year if it is divisible by 4.
- at keyword only_use_cftime_datetimes: if False (default), datetime.datetime
+ at keyword only_use_cftime_datetimes: if False, datetime.datetime
objects are returned from num2date where possible; if True dates which subclass
-cftime.datetime are returned for all calendars.
+cftime.datetime are returned for all calendars. Default True.
@returns: A class instance which may be used for converting times from netCDF
units to datetime objects.
@@ -823,10 +882,10 @@ units to datetime objects.
Works for scalars, sequences and numpy arrays.
Returns a scalar if input is a scalar, else returns a numpy array.
- The datetime instances returned by C{num2date} are 'real' python datetime
+ The datetime instances returned by C{num2date} are native python datetime
objects if the date falls in the Gregorian calendar (i.e.
C{calendar='proleptic_gregorian'}, or C{calendar = 'standard'/'gregorian'} and
- the date is after 1582-10-15). Otherwise, they are 'phony' datetime
+ the date is after 1582-10-15). Otherwise, they are cftime.datetime
objects which are actually instances of cftime.datetime. This is
because the python datetime module cannot handle the weird dates in some
calendars (such as C{'360_day'} and C{'all_leap'}) which
@@ -1184,7 +1243,7 @@ The base class implementing most methods of datetime classes that
mimic datetime.datetime but support calendars other than the proleptic
Gregorial calendar.
"""
- cdef readonly int year, month, day, hour, minute, dayofwk, dayofyr
+ cdef readonly int year, month, day, hour, minute, dayofwk, dayofyr, daysinmonth
cdef readonly int second, microsecond
cdef readonly str calendar
@@ -1208,7 +1267,7 @@ Gregorial calendar.
self.second = second
self.microsecond = microsecond
self.calendar = ""
-
+ self.daysinmonth = -1
self.datetime_compatible = True
@property
@@ -1368,7 +1427,12 @@ Gregorial calendar.
elif isinstance(other, datetime_python):
# datetime - real_datetime
if not dt.datetime_compatible:
- raise ValueError("cannot compute the time difference between dates with different calendars")
+ msg="""
+Cannot compute the time difference between dates with different calendars.
+One of the datetime objects may have been converted to a native python
+datetime instance. Try using only_use_cftime_datetimes=True when creating the
+datetime object."""
+ raise ValueError(msg)
return dt._to_real_datetime() - other
elif isinstance(other, timedelta):
# datetime - timedelta
@@ -1379,7 +1443,12 @@ Gregorial calendar.
if isinstance(self, datetime_python):
# real_datetime - datetime
if not other.datetime_compatible:
- raise ValueError("cannot compute the time difference between dates with different calendars")
+ msg="""
+Cannot compute the time difference between dates with different calendars.
+One of the datetime objects may have been converted to a native python
+datetime instance. Try using only_use_cftime_datetimes=True when creating the
+datetime object."""
+ raise ValueError(msg)
return self - other._to_real_datetime()
else:
return NotImplemented
@@ -1402,6 +1471,7 @@ but uses the "noleap" ("365_day") calendar.
DateFromJulianDay(jd,return_tuple=True,calendar='365_day')
self.dayofwk = dayofwk
self.dayofyr = dayofyr
+ self.daysinmonth = _dpm[self.month-1]
cdef _add_timedelta(self, delta):
return DatetimeNoLeap(*add_timedelta(self, delta, no_leap, False))
@@ -1424,6 +1494,7 @@ but uses the "all_leap" ("366_day") calendar.
DateFromJulianDay(jd,return_tuple=True,calendar='366_day')
self.dayofwk = dayofwk
self.dayofyr = dayofyr
+ self.daysinmonth = _dpm_leap[self.month-1]
cdef _add_timedelta(self, delta):
return DatetimeAllLeap(*add_timedelta(self, delta, all_leap, False))
@@ -1446,6 +1517,7 @@ but uses the "360_day" calendar.
DateFromJulianDay(jd,return_tuple=True,calendar='360_day')
self.dayofwk = dayofwk
self.dayofyr = dayofyr
+ self.daysinmonth = 30
cdef _add_timedelta(self, delta):
return Datetime360Day(*add_timedelta_360_day(self, delta))
@@ -1468,6 +1540,7 @@ but uses the "julian" calendar.
DateFromJulianDay(jd,return_tuple=True,calendar='julian')
self.dayofwk = dayofwk
self.dayofyr = dayofyr
+ self.daysinmonth = get_days_in_month(_is_leap(self.year, self.calendar), self.month)
cdef _add_timedelta(self, delta):
return DatetimeJulian(*add_timedelta(self, delta, is_leap_julian, False))
@@ -1504,6 +1577,7 @@ a datetime.datetime instance or vice versa.
DateFromJulianDay(jd,return_tuple=True,calendar='gregorian')
self.dayofwk = dayofwk
self.dayofyr = dayofyr
+ self.daysinmonth = get_days_in_month(_is_leap(self.year, self.calendar), self.month)
cdef _add_timedelta(self, delta):
return DatetimeGregorian(*add_timedelta(self, delta, is_leap_gregorian, True))
@@ -1518,9 +1592,9 @@ Supports timedelta operations by overloading + and -.
Has strftime, timetuple, replace, __repr__, and __str__ methods. The
format of the string produced by __str__ is controlled by self.format
-(default %Y-%m-%d %H:%M:%S). Supports comparisons with other phony
+(default %Y-%m-%d %H:%M:%S). Supports comparisons with other
datetime instances using the same calendar; comparison with
-datetime.datetime instances is possible for cftime.datetime
+native python datetime instances is possible for cftime.datetime
instances using 'gregorian' and 'proleptic_gregorian' calendars.
Instance variables are year,month,day,hour,minute,second,microsecond,dayofwk,dayofyr,
@@ -1538,6 +1612,7 @@ format, and calendar.
DateFromJulianDay(jd,return_tuple=True,calendar='proleptic_gregorian')
self.dayofwk = dayofwk
self.dayofyr = dayofyr
+ self.daysinmonth = get_days_in_month(_is_leap(self.year, self.calendar), self.month)
cdef _add_timedelta(self, delta):
return DatetimeProlepticGregorian(*add_timedelta(self, delta,
@@ -1789,7 +1864,7 @@ cdef tuple add_timedelta_360_day(datetime dt, delta):
return (year, month, day, hour, minute, second, microsecond, -1, 1)
# Calendar calculations base on calcals.c by David W. Pierce
-# http://meteora.ucsd.edu/~pierce/calcalcs
+# http://meteora.ucsd.edu/~pierce/calcalcs
cdef _is_leap(int year, calendar):
cdef int tyear
=====================================
docs/api.rst
=====================================
@@ -2,6 +2,5 @@ API
===
.. automodule:: cftime
- :members: datetime, date2num, date2index, num2date, JulianDayFromDate, DatetimeJulian, DatetimeProlepticGregorian, DatetimeNoLeap, DatetimeAllLeap, DatetimeGregorian
+ :members: datetime, date2num, num2date, num2pydate, date2index, JulianDayFromDate, DatetimeJulian, DatetimeProlepticGregorian, DatetimeNoLeap, DatetimeAllLeap, DatetimeGregorian
:show-inheritance:
- :noindex:
\ No newline at end of file
=====================================
docs/index.html
=====================================
@@ -0,0 +1 @@
+<meta http-equiv="refresh" content="0; url=./_build/html/index.html" />
=====================================
setup.py
=====================================
@@ -2,6 +2,7 @@ from __future__ import print_function
import os
import sys
+import numpy
from setuptools import Command, Extension, setup
@@ -88,7 +89,8 @@ if any([arg in CMDS_NOCYTHONIZE for arg in sys.argv]):
else:
extension = Extension('{}._{}'.format(NAME, NAME),
sources=[CYTHON_FNAME],
- define_macros=DEFINE_MACROS)
+ define_macros=DEFINE_MACROS,
+ include_dirs=[numpy.get_include(),])
ext_modules = [extension]
if cythonize:
ext_modules = cythonize(extension,
=====================================
test/test_cftime.py
=====================================
@@ -440,7 +440,8 @@ class cftimeTestCase(unittest.TestCase):
err = np.abs(mins1 - mins2)
maxerr = max(err,maxerr)
assert(err < eps)
- assert(date1.strftime(dateformat) == date2.strftime(dateformat))
+ diff = abs(date1-date2)
+ assert(diff.microseconds < 100)
if verbose:
print('calendar = %s max abs err (mins) = %s eps = %s' % \
(calendar,maxerr,eps))
@@ -456,7 +457,8 @@ class cftimeTestCase(unittest.TestCase):
err = np.abs(hrs1 - hrs2)
maxerr = max(err,maxerr)
assert(err < eps)
- assert(date1.strftime(dateformat) == date2.strftime(dateformat))
+ diff = abs(date1-date2)
+ assert(diff.microseconds < 100)
if verbose:
print('calendar = %s max abs err (hours) = %s eps = %s' % \
(calendar,maxerr,eps))
@@ -472,7 +474,8 @@ class cftimeTestCase(unittest.TestCase):
err = np.abs(days1 - days2)
maxerr = max(err,maxerr)
assert(err < eps)
- assert(date1.strftime(dateformat) == date2.strftime(dateformat))
+ diff = abs(date1-date2)
+ assert(diff.microseconds < 100)
if verbose:
print('calendar = %s max abs err (days) = %s eps = %s' % \
(calendar,maxerr,eps))
@@ -616,6 +619,13 @@ class cftimeTestCase(unittest.TestCase):
assert (d.month == 1)
assert (d.day == 1)
assert (d.hour == 0)
+ # cftime issue #134
+ d = num2date(-657071, units, calendar='proleptic_gregorian',
+ only_use_cftime_datetimes=False,only_use_python_datetimes=True)
+ assert(d==datetime(1,1,1,0))
+ self.assertRaises(ValueError, num2date, \
+ -657072, units, calendar='proleptic_gregorian',
+ only_use_cftime_datetimes=False,only_use_python_datetimes=True)
# issue 685: wrong time zone conversion
# 'The following times all refer to the same moment: "18:30Z", "22:30+04", "1130-0700", and "15:00-03:30'
# (https://en.wikipedia.org/w/index.php?title=ISO_8601&oldid=787811367#Time_offsets_from_UTC)
@@ -715,6 +725,10 @@ class cftimeTestCase(unittest.TestCase):
d = cftime.DatetimeProlepticGregorian(1, 1, 1)
assert(cftime.date2num(d, 'days since 0001-01-01',\
'proleptic_gregorian') == 0.0)
+ # issue #140 (fractional seconds in reference date)
+ d = datetime.strptime('2018-01-23 09:27:10.950000',"%Y-%m-%d %H:%M:%S.%f")
+ units = 'seconds since 2018-01-23 09:31:42.94'
+ assert(cftime.date2num(d, units) == -271.99)
class TestDate2index(unittest.TestCase):
@@ -895,8 +909,9 @@ class TestDate2index(unittest.TestCase):
datetime(1995, 11, 25, 18, 7, 59, 999999)]
times2 = date2num(dates, units)
dates2 = num2date(times2, units)
- for date, date2 in zip(dates, dates2):
- assert_equal(date, date2)
+ datediff = abs(dates-dates2)
+ for diff in datediff:
+ assert(diff.microseconds < 100) # tolerance of 100 ms
def test_issue444(self):
# make sure integer overflow not causing error in
@@ -1488,6 +1503,16 @@ def test_dayofwk_after_replace(date_type):
assert result == expected
+def test_daysinmonth_non_leap(date_type, month, days_per_month_non_leap_year):
+ date = date_type(1, month, 1)
+ assert date.daysinmonth == days_per_month_non_leap_year
+
+
+def test_daysinmonth_leap(date_type, month, days_per_month_leap_year):
+ date = date_type(2000, month, 1)
+ assert date.daysinmonth == days_per_month_leap_year
+
+
@pytest.mark.parametrize('argument', ['dayofyr', 'dayofwk'])
def test_replace_dayofyr_or_dayofwk_error(date_type, argument):
with pytest.raises(ValueError):
View it on GitLab: https://salsa.debian.org/debian-gis-team/cftime/compare/71e924ac5b654426ca9465932e0c2748a0285dd8...3b9efa37703d58d35db66d9394c753043b881b50
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/cftime/compare/71e924ac5b654426ca9465932e0c2748a0285dd8...3b9efa37703d58d35db66d9394c753043b881b50
You're receiving this email because of your account on salsa.debian.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-grass-devel/attachments/20200214/0b50542d/attachment-0001.html>
More information about the Pkg-grass-devel
mailing list