Skip to content

Commit e277333

Browse files
committed
FIX: translate timedeltas in _to_ordinalf
FIX: translate timedelta64 in _dt64_to_ordinalf
1 parent 63fe909 commit e277333

File tree

2 files changed

+72
-10
lines changed

2 files changed

+72
-10
lines changed

lib/matplotlib/dates.py

+39-10
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,10 @@ def _to_ordinalf(dt):
222222
dt = dt.astimezone(UTC)
223223
tzi = UTC
224224

225+
if isinstance(dt, datetime.timedelta):
226+
base = dt / datetime.timedelta(days=1)
227+
return base
228+
225229
base = float(dt.toordinal())
226230

227231
# If it's sufficiently datetime-like, it will have a `date()` method
@@ -251,6 +255,11 @@ def _dt64_to_ordinalf(d):
251255
because we do times compared to ``0001-01-01T00:00:00`` (plus one day).
252256
"""
253257

258+
if (isinstance(d, np.timedelta64) or
259+
(isinstance(d, np.ndarray) and
260+
np.issubdtype(d.dtype, np.timedelta64))):
261+
return d / np.timedelta64(1, 'D')
262+
254263
# the "extra" ensures that we at least allow the dynamic range out to
255264
# seconds. That should get out to +/-2e11 years.
256265
# NOTE: First cast truncates; second cast back is for NumPy 1.10.
@@ -271,6 +280,12 @@ def _dt64_to_ordinalf(d):
271280
return dt
272281

273282

283+
def _dt64_to_ordinalf_iterable(d):
284+
dnew = np.zeros(len(d))
285+
for nn, dd in enumerate(d):
286+
dnew[nn] = _dt64_to_ordinalf(dd)
287+
return dnew
288+
274289
def _from_ordinalf(x, tz=None):
275290
"""
276291
Convert Gregorian float of the date, preserving hours, minutes,
@@ -405,22 +420,36 @@ def date2num(d):
405420
Gregorian calendar is assumed; this is not universal practice.
406421
For details see the module docstring.
407422
"""
423+
408424
if hasattr(d, "values"):
409425
# this unpacks pandas series or dataframes...
410426
d = d.values
411-
if not np.iterable(d):
412-
if (isinstance(d, np.datetime64) or (isinstance(d, np.ndarray) and
413-
np.issubdtype(d.dtype, np.datetime64))):
414-
return _dt64_to_ordinalf(d)
415-
return _to_ordinalf(d)
416427

417-
else:
418-
d = np.asarray(d)
419-
if np.issubdtype(d.dtype, np.datetime64):
428+
if not np.iterable(d) and not isinstance(d, np.ndarray):
429+
# single value logic...
430+
if (isinstance(d, np.datetime64) or isinstance(d, np.timedelta64)):
420431
return _dt64_to_ordinalf(d)
421-
if not d.size:
422-
return d
432+
else:
433+
return _to_ordinalf(d)
434+
435+
elif (isinstance(d, np.ndarray) and
436+
(np.issubdtype(d.dtype, np.datetime64) or
437+
np.issubdtype(d.dtype, np.timedelta64))):
438+
# array with all one type of datetime64 object.
439+
return _dt64_to_ordinalf(d)
440+
441+
elif len(d):
442+
# this is a list or tuple...
443+
if (isinstance(d[0], np.datetime64) or
444+
isinstance(d[0], np.timedelta64)):
445+
return _dt64_to_ordinalf_iterable(d)
423446
return _to_ordinalf_np_vectorized(d)
447+
elif hasattr(d, 'size') and not d.size:
448+
# this elif doesn't get tested, but leaving here in case anyone
449+
# needs it.
450+
return d
451+
else:
452+
return []
424453

425454

426455
def julian2num(j):

lib/matplotlib/tests/test_dates.py

+33
Original file line numberDiff line numberDiff line change
@@ -680,3 +680,36 @@ def test_datetime64_in_list():
680680
dt = [np.datetime64('2000-01-01'), np.datetime64('2001-01-01')]
681681
dn = mdates.date2num(dt)
682682
assert np.array_equal(dn, [730120., 730486.])
683+
684+
685+
def test_timedelta():
686+
"""
687+
Test that timedelta objects are properly translated into days.
688+
"""
689+
dt = [datetime.datetime(2000, 1, 1, 0, 0, 0),
690+
datetime.timedelta(days=1, hours=2)]
691+
assert mdates.date2num(dt[1]) == 1 + 2 / 24
692+
# check that mixed lists work....
693+
assert mdates.date2num(dt)[0] == 730120.0
694+
assert mdates.date2num(dt)[1] == 1 + 2 / 24
695+
696+
dt = (np.datetime64('2000-01-01'),
697+
np.timedelta64(26, 'h'))
698+
assert mdates.date2num(dt[1]) == 1 + 2 / 24
699+
# check that mixed lists work....
700+
assert mdates.date2num(dt)[0] == 730120.0
701+
assert mdates.date2num(dt)[1] == 1 + 2 / 24
702+
703+
dt = [datetime.timedelta(days=1, hours=1),
704+
datetime.timedelta(days=1, hours=2)]
705+
assert mdates.date2num(dt)[0] == 1 + 1 / 24
706+
assert mdates.date2num(dt)[1] == 1 + 2 / 24
707+
708+
dt = (np.timedelta64(25, 'h'),
709+
np.timedelta64(26, 'h'))
710+
assert mdates.date2num(dt)[0] == 1 + 1 / 24
711+
assert mdates.date2num(dt)[1] == 1 + 2 / 24
712+
713+
dt = np.array([25, 26], dtype='timedelta64[h]')
714+
assert mdates.date2num(dt)[0] == 1 + 1 / 24
715+
assert mdates.date2num(dt)[1] == 1 + 2 / 24

0 commit comments

Comments
 (0)