From 156eda683dea3fe7012af7b4dfcf5877fe556f46 Mon Sep 17 00:00:00 2001 From: Spencer Clark Date: Sun, 21 Jun 2020 11:42:43 -0400 Subject: [PATCH 1/3] Make cftime.datetime - cftime.datetime -> timedelta microsecond-exact --- cftime/_cftime.pyx | 11 +++++++++-- test/test_cftime.py | 8 ++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/cftime/_cftime.pyx b/cftime/_cftime.pyx index 1e97636f..57789325 100644 --- a/cftime/_cftime.pyx +++ b/cftime/_cftime.pyx @@ -1280,6 +1280,7 @@ _converters = {} for calendar in _calendars: _converters[calendar] = utime("seconds since 1-1-1", calendar) + @cython.embedsignature(True) cdef class datetime(object): """ @@ -1517,8 +1518,14 @@ Gregorial calendar. raise ValueError("cannot compute the time difference between dates with different calendars") if dt.calendar == "": raise ValueError("cannot compute the time difference between dates that are not calendar-aware") - converter = _converters[dt.calendar] - return timedelta(seconds=converter.date2num(dt) - converter.date2num(other)) + ordinal_self = _IntJulianDayFromDate(dt.year, dt.month, dt.day, dt.calendar) + ordinal_other = _IntJulianDayFromDate(other.year, other.month, other.day, other.calendar) + days = ordinal_self - ordinal_other + seconds_self = dt.second + 60 * dt.minute + 3600 * dt.hour + seconds_other = other.second + 60 * other.minute + 3600 * other.hour + seconds = seconds_self - seconds_other + microseconds = dt.microsecond - other.microsecond + return timedelta(days, seconds, microseconds) elif isinstance(other, datetime_python): # datetime - real_datetime if not dt.datetime_compatible: diff --git a/test/test_cftime.py b/test/test_cftime.py index d2452a64..3ef973b9 100644 --- a/test/test_cftime.py +++ b/test/test_cftime.py @@ -1583,5 +1583,13 @@ 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 + + if __name__ == '__main__': unittest.main() From d9c9b3e3e90cc08a5b26ff0f95cb17d9e5213703 Mon Sep 17 00:00:00 2001 From: Spencer Clark Date: Sun, 21 Jun 2020 11:45:51 -0400 Subject: [PATCH 2/3] Remove formatting change --- cftime/_cftime.pyx | 1 - 1 file changed, 1 deletion(-) diff --git a/cftime/_cftime.pyx b/cftime/_cftime.pyx index 57789325..c164043e 100644 --- a/cftime/_cftime.pyx +++ b/cftime/_cftime.pyx @@ -1280,7 +1280,6 @@ _converters = {} for calendar in _calendars: _converters[calendar] = utime("seconds since 1-1-1", calendar) - @cython.embedsignature(True) cdef class datetime(object): """ From b795635ca4096fcb66b0838bdda4c797dee2a45e Mon Sep 17 00:00:00 2001 From: Spencer Clark Date: Mon, 22 Jun 2020 20:57:30 -0400 Subject: [PATCH 3/3] Revert irrelevant formatting changes --- test/test_cftime.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/test_cftime.py b/test/test_cftime.py index a64349ec..502787e6 100644 --- a/test/test_cftime.py +++ b/test/test_cftime.py @@ -1736,12 +1736,12 @@ def test_num2date_int_only_use_python_datetimes(calendar, shape, dtype): if calendar not in _STANDARD_CALENDARS: with pytest.raises(ValueError): num2date_int(numeric_times, units=units, calendar=calendar, - only_use_python_datetimes=True, - only_use_cftime_datetimes=False) + only_use_python_datetimes=True, + only_use_cftime_datetimes=False) else: result = num2date_int(numeric_times, units=units, calendar=calendar, - only_use_python_datetimes=True, - only_use_cftime_datetimes=False) + only_use_python_datetimes=True, + only_use_cftime_datetimes=False) np.testing.assert_equal(result, expected) @@ -1758,8 +1758,8 @@ def test_num2date_int_use_pydatetime_if_possible(calendar, shape, dtype): numeric_times = np.array([1, 2, 3, 4]).reshape(shape).astype(dtype) units = "days since 2000-01-01" result = num2date_int(numeric_times, units=units, calendar=calendar, - only_use_python_datetimes=False, - only_use_cftime_datetimes=False) + only_use_python_datetimes=False, + only_use_cftime_datetimes=False) np.testing.assert_equal(result, expected)