Skip to content

Commit a79a42d

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

File tree

2 files changed

+71
-10
lines changed

2 files changed

+71
-10
lines changed

lib/matplotlib/dates.py

+38-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,11 @@ def _dt64_to_ordinalf(d):
271280
return dt
272281

273282

283+
def _dt64_to_ordinalf_iterable(d):
284+
return np.fromiter((_dt64_to_ordinalf(dd) for dd in d),
285+
float, count=len(d))
286+
287+
274288
def _from_ordinalf(x, tz=None):
275289
"""
276290
Convert Gregorian float of the date, preserving hours, minutes,
@@ -405,22 +419,36 @@ def date2num(d):
405419
Gregorian calendar is assumed; this is not universal practice.
406420
For details see the module docstring.
407421
"""
422+
408423
if hasattr(d, "values"):
409424
# this unpacks pandas series or dataframes...
410425
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)
416426

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

425453

426454
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)