Skip to content

FIX: properly set tz for YearLocator #12678

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions lib/matplotlib/dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -1417,7 +1417,7 @@ def __init__(self, tz=None, minticks=5, maxticks=None,
locator.intervald[HOURLY] = [3] # only show every 3 hours
"""
DateLocator.__init__(self, tz)
self._locator = YearLocator()
self._locator = YearLocator(tz=tz)
self._freq = YEARLY
self._freqs = [YEARLY, MONTHLY, DAILY, HOURLY, MINUTELY,
SECONDLY, MICROSECONDLY]
Expand Down Expand Up @@ -1574,7 +1574,7 @@ def get_locator(self, dmin, dmax):
'AutoDateLocator.')

if (freq == YEARLY) and self.interval_multiples:
locator = YearLocator(interval)
locator = YearLocator(interval, tz=self.tz)
elif use_rrule_locator[i]:
_, bymonth, bymonthday, byhour, byminute, bysecond, _ = byranges
rrule = rrulewrapper(self._freq, interval=interval,
Expand Down Expand Up @@ -1623,8 +1623,11 @@ def __init__(self, base=1, month=1, day=1, tz=None):
'hour': 0,
'minute': 0,
'second': 0,
'tzinfo': tz
}
if not hasattr(tz, 'localize'):
# if tz is pytz, we need to do this w/ the localize fcn,
# otherwise datetime.replace works fine...
self.replaced['tzinfo'] = tz

def __call__(self):
# if no data have been set, this will tank with a ValueError
Expand All @@ -1639,13 +1642,26 @@ def tick_values(self, vmin, vmax):
ymin = self.base.le(vmin.year) * self.base.step
ymax = self.base.ge(vmax.year) * self.base.step

ticks = [vmin.replace(year=ymin, **self.replaced)]
vmin = vmin.replace(year=ymin, **self.replaced)
if hasattr(self.tz, 'localize'):
# look after pytz
if not vmin.tzinfo:
vmin = self.tz.localize(vmin, is_dst=True)

ticks = [vmin]

while True:
dt = ticks[-1]
if dt.year >= ymax:
return date2num(ticks)
year = dt.year + self.base.step
ticks.append(dt.replace(year=year, **self.replaced))
dt = dt.replace(year=year, **self.replaced)
if hasattr(self.tz, 'localize'):
# look after pytz
if not dt.tzinfo:
dt = self.tz.localize(dt, is_dst=True)

ticks.append(dt)

def autoscale(self):
"""
Expand All @@ -1656,7 +1672,9 @@ def autoscale(self):
ymin = self.base.le(dmin.year)
ymax = self.base.ge(dmax.year)
vmin = dmin.replace(year=ymin, **self.replaced)
vmin = vmin.astimezone(self.tz)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this acutally different from he above cases?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ummm, hmmm, not sure this was properly tested....

vmax = dmax.replace(year=ymax, **self.replaced)
vmax = vmax.astimezone(self.tz)

vmin = date2num(vmin)
vmax = date2num(vmax)
Expand Down
98 changes: 97 additions & 1 deletion lib/matplotlib/tests/test_dates.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from matplotlib.cbook import MatplotlibDeprecationWarning
import matplotlib.dates as mdates
import matplotlib.ticker as mticker
from matplotlib import rc_context


def __has_pytz():
Expand Down Expand Up @@ -439,7 +440,6 @@ def _create_auto_date_locator(date1, date2):
mdates.date2num(date2))
return locator

d1 = datetime.datetime(1997, 1, 1)
results = ([datetime.timedelta(weeks=52 * 200),
['1980-01-01 00:00:00+00:00', '2000-01-01 00:00:00+00:00',
'2020-01-01 00:00:00+00:00', '2040-01-01 00:00:00+00:00',
Expand Down Expand Up @@ -500,6 +500,7 @@ def _create_auto_date_locator(date1, date2):
],
)

d1 = datetime.datetime(1997, 1, 1)
for t_delta, expected in results:
d2 = d1 + t_delta
locator = _create_auto_date_locator(d1, d2)
Expand Down Expand Up @@ -557,6 +558,77 @@ def _create_auto_date_locator(date1, date2):
assert strings == expected


def test_auto_date_locator_intmult_tz():
def _create_auto_date_locator(date1, date2, tz):
locator = mdates.AutoDateLocator(interval_multiples=True, tz=tz)
locator.create_dummy_axis()
locator.set_view_interval(mdates.date2num(date1),
mdates.date2num(date2))
return locator

results = ([datetime.timedelta(weeks=52*200),
['1980-01-01 00:00:00-08:00', '2000-01-01 00:00:00-08:00',
'2020-01-01 00:00:00-08:00', '2040-01-01 00:00:00-08:00',
'2060-01-01 00:00:00-08:00', '2080-01-01 00:00:00-08:00',
'2100-01-01 00:00:00-08:00', '2120-01-01 00:00:00-08:00',
'2140-01-01 00:00:00-08:00', '2160-01-01 00:00:00-08:00',
'2180-01-01 00:00:00-08:00', '2200-01-01 00:00:00-08:00']
],
[datetime.timedelta(weeks=52),
['1997-01-01 00:00:00-08:00', '1997-02-01 00:00:00-08:00',
'1997-03-01 00:00:00-08:00', '1997-04-01 00:00:00-08:00',
'1997-05-01 00:00:00-07:00', '1997-06-01 00:00:00-07:00',
'1997-07-01 00:00:00-07:00', '1997-08-01 00:00:00-07:00',
'1997-09-01 00:00:00-07:00', '1997-10-01 00:00:00-07:00',
'1997-11-01 00:00:00-08:00', '1997-12-01 00:00:00-08:00']
],
[datetime.timedelta(days=141),
['1997-01-01 00:00:00-08:00', '1997-01-22 00:00:00-08:00',
'1997-02-01 00:00:00-08:00', '1997-02-22 00:00:00-08:00',
'1997-03-01 00:00:00-08:00', '1997-03-22 00:00:00-08:00',
'1997-04-01 00:00:00-08:00', '1997-04-22 00:00:00-07:00',
'1997-05-01 00:00:00-07:00', '1997-05-22 00:00:00-07:00']
],
[datetime.timedelta(days=40),
['1997-01-01 00:00:00-08:00', '1997-01-05 00:00:00-08:00',
'1997-01-09 00:00:00-08:00', '1997-01-13 00:00:00-08:00',
'1997-01-17 00:00:00-08:00', '1997-01-21 00:00:00-08:00',
'1997-01-25 00:00:00-08:00', '1997-01-29 00:00:00-08:00',
'1997-02-01 00:00:00-08:00', '1997-02-05 00:00:00-08:00',
'1997-02-09 00:00:00-08:00']
],
[datetime.timedelta(hours=40),
['1997-01-01 00:00:00-08:00', '1997-01-01 04:00:00-08:00',
'1997-01-01 08:00:00-08:00', '1997-01-01 12:00:00-08:00',
'1997-01-01 16:00:00-08:00', '1997-01-01 20:00:00-08:00',
'1997-01-02 00:00:00-08:00', '1997-01-02 04:00:00-08:00',
'1997-01-02 08:00:00-08:00', '1997-01-02 12:00:00-08:00',
'1997-01-02 16:00:00-08:00']
],
[datetime.timedelta(minutes=20),
['1997-01-01 00:00:00-08:00', '1997-01-01 00:05:00-08:00',
'1997-01-01 00:10:00-08:00', '1997-01-01 00:15:00-08:00',
'1997-01-01 00:20:00-08:00']
],
[datetime.timedelta(seconds=40),
['1997-01-01 00:00:00-08:00', '1997-01-01 00:00:05-08:00',
'1997-01-01 00:00:10-08:00', '1997-01-01 00:00:15-08:00',
'1997-01-01 00:00:20-08:00', '1997-01-01 00:00:25-08:00',
'1997-01-01 00:00:30-08:00', '1997-01-01 00:00:35-08:00',
'1997-01-01 00:00:40-08:00']
]
)

tz = dateutil.tz.gettz('Canada/Pacific')
d1 = datetime.datetime(1997, 1, 1, tzinfo=tz)
for t_delta, expected in results:
with rc_context({'_internal.classic_mode': False}):
d2 = d1 + t_delta
locator = _create_auto_date_locator(d1, d2, tz)
st = list(map(str, mdates.num2date(locator(), tz=tz)))
assert st == expected


@image_comparison(baseline_images=['date_inverted_limit'],
extensions=['png'])
def test_date_inverted_limit():
Expand Down Expand Up @@ -701,6 +773,30 @@ def attach_tz(dt, zi):
_test_rrulewrapper(attach_tz, pytz.timezone)


@pytest.mark.pytz
@pytest.mark.skipif(not __has_pytz(), reason="Requires pytz")
def test_yearlocator_pytz():
import pytz

tz = pytz.timezone('America/New_York')
x = [tz.localize(datetime.datetime(2010, 1, 1))
+ datetime.timedelta(i) for i in range(2000)]
locator = mdates.AutoDateLocator(interval_multiples=True, tz=tz)
locator.create_dummy_axis()
locator.set_view_interval(mdates.date2num(x[0])-1.0,
mdates.date2num(x[-1])+1.0)

np.testing.assert_allclose([733408.208333, 733773.208333, 734138.208333,
734503.208333, 734869.208333,
735234.208333, 735599.208333], locator())
expected = ['2009-01-01 00:00:00-05:00',
'2010-01-01 00:00:00-05:00', '2011-01-01 00:00:00-05:00',
'2012-01-01 00:00:00-05:00', '2013-01-01 00:00:00-05:00',
'2014-01-01 00:00:00-05:00', '2015-01-01 00:00:00-05:00']
st = list(map(str, mdates.num2date(locator(), tz=tz)))
assert st == expected


def test_DayLocator():
with pytest.raises(ValueError):
mdates.DayLocator(interval=-1)
Expand Down