Skip to content
Advertisement

Why time zone conversation doesn’t affect the figure in plotting datetime objects in matplotlib?

I’m trying to plot a figure in which dates, without times, are in x-axis and times, without dates, are in y-axis:

import datetime as dt
import matplotlib.pyplot as plt
import matplotlib.dates as mdates


dates = [dt.datetime(2020, 8, 11),
         dt.datetime(2020, 8,  9),
         dt.datetime(2020, 8,  8),
         dt.datetime(2020, 8,  6),
         dt.datetime(2020, 8,  4),
         dt.datetime(2020, 8,  3)]

times = [dt.datetime(1900, 1, 1, 22,  7, 0),
         dt.datetime(1900, 1, 1, 23,  0, 0),
         dt.datetime(1900, 1, 1, 21,  5, 0),
         dt.datetime(1900, 1, 1,  2, 33, 0),
         dt.datetime(1900, 1, 1,  2, 33, 0),
         dt.datetime(1900, 1, 1, 14,  0, 0)]

fig, ax = plt.subplots()

ax.plot(dates, times, "ro")

ax.yaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
plt.gca().yaxis.set_major_locator(mdates.HourLocator())

ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m/%d"))
plt.gca().xaxis.set_major_locator(mdates.DayLocator())

fig.autofmt_xdate()

plt.show()

The above code works well. However when I convert time zones from UTC to US/Eastern I get the same result, as if I did nothing.

import pytz
old_timezone = pytz.timezone("UTC")
new_timezone = pytz.timezone("US/Eastern")
times = [old_timezone.localize(t).astimezone(new_timezone) for t in times]

The result of both before and after time zone conversation:

enter image description here

When I print, for example, first element of the list times before and after conversation I get different and the desired result. So the conversation works well:

1900-01-01 22:07:00       # before
1900-01-01 17:11:00-04:56 # after

Advertisement

Answer

to get a correct localization of the time, I suggest to combine the date from your dates list with the time from your times list – assuming they belong together! otherwise, localization will most likely be incorrect for the date 1900-1-1.

import datetime as dt
from dateutil.tz import gettz

dates = [dt.datetime(2020, 8, 11),
         dt.datetime(2020, 8,  9),
         dt.datetime(2020, 8,  8),
         dt.datetime(2020, 8,  6),
         dt.datetime(2020, 8,  4),
         dt.datetime(2020, 8,  3)]

times = [dt.datetime(1900, 1, 1, 22,  7, 0),
         dt.datetime(1900, 1, 1, 23,  0, 0),
         dt.datetime(1900, 1, 1, 21,  5, 0),
         dt.datetime(1900, 1, 1,  2, 33, 0),
         dt.datetime(1900, 1, 1,  2, 33, 0),
         dt.datetime(1900, 1, 1, 14,  0, 0)]

loctimes = [dt.datetime.combine( # outer combine:
                dt.date(1900, 1, 1), # will reset the date back to 1900-01-01
                dt.datetime.combine(d.date(), t.time()) # inner combine: date from "dates" with time from "times"
                .replace(tzinfo=dt.timezone.utc) # define that it's UTC
                .astimezone(gettz('US/Eastern')) # change timezone to US/Eastern
                .time() # use only the time part from the inner combine
            ) # outer combine done
            for d, t in zip(dates, times)]

# loctimes
# [datetime.datetime(1900, 1, 1, 18, 7),
#  datetime.datetime(1900, 1, 1, 19, 0),
#  datetime.datetime(1900, 1, 1, 17, 5),
#  datetime.datetime(1900, 1, 1, 22, 33),
#  datetime.datetime(1900, 1, 1, 22, 33),
#  datetime.datetime(1900, 1, 1, 10, 0)]

now the plot works as expected:

import matplotlib.pyplot as plt
import matplotlib.dates as mdates

fig, ax = plt.subplots()
ax.plot(dates, loctimes, "ro")
ax.yaxis.set_major_formatter(mdates.DateFormatter("%H:%M"))
plt.gca().yaxis.set_major_locator(mdates.HourLocator())
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y/%m/%d"))
plt.gca().xaxis.set_major_locator(mdates.DayLocator())
fig.autofmt_xdate()
plt.show()

enter image description here

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement