.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "gallery/ticks_and_spines/date_precision_and_epochs.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note Click :ref:`here ` to download the full example code .. rst-class:: sphx-glr-example-title .. _sphx_glr_gallery_ticks_and_spines_date_precision_and_epochs.py: ========================= Date Precision and Epochs ========================= Matplotlib can handle `.datetime` objects and `numpy.datetime64` objects using a unit converter that recognizes these dates and converts them to floating point numbers. Before Matplotlib 3.3, the default for this conversion returns a float that was days since "0000-12-31T00:00:00". As of Matplotlib 3.3, the default is days from "1970-01-01T00:00:00". This allows more resolution for modern dates. "2020-01-01" with the old epoch converted to 730120, and a 64-bit floating point number has a resolution of 2^{-52}, or approximately 14 microseconds, so microsecond precision was lost. With the new default epoch "2020-01-01" is 10957.0, so the achievable resolution is 0.21 microseconds. .. GENERATED FROM PYTHON SOURCE LINES 20-36 .. code-block:: default import datetime import numpy as np import matplotlib import matplotlib.pyplot as plt import matplotlib.dates as mdates def _reset_epoch_for_tutorial(): """ Users (and downstream libraries) should not use the private method of resetting the epoch. """ mdates._reset_epoch_test_example() .. GENERATED FROM PYTHON SOURCE LINES 37-43 Datetime -------- Python `.datetime` objects have microsecond resolution, so with the old default matplotlib dates could not round-trip full-resolution datetime objects. .. GENERATED FROM PYTHON SOURCE LINES 43-57 .. code-block:: default old_epoch = '0000-12-31T00:00:00' new_epoch = '1970-01-01T00:00:00' _reset_epoch_for_tutorial() # Don't do this. Just for this tutorial. mdates.set_epoch(old_epoch) # old epoch (pre MPL 3.3) date1 = datetime.datetime(2000, 1, 1, 0, 10, 0, 12, tzinfo=datetime.timezone.utc) mdate1 = mdates.date2num(date1) print('Before Roundtrip: ', date1, 'Matplotlib date:', mdate1) date2 = mdates.num2date(mdate1) print('After Roundtrip: ', date2) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none Before Roundtrip: 2000-01-01 00:10:00.000012+00:00 Matplotlib date: 730120.0069444446 After Roundtrip: 2000-01-01 00:10:00.000020+00:00 .. GENERATED FROM PYTHON SOURCE LINES 58-60 Note this is only a round-off error, and there is no problem for dates closer to the old epoch: .. GENERATED FROM PYTHON SOURCE LINES 60-68 .. code-block:: default date1 = datetime.datetime(10, 1, 1, 0, 10, 0, 12, tzinfo=datetime.timezone.utc) mdate1 = mdates.date2num(date1) print('Before Roundtrip: ', date1, 'Matplotlib date:', mdate1) date2 = mdates.num2date(mdate1) print('After Roundtrip: ', date2) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none Before Roundtrip: 0010-01-01 00:10:00.000012+00:00 Matplotlib date: 3288.006944444583 After Roundtrip: 0010-01-01 00:10:00.000012+00:00 .. GENERATED FROM PYTHON SOURCE LINES 69-73 If a user wants to use modern dates at microsecond precision, they can change the epoch using `~.set_epoch`. However, the epoch has to be set before any date operations to prevent confusion between different epochs. Trying to change the epoch later will raise a `RuntimeError`. .. GENERATED FROM PYTHON SOURCE LINES 73-79 .. code-block:: default try: mdates.set_epoch(new_epoch) # this is the new MPL 3.3 default. except RuntimeError as e: print('RuntimeError:', str(e)) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none RuntimeError: set_epoch must be called before dates plotted. .. GENERATED FROM PYTHON SOURCE LINES 80-82 For this tutorial, we reset the sentinel using a private method, but users should just set the epoch once, if at all. .. GENERATED FROM PYTHON SOURCE LINES 82-93 .. code-block:: default _reset_epoch_for_tutorial() # Just being done for this tutorial. mdates.set_epoch(new_epoch) date1 = datetime.datetime(2020, 1, 1, 0, 10, 0, 12, tzinfo=datetime.timezone.utc) mdate1 = mdates.date2num(date1) print('Before Roundtrip: ', date1, 'Matplotlib date:', mdate1) date2 = mdates.num2date(mdate1) print('After Roundtrip: ', date2) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none Before Roundtrip: 2020-01-01 00:10:00.000012+00:00 Matplotlib date: 18262.006944444583 After Roundtrip: 2020-01-01 00:10:00.000012+00:00 .. GENERATED FROM PYTHON SOURCE LINES 94-101 datetime64 ---------- `numpy.datetime64` objects have microsecond precision for a much larger timespace than `.datetime` objects. However, currently Matplotlib time is only converted back to datetime objects, which have microsecond resolution, and years that only span 0000 to 9999. .. GENERATED FROM PYTHON SOURCE LINES 101-111 .. code-block:: default _reset_epoch_for_tutorial() # Don't do this. Just for this tutorial. mdates.set_epoch(new_epoch) date1 = np.datetime64('2000-01-01T00:10:00.000012') mdate1 = mdates.date2num(date1) print('Before Roundtrip: ', date1, 'Matplotlib date:', mdate1) date2 = mdates.num2date(mdate1) print('After Roundtrip: ', date2) .. rst-class:: sphx-glr-script-out Out: .. code-block:: none Before Roundtrip: 2000-01-01T00:10:00.000012 Matplotlib date: 10957.006944444583 After Roundtrip: 2000-01-01 00:10:00.000012+00:00 .. GENERATED FROM PYTHON SOURCE LINES 112-117 Plotting -------- This all of course has an effect on plotting. With the old default epoch the times were rounded, leading to jumps in the data: .. GENERATED FROM PYTHON SOURCE LINES 117-130 .. code-block:: default _reset_epoch_for_tutorial() # Don't do this. Just for this tutorial. mdates.set_epoch(old_epoch) x = np.arange('2000-01-01T00:00:00.0', '2000-01-01T00:00:00.000100', dtype='datetime64[us]') y = np.arange(0, len(x)) fig, ax = plt.subplots(constrained_layout=True) ax.plot(x, y) ax.set_title('Epoch: ' + mdates.get_epoch()) plt.setp(ax.xaxis.get_majorticklabels(), rotation=40) plt.show() .. image:: /gallery/ticks_and_spines/images/sphx_glr_date_precision_and_epochs_001.png :alt: Epoch: 0000-12-31T00:00:00 :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out Out: .. code-block:: none /root/matplotlib/examples/ticks_and_spines/date_precision_and_epochs.py:127: UserWarning: Plotting microsecond time intervals for dates far from the epoch (time origin: 0000-12-31T00:00:00) is not well-supported. See matplotlib.dates.set_epoch to change the epoch. plt.setp(ax.xaxis.get_majorticklabels(), rotation=40) .. GENERATED FROM PYTHON SOURCE LINES 131-132 For a more recent epoch, the plot is smooth: .. GENERATED FROM PYTHON SOURCE LINES 132-144 .. code-block:: default _reset_epoch_for_tutorial() # Don't do this. Just for this tutorial. mdates.set_epoch(new_epoch) fig, ax = plt.subplots(constrained_layout=True) ax.plot(x, y) ax.set_title('Epoch: ' + mdates.get_epoch()) plt.setp(ax.xaxis.get_majorticklabels(), rotation=40) plt.show() _reset_epoch_for_tutorial() # Don't do this. Just for this tutorial. .. image:: /gallery/ticks_and_spines/images/sphx_glr_date_precision_and_epochs_002.png :alt: Epoch: 1970-01-01T00:00:00 :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 145-152 ------------ References """""""""" The use of the following functions, methods and classes is shown in this example: .. GENERATED FROM PYTHON SOURCE LINES 152-156 .. code-block:: default matplotlib.dates.num2date matplotlib.dates.date2num matplotlib.dates.set_epoch .. rst-class:: sphx-glr-script-out Out: .. code-block:: none .. _sphx_glr_download_gallery_ticks_and_spines_date_precision_and_epochs.py: .. only :: html .. container:: sphx-glr-footer :class: sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: date_precision_and_epochs.py ` .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: date_precision_and_epochs.ipynb ` .. only:: html .. rst-class:: sphx-glr-signature Keywords: matplotlib code example, codex, python plot, pyplot `Gallery generated by Sphinx-Gallery `_