Skip to content

Commit 9f6cf2b

Browse files
jklymakdstansby
authored andcommitted
Backport PR #12678: FIX: properly set tz for YearLocator (#13308)
1 parent 5e7a327 commit 9f6cf2b

File tree

2 files changed

+121
-6
lines changed

2 files changed

+121
-6
lines changed

lib/matplotlib/dates.py

+23-5
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,7 @@ def __init__(self, tz=None, minticks=5, maxticks=None,
11871187
locator.intervald[HOURLY] = [3] # only show every 3 hours
11881188
"""
11891189
DateLocator.__init__(self, tz)
1190-
self._locator = YearLocator()
1190+
self._locator = YearLocator(tz=tz)
11911191
self._freq = YEARLY
11921192
self._freqs = [YEARLY, MONTHLY, DAILY, HOURLY, MINUTELY,
11931193
SECONDLY, MICROSECONDLY]
@@ -1340,7 +1340,7 @@ def get_locator(self, dmin, dmax):
13401340
'AutoDateLocator.')
13411341

13421342
if (freq == YEARLY) and self.interval_multiples:
1343-
locator = YearLocator(interval)
1343+
locator = YearLocator(interval, tz=self.tz)
13441344
elif use_rrule_locator[i]:
13451345
_, bymonth, bymonthday, byhour, byminute, bysecond, _ = byranges
13461346
rrule = rrulewrapper(self._freq, interval=interval,
@@ -1390,8 +1390,11 @@ def __init__(self, base=1, month=1, day=1, tz=None):
13901390
'hour': 0,
13911391
'minute': 0,
13921392
'second': 0,
1393-
'tzinfo': tz
13941393
}
1394+
if not hasattr(tz, 'localize'):
1395+
# if tz is pytz, we need to do this w/ the localize fcn,
1396+
# otherwise datetime.replace works fine...
1397+
self.replaced['tzinfo'] = tz
13951398

13961399
def __call__(self):
13971400
# if no data have been set, this will tank with a ValueError
@@ -1406,13 +1409,26 @@ def tick_values(self, vmin, vmax):
14061409
ymin = self.base.le(vmin.year) * self.base.step
14071410
ymax = self.base.ge(vmax.year) * self.base.step
14081411

1409-
ticks = [vmin.replace(year=ymin, **self.replaced)]
1412+
vmin = vmin.replace(year=ymin, **self.replaced)
1413+
if hasattr(self.tz, 'localize'):
1414+
# look after pytz
1415+
if not vmin.tzinfo:
1416+
vmin = self.tz.localize(vmin, is_dst=True)
1417+
1418+
ticks = [vmin]
1419+
14101420
while True:
14111421
dt = ticks[-1]
14121422
if dt.year >= ymax:
14131423
return date2num(ticks)
14141424
year = dt.year + self.base.step
1415-
ticks.append(dt.replace(year=year, **self.replaced))
1425+
dt = dt.replace(year=year, **self.replaced)
1426+
if hasattr(self.tz, 'localize'):
1427+
# look after pytz
1428+
if not dt.tzinfo:
1429+
dt = self.tz.localize(dt, is_dst=True)
1430+
1431+
ticks.append(dt)
14161432

14171433
def autoscale(self):
14181434
"""
@@ -1423,7 +1439,9 @@ def autoscale(self):
14231439
ymin = self.base.le(dmin.year)
14241440
ymax = self.base.ge(dmax.year)
14251441
vmin = dmin.replace(year=ymin, **self.replaced)
1442+
vmin = vmin.astimezone(self.tz)
14261443
vmax = dmax.replace(year=ymax, **self.replaced)
1444+
vmax = vmax.astimezone(self.tz)
14271445

14281446
vmin = date2num(vmin)
14291447
vmax = date2num(vmax)

lib/matplotlib/tests/test_dates.py

+98-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
import matplotlib.pyplot as plt
1212
from matplotlib.cbook import MatplotlibDeprecationWarning
1313
import matplotlib.dates as mdates
14+
import matplotlib.ticker as mticker
15+
from matplotlib import rc_context
1416

1517

1618
def __has_pytz():
@@ -406,7 +408,6 @@ def _create_auto_date_locator(date1, date2):
406408
mdates.date2num(date2))
407409
return locator
408410

409-
d1 = datetime.datetime(1997, 1, 1)
410411
results = ([datetime.timedelta(weeks=52 * 200),
411412
['1980-01-01 00:00:00+00:00', '2000-01-01 00:00:00+00:00',
412413
'2020-01-01 00:00:00+00:00', '2040-01-01 00:00:00+00:00',
@@ -467,12 +468,84 @@ def _create_auto_date_locator(date1, date2):
467468
],
468469
)
469470

471+
d1 = datetime.datetime(1997, 1, 1)
470472
for t_delta, expected in results:
471473
d2 = d1 + t_delta
472474
locator = _create_auto_date_locator(d1, d2)
473475
assert list(map(str, mdates.num2date(locator()))) == expected
474476

475477

478+
def test_auto_date_locator_intmult_tz():
479+
def _create_auto_date_locator(date1, date2, tz):
480+
locator = mdates.AutoDateLocator(interval_multiples=True, tz=tz)
481+
locator.create_dummy_axis()
482+
locator.set_view_interval(mdates.date2num(date1),
483+
mdates.date2num(date2))
484+
return locator
485+
486+
results = ([datetime.timedelta(weeks=52*200),
487+
['1980-01-01 00:00:00-08:00', '2000-01-01 00:00:00-08:00',
488+
'2020-01-01 00:00:00-08:00', '2040-01-01 00:00:00-08:00',
489+
'2060-01-01 00:00:00-08:00', '2080-01-01 00:00:00-08:00',
490+
'2100-01-01 00:00:00-08:00', '2120-01-01 00:00:00-08:00',
491+
'2140-01-01 00:00:00-08:00', '2160-01-01 00:00:00-08:00',
492+
'2180-01-01 00:00:00-08:00', '2200-01-01 00:00:00-08:00']
493+
],
494+
[datetime.timedelta(weeks=52),
495+
['1997-01-01 00:00:00-08:00', '1997-02-01 00:00:00-08:00',
496+
'1997-03-01 00:00:00-08:00', '1997-04-01 00:00:00-08:00',
497+
'1997-05-01 00:00:00-07:00', '1997-06-01 00:00:00-07:00',
498+
'1997-07-01 00:00:00-07:00', '1997-08-01 00:00:00-07:00',
499+
'1997-09-01 00:00:00-07:00', '1997-10-01 00:00:00-07:00',
500+
'1997-11-01 00:00:00-08:00', '1997-12-01 00:00:00-08:00']
501+
],
502+
[datetime.timedelta(days=141),
503+
['1997-01-01 00:00:00-08:00', '1997-01-22 00:00:00-08:00',
504+
'1997-02-01 00:00:00-08:00', '1997-02-22 00:00:00-08:00',
505+
'1997-03-01 00:00:00-08:00', '1997-03-22 00:00:00-08:00',
506+
'1997-04-01 00:00:00-08:00', '1997-04-22 00:00:00-07:00',
507+
'1997-05-01 00:00:00-07:00', '1997-05-22 00:00:00-07:00']
508+
],
509+
[datetime.timedelta(days=40),
510+
['1997-01-01 00:00:00-08:00', '1997-01-05 00:00:00-08:00',
511+
'1997-01-09 00:00:00-08:00', '1997-01-13 00:00:00-08:00',
512+
'1997-01-17 00:00:00-08:00', '1997-01-21 00:00:00-08:00',
513+
'1997-01-25 00:00:00-08:00', '1997-01-29 00:00:00-08:00',
514+
'1997-02-01 00:00:00-08:00', '1997-02-05 00:00:00-08:00',
515+
'1997-02-09 00:00:00-08:00']
516+
],
517+
[datetime.timedelta(hours=40),
518+
['1997-01-01 00:00:00-08:00', '1997-01-01 04:00:00-08:00',
519+
'1997-01-01 08:00:00-08:00', '1997-01-01 12:00:00-08:00',
520+
'1997-01-01 16:00:00-08:00', '1997-01-01 20:00:00-08:00',
521+
'1997-01-02 00:00:00-08:00', '1997-01-02 04:00:00-08:00',
522+
'1997-01-02 08:00:00-08:00', '1997-01-02 12:00:00-08:00',
523+
'1997-01-02 16:00:00-08:00']
524+
],
525+
[datetime.timedelta(minutes=20),
526+
['1997-01-01 00:00:00-08:00', '1997-01-01 00:05:00-08:00',
527+
'1997-01-01 00:10:00-08:00', '1997-01-01 00:15:00-08:00',
528+
'1997-01-01 00:20:00-08:00']
529+
],
530+
[datetime.timedelta(seconds=40),
531+
['1997-01-01 00:00:00-08:00', '1997-01-01 00:00:05-08:00',
532+
'1997-01-01 00:00:10-08:00', '1997-01-01 00:00:15-08:00',
533+
'1997-01-01 00:00:20-08:00', '1997-01-01 00:00:25-08:00',
534+
'1997-01-01 00:00:30-08:00', '1997-01-01 00:00:35-08:00',
535+
'1997-01-01 00:00:40-08:00']
536+
]
537+
)
538+
539+
tz = dateutil.tz.gettz('Canada/Pacific')
540+
d1 = datetime.datetime(1997, 1, 1, tzinfo=tz)
541+
for t_delta, expected in results:
542+
with rc_context({'_internal.classic_mode': False}):
543+
d2 = d1 + t_delta
544+
locator = _create_auto_date_locator(d1, d2, tz)
545+
st = list(map(str, mdates.num2date(locator(), tz=tz)))
546+
assert st == expected
547+
548+
476549
@image_comparison(baseline_images=['date_inverted_limit'],
477550
extensions=['png'])
478551
def test_date_inverted_limit():
@@ -617,6 +690,30 @@ def attach_tz(dt, zi):
617690
_test_rrulewrapper(attach_tz, pytz.timezone)
618691

619692

693+
@pytest.mark.pytz
694+
@pytest.mark.skipif(not __has_pytz(), reason="Requires pytz")
695+
def test_yearlocator_pytz():
696+
import pytz
697+
698+
tz = pytz.timezone('America/New_York')
699+
x = [tz.localize(datetime.datetime(2010, 1, 1))
700+
+ datetime.timedelta(i) for i in range(2000)]
701+
locator = mdates.AutoDateLocator(interval_multiples=True, tz=tz)
702+
locator.create_dummy_axis()
703+
locator.set_view_interval(mdates.date2num(x[0])-1.0,
704+
mdates.date2num(x[-1])+1.0)
705+
706+
np.testing.assert_allclose([733408.208333, 733773.208333, 734138.208333,
707+
734503.208333, 734869.208333,
708+
735234.208333, 735599.208333], locator())
709+
expected = ['2009-01-01 00:00:00-05:00',
710+
'2010-01-01 00:00:00-05:00', '2011-01-01 00:00:00-05:00',
711+
'2012-01-01 00:00:00-05:00', '2013-01-01 00:00:00-05:00',
712+
'2014-01-01 00:00:00-05:00', '2015-01-01 00:00:00-05:00']
713+
st = list(map(str, mdates.num2date(locator(), tz=tz)))
714+
assert st == expected
715+
716+
620717
def test_DayLocator():
621718
with pytest.raises(ValueError):
622719
mdates.DayLocator(interval=-1)

0 commit comments

Comments
 (0)