From 4757d983b8f9739d4eef84e2d6ef6b4bddbd6121 Mon Sep 17 00:00:00 2001 From: Jody Klymak Date: Wed, 22 Jul 2020 10:56:46 -0700 Subject: [PATCH] FIX: update num2julian and julian2num Apply suggestions from code review Co-authored-by: Elliott Sales de Andrade --- .../deprecations/17983-JMK.rst | 14 ++++++-- lib/matplotlib/dates.py | 33 ++++++++++++++----- lib/matplotlib/tests/test_dates.py | 14 ++++++++ 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/doc/api/next_api_changes/deprecations/17983-JMK.rst b/doc/api/next_api_changes/deprecations/17983-JMK.rst index 4559b9919e6a..9d6500125bd9 100644 --- a/doc/api/next_api_changes/deprecations/17983-JMK.rst +++ b/doc/api/next_api_changes/deprecations/17983-JMK.rst @@ -1,8 +1,16 @@ -Reverted deprecation of `~.dates.num2epoch` and `~.dates.epoch2num` +Reverted deprecation of ``num2epoch`` and ``epoch2num`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ These two functions were deprecated in 3.3.0, and did not return an accurate Matplotlib datenum relative to the new Matplotlib epoch handling (`~.dates.get_epoch` and :rc:`date.epoch`). This version -reverts the deprecation and fixes those functions to work with -`~.dates.get_epoch`. +reverts the deprecation. + +Functions ``epoch2num`` and ``dates.julian2num`` use ``date.epoch`` rcParam +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now `~.dates.epoch2num` and (undocumented) ``julian2num`` return floating point +days since `~.dates.get_epoch` as set by :rc:`date.epoch`, instead of +floating point days since the old epoch of "0000-12-31T00:00:00". If +needed, you can translate from the new to old values as +``old = new + mdates.date2num(np.datetime64('0000-12-31'))`` diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py index 2dd2a0e9fb79..19a7f9087cf4 100644 --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -197,7 +197,13 @@ def _get_rc_timezone(): Time-related constants. """ EPOCH_OFFSET = float(datetime.datetime(1970, 1, 1).toordinal()) -JULIAN_OFFSET = 1721424.5 # Julian date at 0001-01-01 +# EPOCH_OFFSET is not used by matplotlib +JULIAN_OFFSET = 1721424.5 # Julian date at 0000-12-31 +# note that the Julian day epoch is achievable w/ +# np.datetime64('-4713-11-24T12:00:00'); datetime64 is proleptic +# Gregorian and BC has a one-year offset. So +# np.datetime64('0000-12-31') - np.datetime64('-4713-11-24T12:00') = 1721424.5 +# Ref: https://en.wikipedia.org/wiki/Julian_day MICROSECONDLY = SECONDLY + 1 HOURS_PER_DAY = 24. MIN_PER_HOUR = 60. @@ -445,14 +451,20 @@ def julian2num(j): Parameters ---------- j : float or sequence of floats - Julian date(s) + Julian dates (days relative to 4713 BC Jan 1, 12:00:00 Julian + calendar or 4714 BC Nov 24, 12:00:00, proleptic Gregorian calendar). Returns ------- float or sequence of floats - Matplotlib date(s) + Matplotlib dates (days relative to `.get_epoch`). """ - return np.subtract(j, JULIAN_OFFSET) # Handles both scalar & nonscalar j. + ep = np.datetime64(get_epoch(), 'h').astype(float) / 24. + ep0 = np.datetime64('0000-12-31T00:00:00', 'h').astype(float) / 24. + # Julian offset defined above is relative to 0000-12-31, but we need + # relative to our current epoch: + dt = JULIAN_OFFSET - ep0 + ep + return np.subtract(j, dt) # Handles both scalar & nonscalar j. def num2julian(n): @@ -462,14 +474,19 @@ def num2julian(n): Parameters ---------- n : float or sequence of floats - Matplotlib date(s) + Matplotlib dates (days relative to `.get_epoch`). Returns ------- float or sequence of floats - Julian date(s) - """ - return np.add(n, JULIAN_OFFSET) # Handles both scalar & nonscalar j. + Julian dates (days relative to 4713 BC Jan 1, 12:00:00). + """ + ep = np.datetime64(get_epoch(), 'h').astype(float) / 24. + ep0 = np.datetime64('0000-12-31T00:00:00', 'h').astype(float) / 24. + # Julian offset defined above is relative to 0000-12-31, but we need + # relative to our current epoch: + dt = JULIAN_OFFSET - ep0 + ep + return np.add(n, dt) # Handles both scalar & nonscalar j. def num2date(x, tz=None): diff --git a/lib/matplotlib/tests/test_dates.py b/lib/matplotlib/tests/test_dates.py index a446d3fd3c5c..59ad50fdb086 100644 --- a/lib/matplotlib/tests/test_dates.py +++ b/lib/matplotlib/tests/test_dates.py @@ -1010,3 +1010,17 @@ def test_epoch2num(): mdates.set_epoch('1970-01-01T00:00:00') assert mdates.epoch2num(86400) == 1.0 assert mdates.num2epoch(2.0) == 86400 * 2 + + +def test_julian2num(): + mdates._reset_epoch_test_example() + mdates.set_epoch('0000-12-31') + # 2440587.5 is julian date for 1970-01-01T00:00:00 + # https://en.wikipedia.org/wiki/Julian_day + assert mdates.julian2num(2440588.5) == 719164.0 + assert mdates.num2julian(719165.0) == 2440589.5 + # set back to the default + mdates._reset_epoch_test_example() + mdates.set_epoch('1970-01-01T00:00:00') + assert mdates.julian2num(2440588.5) == 1.0 + assert mdates.num2julian(2.0) == 2440589.5