
.. 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 <sphx_glr_download_gallery_ticks_and_spines_date_precision_and_epochs.py>`
        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

    /build/matplotlib-eAPYn3/matplotlib-3.3.4/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


    <function set_epoch at 0x7f73bea27a60>




.. rst-class:: sphx-glr-timing

   **Total running time of the script:** ( 0 minutes  1.390 seconds)


.. _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 <date_precision_and_epochs.py>`



  .. container:: sphx-glr-download sphx-glr-download-jupyter

     :download:`Download Jupyter notebook: date_precision_and_epochs.ipynb <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
    <https://sphinx-gallery.readthedocs.io>`_
