[Git][debian-gis-team/cftime][upstream] New upstream version 1.2.0+ds
Bas Couwenberg
gitlab at salsa.debian.org
Mon Jul 6 04:48:30 BST 2020
Bas Couwenberg pushed to branch upstream at Debian GIS Project / cftime
Commits:
2153605f by Bas Couwenberg at 2020-07-06T05:42:01+02:00
New upstream version 1.2.0+ds
- - - - -
8 changed files:
- .travis.yml
- Changelog
- README.md
- cftime/__init__.py
- cftime/_cftime.pyx
- docs/api.rst
- docs/installing.rst
- test/test_cftime.py
Changes:
=====================================
.travis.yml
=====================================
@@ -9,8 +9,8 @@ notifications:
matrix:
fast_finish: true
include:
- - name: "python-2.7"
- env: PY=2.7
+# - name: "python-2.7"
+# env: PY=2.7
- name: "python-3.7"
env: PY=3.7
- name: "python-3.8"
@@ -20,6 +20,10 @@ matrix:
- name: "docs"
env: PY=3
+#jobs:
+# allow_failures:
+# - env: PY=2.7
+
before_install:
# Build the conda testing environment.
- >
=====================================
Changelog
=====================================
@@ -1,3 +1,19 @@
+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).
=====================================
README.md
=====================================
@@ -12,6 +12,8 @@ Time-handling functionality from netcdf4-python
## News
For details on the latest updates, see the [Changelog](https://github.com/Unidata/cftime/blob/master/Changelog).
+7/06/2020: version 1.2.0 released. New microsecond accurate algorithm for date2num/num2date contributed by @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).
=====================================
cftime/__init__.py
=====================================
@@ -1,4 +1,4 @@
-from ._cftime import utime, JulianDayFromDate, DateFromJulianDay
+from ._cftime import utime, JulianDayFromDate, DateFromJulianDay, UNIT_CONVERSION_FACTORS
from ._cftime import _parse_date, date2index, time2index
from ._cftime import datetime, real_datetime
from ._cftime import DatetimeNoLeap, DatetimeAllLeap, Datetime360Day, DatetimeJulian, \
=====================================
cftime/_cftime.pyx
=====================================
The diff for this file was not included because it is too large.
=====================================
docs/api.rst
=====================================
@@ -2,5 +2,5 @@ API
===
.. automodule:: cftime
- :members: datetime, date2num, num2date, num2pydate, date2index, JulianDayFromDate, DatetimeJulian, DatetimeProlepticGregorian, DatetimeNoLeap, DatetimeAllLeap, DatetimeGregorian
+ :members: datetime, date2num, num2date, num2pydate, date2index, JulianDayFromDate, DatetimeJulian, DatetimeProlepticGregorian, DatetimeNoLeap, DatetimeAllLeap, DatetimeGregorian, DateFromJulianDay, time2index
:show-inheritance:
=====================================
docs/installing.rst
=====================================
@@ -4,7 +4,7 @@ Installation
Required dependencies
---------------------
-- Python 2.7, 3.4, 3.5, or 3.6
+- Python: >3.2
- `numpy <http://www.numpy.org/>`__ (1.7 or later)
=====================================
test/test_cftime.py
=====================================
@@ -5,7 +5,7 @@ import operator
import sys
import unittest
from collections import namedtuple
-from datetime import datetime, timedelta
+from datetime import datetime, timedelta, MINYEAR
import numpy as np
import pytest
@@ -17,7 +17,7 @@ from cftime import real_datetime
from cftime import (DateFromJulianDay, Datetime360Day, DatetimeAllLeap,
DatetimeGregorian, DatetimeJulian, DatetimeNoLeap,
DatetimeProlepticGregorian, JulianDayFromDate, _parse_date,
- date2index, date2num, num2date, utime)
+ date2index, date2num, num2date, utime, UNIT_CONVERSION_FACTORS)
try:
from datetime import timezone
@@ -115,11 +115,8 @@ class cftimeTestCase(unittest.TestCase):
t1 = self.cdftime_mixed.date2num(d1)
d2 = datetime(1582, 10, 4, 18, tzinfo=est)
t2 = self.cdftime_mixed.date2num(d2)
- d3 = d2.replace(tzinfo=None)
- t3 = self.cdftime_mixed.date2num(d3)
assert_almost_equal(t1, 13865687.0)
- assert_almost_equal(t2, 13865687.0)
- assert_almost_equal(t3, 13865682.0)
+ assert_almost_equal(t2, 13865682.0) # est is 5 hours behind utc
def test_tz_naive(self):
"""testing cftime"""
@@ -380,7 +377,7 @@ class cftimeTestCase(unittest.TestCase):
ntimes = 1001
verbose = True # print out max error diagnostics
for calendar in calendars:
- eps = 100.
+ eps = 1.
units = 'microseconds since 2000-01-30 01:01:01'
microsecs1 = date2num(dateref,units,calendar=calendar)
maxerr = 0
@@ -397,7 +394,7 @@ class cftimeTestCase(unittest.TestCase):
print('calendar = %s max abs err (microsecs) = %s eps = %s' % \
(calendar,maxerr,eps))
units = 'milliseconds since 1800-01-30 01:01:01'
- eps = 0.1
+ eps = 0.001
millisecs1 = date2num(dateref,units,calendar=calendar)
maxerr = 0.
for n in range(ntimes):
@@ -412,7 +409,7 @@ class cftimeTestCase(unittest.TestCase):
if verbose:
print('calendar = %s max abs err (millisecs) = %s eps = %s' % \
(calendar,maxerr,eps))
- eps = 1.e-3
+ eps = 1.e-5
units = 'seconds since 0001-01-30 01:01:01'
secs1 = date2num(dateref,units,calendar=calendar)
maxerr = 0.
@@ -428,7 +425,7 @@ class cftimeTestCase(unittest.TestCase):
if verbose:
print('calendar = %s max abs err (secs) = %s eps = %s' % \
(calendar,maxerr,eps))
- eps = 1.e-5
+ eps = 1.e-6
units = 'minutes since 0001-01-30 01:01:01'
mins1 = date2num(dateref,units,calendar=calendar)
maxerr = 0.
@@ -445,7 +442,7 @@ class cftimeTestCase(unittest.TestCase):
if verbose:
print('calendar = %s max abs err (mins) = %s eps = %s' % \
(calendar,maxerr,eps))
- eps = 1.e-6
+ eps = 1.e-8
units = 'hours since 0001-01-30 01:01:01'
hrs1 = date2num(dateref,units,calendar=calendar)
maxerr = 0.
@@ -462,7 +459,7 @@ class cftimeTestCase(unittest.TestCase):
if verbose:
print('calendar = %s max abs err (hours) = %s eps = %s' % \
(calendar,maxerr,eps))
- eps = 1.e-8
+ eps = 1.e-9
units = 'days since 0001-01-30 01:01:01'
days1 = date2num(dateref,units,calendar=calendar)
maxerr = 0.
@@ -697,6 +694,20 @@ class cftimeTestCase(unittest.TestCase):
d2 = real_datetime(1582,10,4,12)
assert (d1.dayofwk == d2.dayofwk == 0)
assert (d1.dayofyr == d2.dayofyr == 277)
+
+ # issue 173: Return the default values of dayofwk and dayofyr
+ # when calendar is ''
+ d1 = datetimex(1582, 10, 4, 12, calendar='')
+ assert (d1.dayofwk == d1.dayofyr == -1)
+ d1 = datetimex(2020, 5, 20, calendar='')
+ assert (d1.dayofwk == d1.dayofyr == -1)
+ d1 = datetimex(2020, 5, 20, dayofwk=-2, dayofyr=-3, calendar='')
+ assert (d1.dayofwk == -2)
+ assert (d1.dayofyr == -3)
+ d1 = datetimex(2020, 5, 20, dayofwk=8, dayofyr=9, calendar='')
+ assert (d1.dayofwk == 8)
+ assert (d1.dayofyr == 9)
+
# issue 71: negative reference years
# https://coastwatch.pfeg.noaa.gov/erddap/convert/time.html
# gives 2446433 (365 days more - is it counting year 0?)
@@ -758,6 +769,42 @@ class cftimeTestCase(unittest.TestCase):
# to fail.
c = cftime.datetime(*cftime._parse_date('7480-01-01 00:00:00'))
assert(c.strftime() == '7480-01-01 00:00:00')
+ # issue #175: masked values not treated properly in num2date
+ times = np.ma.masked_array([-3956.7499999995343,-999999999999],mask=[False,True])
+ units='days since 1858-11-17 00:00:00'
+ dates = num2date(times, units=units, calendar='standard',\
+ only_use_cftime_datetimes=False, only_use_python_datetimes=True)
+ test = dates == np.ma.masked_array([datetime(1848, 1, 17, 6, 0, 0, 40), None],mask=[0,1])
+ assert(test.all())
+ dates = num2date(times, units=units, calendar='standard')
+ assert(str(dates)=='[cftime.DatetimeGregorian(1848, 1, 17, 6, 0, 0, 40) --]')
+# check that time range of 200,000 + years can be represented accurately
+ calendar='standard'
+ _MAX_INT64 = np.iinfo("int64").max
+ refdate = DatetimeGregorian(292277,10,24,0,0,1)
+ for unit in ['microseconds','milliseconds','seconds']:
+ units = '%s since 01-01-01' % unit
+ time = 292471*365*86400*(1000000//int(UNIT_CONVERSION_FACTORS[unit])) + 1000000//int(UNIT_CONVERSION_FACTORS[unit])
+ date = num2date(time,units,calendar=calendar)
+ assert(date == refdate)
+ # check round-trip
+ time2 = date2num(date,units,calendar=calendar)
+ date2 = num2date(time2,units,calendar=calendar)
+ # windows doesn't have a longdouble type (it defaults to float64)
+ if np.finfo(np.longdouble).precision == 18:
+ assert(date2 == refdate)
+# microsecond roundtrip accuracy preserved over time ranges of 286 years
+# (float64 can only represent integers exactly up to 2**53-1)
+ refdate=DatetimeGregorian(286,6,3,23,47,34,740992)
+ for unit in ['microseconds','milliseconds','seconds','hours','days']:
+ units = '%s since 01-01-01' % unit
+ time = (2**53 - 1)*(1/UNIT_CONVERSION_FACTORS[unit]) + 1/UNIT_CONVERSION_FACTORS[unit]
+ date = num2date(time,units,calendar=calendar)
+ assert(date == refdate)
+ # check round-trip
+ time2 = date2num(date,units,calendar=calendar)
+ date2 = num2date(time2,units,calendar=calendar)
+ assert(date2 == refdate)
class TestDate2index(unittest.TestCase):
@@ -1139,6 +1186,10 @@ class DateTime(unittest.TestCase):
self.assertEqual(self.date1_365_day.replace(minute=3).minute, 3)
self.assertEqual(self.date1_365_day.replace(second=3).second, 3)
self.assertEqual(self.date1_365_day.replace(microsecond=3).microsecond, 3)
+ d = datetimex(2000, 2, 3, calendar='noleap')
+ self.assertEqual(d.replace(year=1999).calendar, 'noleap')
+ d = datetimex(2000, 2, 3, calendar='')
+ self.assertEqual(d.replace(year=1999).calendar, '')
def test_pickling(self):
"Test reversibility of pickling."
@@ -1315,13 +1366,13 @@ class issue57TestCase(unittest.TestCase):
for datestr in ("days since2017-05-01 ", "dayssince 2017-05-01 00:00", "days snce 2017-05-01 00:00", "days_since_2017-05-01 00:00",
"days_since_2017-05-01_00:00"):
self.assertRaises(
- ValueError, cftime._cftime._dateparse, datestr)
+ ValueError, cftime._cftime._dateparse, datestr, 'standard')
self.assertRaises(
- ValueError, cftime._cftime.num2date, 1, datestr)
+ ValueError, cftime._cftime.num2date, 1, datestr, 'standard')
self.assertRaises(
- ValueError, cftime._cftime.date2num, datetime(1900, 1, 1, 0), datestr)
+ ValueError, cftime._cftime.date2num, datetime(1900, 1, 1, 0), datestr, 'standard')
_DATE_TYPES = [DatetimeNoLeap, DatetimeAllLeap, DatetimeJulian, Datetime360Day,
@@ -1514,7 +1565,8 @@ def test_num2date_only_use_cftime_datetimes_post_gregorian(
def test_repr():
- expected = 'cftime.datetime(2000-01-01 00:00:00)'
+ #expected = 'cftime.datetime(2000-01-01 00:00:00)'
+ expected = 'cftime.datetime(2000, 1, 1, 0, 0, 0, 0)'
assert repr(datetimex(2000, 1, 1)) == expected
@@ -1555,5 +1607,272 @@ def test_dayofyr_after_timedelta_addition(date_type):
assert date_after_timedelta_addition.dayofyr == 3
+def test_exact_datetime_difference(date_type):
+ b = date_type(2000, 1, 2, 0, 0, 0, 5)
+ a = date_type(2000, 1, 2)
+ result = b - a
+ expected = timedelta(microseconds=5)
+ assert result == expected
+
+
+_SHAPES = [(4, ), (2, 2)]
+_MICROSECOND_UNITS = ["microseconds", "microsecond", "microsec", "microsecs"]
+_MILLISECOND_UNITS = ["milliseconds", "millisecond", "millisec", "millisecs", "ms"]
+_SECOND_UNITS = ["seconds", "second", "sec", "secs", "s"]
+_MINUTE_UNITS = ["minutes", "minute", "min", "mins"]
+_HOUR_UNITS = ["hours", "hour", "hr", "hrs", "h"]
+_DAY_UNITS = ["day", "days", "d"]
+_MONTH_UNITS = ["month", "months"]
+_DTYPES = [np.dtype("int64"), np.dtype("float64")]
+_STANDARD_CALENDARS = [
+ "standard",
+ "gregorian",
+ "proleptic_gregorian"
+]
+_REAL_WORLD_CALENDARS = [
+ "julian",
+ "standard",
+ "gregorian",
+ "proleptic_gregorian"
+]
+_ARTIFICIAL_CALENDARS = ["noleap", "all_leap", "360_day"]
+
+
+ at pytest.fixture(params=_SHAPES)
+def shape(request):
+ return request.param
+
+
+ at pytest.fixture(params=_DTYPES)
+def dtype(request):
+ return request.param
+
+
+ at pytest.fixture(params=list(_EXPECTED_DATE_TYPES.keys()))
+def calendar(request):
+ return request.param
+
+
+ at pytest.mark.parametrize("unit", _MICROSECOND_UNITS)
+def test_num2date_microsecond_units(calendar, unit, shape, dtype):
+ date_type = _EXPECTED_DATE_TYPES[calendar]
+ expected = np.array([date_type(2000, 1, 1, 0, 0, 0, 1),
+ date_type(2000, 1, 1, 0, 0, 0, 2),
+ date_type(2000, 1, 1, 0, 0, 0, 3),
+ date_type(2000, 1, 1, 0, 0, 0, 4)]).reshape(shape)
+ numeric_times = np.array([1, 2, 3, 4]).reshape(shape).astype(dtype)
+ units = "{} since 2000-01-01".format(unit)
+ result = num2date(numeric_times, units=units, calendar=calendar)
+ np.testing.assert_equal(result, expected)
+
+
+ at pytest.mark.parametrize("unit", _MILLISECOND_UNITS)
+def test_num2date_millisecond_units(calendar, unit, shape, dtype):
+ date_type = _EXPECTED_DATE_TYPES[calendar]
+ expected = np.array([date_type(2000, 1, 1, 0, 0, 0, 1000),
+ date_type(2000, 1, 1, 0, 0, 0, 2000),
+ date_type(2000, 1, 1, 0, 0, 0, 3000),
+ date_type(2000, 1, 1, 0, 0, 0, 4000)]).reshape(shape)
+ numeric_times = np.array([1, 2, 3, 4]).reshape(shape).astype(dtype)
+ units = "{} since 2000-01-01".format(unit)
+ result = num2date(numeric_times, units=units, calendar=calendar)
+ np.testing.assert_equal(result, expected)
+
+
+ at pytest.mark.parametrize("unit", _SECOND_UNITS)
+def test_num2date_second_units(calendar, unit, shape, dtype):
+ date_type = _EXPECTED_DATE_TYPES[calendar]
+ expected = np.array([date_type(2000, 1, 1, 0, 0, 1, 0),
+ date_type(2000, 1, 1, 0, 0, 2, 0),
+ date_type(2000, 1, 1, 0, 0, 3, 0),
+ date_type(2000, 1, 1, 0, 0, 4, 0)]).reshape(shape)
+ numeric_times = np.array([1, 2, 3, 4]).reshape(shape).astype(dtype)
+ units = "{} since 2000-01-01".format(unit)
+ result = num2date(numeric_times, units=units, calendar=calendar)
+ np.testing.assert_equal(result, expected)
+
+
+ at pytest.mark.parametrize("unit", _MINUTE_UNITS)
+def test_num2date_minute_units(calendar, unit, shape, dtype):
+ date_type = _EXPECTED_DATE_TYPES[calendar]
+ expected = np.array([date_type(2000, 1, 1, 0, 1, 0, 0),
+ date_type(2000, 1, 1, 0, 2, 0, 0),
+ date_type(2000, 1, 1, 0, 3, 0, 0),
+ date_type(2000, 1, 1, 0, 4, 0, 0)]).reshape(shape)
+ numeric_times = np.array([1, 2, 3, 4]).reshape(shape).astype(dtype)
+ units = "{} since 2000-01-01".format(unit)
+ result = num2date(numeric_times, units=units, calendar=calendar)
+ np.testing.assert_equal(result, expected)
+
+
+ at pytest.mark.parametrize("unit", _HOUR_UNITS)
+def test_num2date_hour_units(calendar, unit, shape, dtype):
+ date_type = _EXPECTED_DATE_TYPES[calendar]
+ expected = np.array([date_type(2000, 1, 1, 1, 0, 0, 0),
+ date_type(2000, 1, 1, 2, 0, 0, 0),
+ date_type(2000, 1, 1, 3, 0, 0, 0),
+ date_type(2000, 1, 1, 4, 0, 0, 0)]).reshape(shape)
+ numeric_times = np.array([1, 2, 3, 4]).reshape(shape).astype(dtype)
+ units = "{} since 2000-01-01".format(unit)
+ result = num2date(numeric_times, units=units, calendar=calendar)
+ np.testing.assert_equal(result, expected)
+
+
+ at pytest.mark.parametrize("unit", _DAY_UNITS)
+def test_num2date_day_units(calendar, unit, shape, dtype):
+ date_type = _EXPECTED_DATE_TYPES[calendar]
+ expected = np.array([date_type(2000, 1, 2, 0, 0, 0, 0),
+ date_type(2000, 1, 3, 0, 0, 0, 0),
+ date_type(2000, 1, 4, 0, 0, 0, 0),
+ date_type(2000, 1, 5, 0, 0, 0, 0)]).reshape(shape)
+ numeric_times = np.array([1, 2, 3, 4]).reshape(shape).astype(dtype)
+ units = "{} since 2000-01-01".format(unit)
+ result = num2date(numeric_times, units=units, calendar=calendar)
+ np.testing.assert_equal(result, expected)
+
+
+ at pytest.mark.parametrize("unit", _MONTH_UNITS)
+def test_num2date_month_units(calendar, unit, shape, dtype):
+ date_type = _EXPECTED_DATE_TYPES[calendar]
+ expected = np.array([date_type(2000, 2, 1, 0, 0, 0, 0),
+ date_type(2000, 3, 1, 0, 0, 0, 0),
+ date_type(2000, 4, 1, 0, 0, 0, 0),
+ date_type(2000, 5, 1, 0, 0, 0, 0)]).reshape(shape)
+ numeric_times = np.array([1, 2, 3, 4]).reshape(shape).astype(dtype)
+ units = "{} since 2000-01-01".format(unit)
+
+ if calendar != "360_day":
+ with pytest.raises(ValueError):
+ num2date(numeric_times, units=units, calendar=calendar)
+ else:
+ result = num2date(numeric_times, units=units, calendar=calendar)
+ np.testing.assert_equal(result, expected)
+
+
+def test_num2date_only_use_python_datetimes(calendar, shape, dtype):
+ date_type = real_datetime
+ expected = np.array([date_type(2000, 1, 2, 0, 0, 0, 0),
+ date_type(2000, 1, 3, 0, 0, 0, 0),
+ date_type(2000, 1, 4, 0, 0, 0, 0),
+ date_type(2000, 1, 5, 0, 0, 0, 0)]).reshape(shape)
+ numeric_times = np.array([1, 2, 3, 4]).reshape(shape).astype(dtype)
+ units = "days since 2000-01-01"
+ if calendar not in _STANDARD_CALENDARS:
+ with pytest.raises(ValueError):
+ num2date(numeric_times, units=units, calendar=calendar,
+ only_use_python_datetimes=True,
+ only_use_cftime_datetimes=False)
+ else:
+ result = num2date(numeric_times, units=units, calendar=calendar,
+ only_use_python_datetimes=True,
+ only_use_cftime_datetimes=False)
+ np.testing.assert_equal(result, expected)
+
+
+def test_num2date_use_pydatetime_if_possible(calendar, shape, dtype):
+ if calendar not in _STANDARD_CALENDARS:
+ date_type = _EXPECTED_DATE_TYPES[calendar]
+ else:
+ date_type = real_datetime
+
+ expected = np.array([date_type(2000, 1, 2, 0, 0, 0, 0),
+ date_type(2000, 1, 3, 0, 0, 0, 0),
+ date_type(2000, 1, 4, 0, 0, 0, 0),
+ date_type(2000, 1, 5, 0, 0, 0, 0)]).reshape(shape)
+ numeric_times = np.array([1, 2, 3, 4]).reshape(shape).astype(dtype)
+ units = "days since 2000-01-01"
+ result = num2date(numeric_times, units=units, calendar=calendar,
+ only_use_python_datetimes=False,
+ only_use_cftime_datetimes=False)
+ np.testing.assert_equal(result, expected)
+
+
+ at pytest.mark.parametrize(
+ ["standard_calendar", "breakpoint"],
+ [("proleptic_gregorian", "{}-12-31T23:59:59.999999".format(MINYEAR - 1)),
+ ("gregorian", "1582-10-15"),
+ ("standard", "1582-10-15")]
+)
+def test_num2date_only_use_python_datetimes_invalid_basedate(
+ standard_calendar,
+ breakpoint
+):
+ units = "days since {}".format(breakpoint)
+ numeric_times = np.array([1, 2, 3, 4])
+ with pytest.raises(ValueError):
+ num2date(
+ numeric_times,
+ units=units,
+ calendar=standard_calendar,
+ only_use_python_datetimes=True,
+ only_use_cftime_datetimes=False
+ )
+
+
+ at pytest.mark.parametrize("real_world_calendar", _REAL_WORLD_CALENDARS)
+def test_num2date_invalid_zero_reference_year(real_world_calendar):
+ units = "days since 0000-01-01"
+ numeric_times = np.array([1, 2, 3, 4])
+ with pytest.raises(ValueError, match="zero not allowed as a reference"):
+ num2date(
+ numeric_times,
+ units=units,
+ calendar=real_world_calendar
+ )
+
+
+ at pytest.mark.parametrize("artificial_calendar", _ARTIFICIAL_CALENDARS)
+def test_num2date_valid_zero_reference_year(artificial_calendar):
+ units = "days since 0000-01-01"
+ numeric_times = np.array([1, 2, 3, 4])
+ num2date(numeric_times, units=units, calendar=artificial_calendar)
+
+
+def test_num2date_masked_array(calendar):
+ date_type = _EXPECTED_DATE_TYPES[calendar]
+ expected = np.array([date_type(2000, 1, 1, 1, 0, 0, 0),
+ date_type(2000, 1, 1, 2, 0, 0, 0),
+ date_type(2000, 1, 1, 3, 0, 0, 0),
+ date_type(2000, 1, 1, 4, 0, 0, 0)])
+ mask = [False, False, True, False]
+ expected = np.ma.masked_array(expected, mask=mask)
+ numeric_times = np.ma.masked_array([1, 2, 3, 4], mask=mask)
+ units = "hours since 2000-01-01"
+ result = num2date(numeric_times, units=units, calendar=calendar)
+ np.testing.assert_equal(result, expected)
+
+
+def test_num2date_out_of_range():
+ numeric_times = 12 * np.array([200000, 400000, 600000])
+ units = "months since 2000-01-01"
+ with pytest.raises(OverflowError, match="time values outside range of 64 bit signed integers"):
+ num2date(numeric_times, units=units, calendar="360_day")
+
+
+def test_num2date_list_input(calendar):
+ date_type = _EXPECTED_DATE_TYPES[calendar]
+ expected = np.array([date_type(2000, 1, 1, 1, 0, 0, 0),
+ date_type(2000, 1, 1, 2, 0, 0, 0),
+ date_type(2000, 1, 1, 3, 0, 0, 0),
+ date_type(2000, 1, 1, 4, 0, 0, 0)])
+ numeric_times = [1, 2, 3, 4]
+ units = "hours since 2000-01-01"
+ result = num2date(numeric_times, units=units, calendar=calendar)
+ np.testing.assert_equal(result, expected)
+
+
+def test_num2date_integer_upcast_required():
+ numeric_times = np.array([30, 60, 90, 120], dtype=np.int32)
+ units = "minutes since 2000-01-01"
+ expected = np.array([
+ Datetime360Day(2000, 1, 1, 0, 30, 0),
+ Datetime360Day(2000, 1, 1, 1, 0, 0),
+ Datetime360Day(2000, 1, 1, 1, 30, 0),
+ Datetime360Day(2000, 1, 1, 2, 0, 0)
+ ])
+ result = num2date(numeric_times, units=units, calendar="360_day")
+ np.testing.assert_equal(result, expected)
+
+
if __name__ == '__main__':
unittest.main()
View it on GitLab: https://salsa.debian.org/debian-gis-team/cftime/-/commit/2153605fbdd4574b6fd22eab81c430dac0db4424
--
View it on GitLab: https://salsa.debian.org/debian-gis-team/cftime/-/commit/2153605fbdd4574b6fd22eab81c430dac0db4424
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/20200706/28bd4c55/attachment-0001.html>
More information about the Pkg-grass-devel
mailing list