Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 478ea3d

Browse files
committed
FIX: properly set tz for YearLocator
FIX: add check for py3.5 to fail if naive datetime TST: make pytz yearlylocator test FIX: use localize instead of astimezone FIX: factor out localization
1 parent ac0525e commit 478ea3d

File tree

2 files changed

+126
-6
lines changed

2 files changed

+126
-6
lines changed

lib/matplotlib/dates.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,7 +1189,7 @@ def __init__(self, tz=None, minticks=5, maxticks=None,
11891189
locator.intervald[HOURLY] = [3] # only show every 3 hours
11901190
"""
11911191
DateLocator.__init__(self, tz)
1192-
self._locator = YearLocator()
1192+
self._locator = YearLocator(tz=tz)
11931193
self._freq = YEARLY
11941194
self._freqs = [YEARLY, MONTHLY, DAILY, HOURLY, MINUTELY,
11951195
SECONDLY, MICROSECONDLY]
@@ -1344,7 +1344,7 @@ def get_locator(self, dmin, dmax):
13441344
'AutoDateLocator.')
13451345

13461346
if (freq == YEARLY) and self.interval_multiples:
1347-
locator = YearLocator(interval)
1347+
locator = YearLocator(interval, tz=self.tz)
13481348
elif use_rrule_locator[i]:
13491349
_, bymonth, bymonthday, byhour, byminute, bysecond, _ = byranges
13501350
rrule = rrulewrapper(self._freq, interval=interval,
@@ -1369,6 +1369,17 @@ def get_locator(self, dmin, dmax):
13691369
return locator
13701370

13711371

1372+
def _localize_tz(date, tz):
1373+
"""
1374+
Helper to get around different time types handling of timezones.
1375+
Basically pytz doesn't handle `tzinfo`.
1376+
"""
1377+
if hasattr(tz, 'localize'):
1378+
date = date.replace(tzinfo=None)
1379+
return tz.localize(date, is_dst=True)
1380+
return date.replace(tzinfo=tz)
1381+
1382+
13721383
class YearLocator(DateLocator):
13731384
"""
13741385
Make ticks on a given day of each year that is a multiple of base.
@@ -1393,7 +1404,6 @@ def __init__(self, base=1, month=1, day=1, tz=None):
13931404
'hour': 0,
13941405
'minute': 0,
13951406
'second': 0,
1396-
'tzinfo': tz
13971407
}
13981408

13991409
def __call__(self):
@@ -1409,13 +1419,22 @@ def tick_values(self, vmin, vmax):
14091419
ymin = self.base.le(vmin.year) * self.base.step
14101420
ymax = self.base.ge(vmax.year) * self.base.step
14111421

1412-
ticks = [vmin.replace(year=ymin, **self.replaced)]
1422+
vmin = vmin.replace(year=ymin, **self.replaced)
1423+
print('vmin before', vmin)
1424+
vmin = _localize_tz(vmin, self.tz)
1425+
print('vmin after', vmin)
1426+
1427+
ticks = [vmin]
1428+
14131429
while True:
14141430
dt = ticks[-1]
14151431
if dt.year >= ymax:
14161432
return date2num(ticks)
14171433
year = dt.year + self.base.step
1418-
ticks.append(dt.replace(year=year, **self.replaced))
1434+
dt = dt.replace(year=year, **self.replaced)
1435+
dt = _localize_tz(dt, self.tz)
1436+
1437+
ticks.append(dt)
14191438

14201439
def autoscale(self):
14211440
"""
@@ -1426,7 +1445,9 @@ def autoscale(self):
14261445
ymin = self.base.le(dmin.year)
14271446
ymax = self.base.ge(dmax.year)
14281447
vmin = dmin.replace(year=ymin, **self.replaced)
1448+
vmin = vmin.astimezone(self.tz)
14291449
vmax = dmax.replace(year=ymax, **self.replaced)
1450+
vmax = vmax.astimezone(self.tz)
14301451

14311452
vmin = date2num(vmin)
14321453
vmax = date2num(vmax)

lib/matplotlib/tests/test_dates.py

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from matplotlib.cbook import MatplotlibDeprecationWarning
1313
import matplotlib.dates as mdates
1414
import matplotlib.ticker as mticker
15+
from matplotlib import rc_context
1516

1617

1718
def __has_pytz():
@@ -439,7 +440,6 @@ def _create_auto_date_locator(date1, date2):
439440
mdates.date2num(date2))
440441
return locator
441442

442-
d1 = datetime.datetime(1997, 1, 1)
443443
results = ([datetime.timedelta(weeks=52 * 200),
444444
['1980-01-01 00:00:00+00:00', '2000-01-01 00:00:00+00:00',
445445
'2020-01-01 00:00:00+00:00', '2040-01-01 00:00:00+00:00',
@@ -500,12 +500,84 @@ def _create_auto_date_locator(date1, date2):
500500
],
501501
)
502502

503+
d1 = datetime.datetime(1997, 1, 1)
503504
for t_delta, expected in results:
504505
d2 = d1 + t_delta
505506
locator = _create_auto_date_locator(d1, d2)
506507
assert list(map(str, mdates.num2date(locator()))) == expected
507508

508509

510+
def test_auto_date_locator_intmult_tz():
511+
def _create_auto_date_locator(date1, date2, tz):
512+
locator = mdates.AutoDateLocator(interval_multiples=True, tz=tz)
513+
locator.create_dummy_axis()
514+
locator.set_view_interval(mdates.date2num(date1),
515+
mdates.date2num(date2))
516+
return locator
517+
518+
results = ([datetime.timedelta(weeks=52*200),
519+
['1980-01-01 00:00:00-08:00', '2000-01-01 00:00:00-08:00',
520+
'2020-01-01 00:00:00-08:00', '2040-01-01 00:00:00-08:00',
521+
'2060-01-01 00:00:00-08:00', '2080-01-01 00:00:00-08:00',
522+
'2100-01-01 00:00:00-08:00', '2120-01-01 00:00:00-08:00',
523+
'2140-01-01 00:00:00-08:00', '2160-01-01 00:00:00-08:00',
524+
'2180-01-01 00:00:00-08:00', '2200-01-01 00:00:00-08:00']
525+
],
526+
[datetime.timedelta(weeks=52),
527+
['1997-01-01 00:00:00-08:00', '1997-02-01 00:00:00-08:00',
528+
'1997-03-01 00:00:00-08:00', '1997-04-01 00:00:00-08:00',
529+
'1997-05-01 00:00:00-07:00', '1997-06-01 00:00:00-07:00',
530+
'1997-07-01 00:00:00-07:00', '1997-08-01 00:00:00-07:00',
531+
'1997-09-01 00:00:00-07:00', '1997-10-01 00:00:00-07:00',
532+
'1997-11-01 00:00:00-08:00', '1997-12-01 00:00:00-08:00']
533+
],
534+
[datetime.timedelta(days=141),
535+
['1997-01-01 00:00:00-08:00', '1997-01-22 00:00:00-08:00',
536+
'1997-02-01 00:00:00-08:00', '1997-02-22 00:00:00-08:00',
537+
'1997-03-01 00:00:00-08:00', '1997-03-22 00:00:00-08:00',
538+
'1997-04-01 00:00:00-08:00', '1997-04-22 00:00:00-07:00',
539+
'1997-05-01 00:00:00-07:00', '1997-05-22 00:00:00-07:00']
540+
],
541+
[datetime.timedelta(days=40),
542+
['1997-01-01 00:00:00-08:00', '1997-01-05 00:00:00-08:00',
543+
'1997-01-09 00:00:00-08:00', '1997-01-13 00:00:00-08:00',
544+
'1997-01-17 00:00:00-08:00', '1997-01-21 00:00:00-08:00',
545+
'1997-01-25 00:00:00-08:00', '1997-01-29 00:00:00-08:00',
546+
'1997-02-01 00:00:00-08:00', '1997-02-05 00:00:00-08:00',
547+
'1997-02-09 00:00:00-08:00']
548+
],
549+
[datetime.timedelta(hours=40),
550+
['1997-01-01 00:00:00-08:00', '1997-01-01 04:00:00-08:00',
551+
'1997-01-01 08:00:00-08:00', '1997-01-01 12:00:00-08:00',
552+
'1997-01-01 16:00:00-08:00', '1997-01-01 20:00:00-08:00',
553+
'1997-01-02 00:00:00-08:00', '1997-01-02 04:00:00-08:00',
554+
'1997-01-02 08:00:00-08:00', '1997-01-02 12:00:00-08:00',
555+
'1997-01-02 16:00:00-08:00']
556+
],
557+
[datetime.timedelta(minutes=20),
558+
['1997-01-01 00:00:00-08:00', '1997-01-01 00:05:00-08:00',
559+
'1997-01-01 00:10:00-08:00', '1997-01-01 00:15:00-08:00',
560+
'1997-01-01 00:20:00-08:00']
561+
],
562+
[datetime.timedelta(seconds=40),
563+
['1997-01-01 00:00:00-08:00', '1997-01-01 00:00:05-08:00',
564+
'1997-01-01 00:00:10-08:00', '1997-01-01 00:00:15-08:00',
565+
'1997-01-01 00:00:20-08:00', '1997-01-01 00:00:25-08:00',
566+
'1997-01-01 00:00:30-08:00', '1997-01-01 00:00:35-08:00',
567+
'1997-01-01 00:00:40-08:00']
568+
]
569+
)
570+
571+
tz = dateutil.tz.gettz('Canada/Pacific')
572+
d1 = datetime.datetime(1997, 1, 1, tzinfo=tz)
573+
for t_delta, expected in results:
574+
with rc_context({'_internal.classic_mode': False}):
575+
d2 = d1 + t_delta
576+
locator = _create_auto_date_locator(d1, d2, tz)
577+
st = list(map(str, mdates.num2date(locator(), tz=tz)))
578+
assert st == expected
579+
580+
509581
@image_comparison(baseline_images=['date_inverted_limit'],
510582
extensions=['png'])
511583
def test_date_inverted_limit():
@@ -650,6 +722,33 @@ def attach_tz(dt, zi):
650722
_test_rrulewrapper(attach_tz, pytz.timezone)
651723

652724

725+
@pytest.mark.pytz
726+
@pytest.mark.skipif(not __has_pytz(), reason="Requires pytz")
727+
def test_yearlocator_pytz():
728+
import pytz
729+
730+
tz = pytz.timezone('Canada/Pacific')
731+
# test chaning the time zones. Note that this start date is
732+
# after the start of the year in NY because it is in Pacific TZ; e.g.
733+
# it is 03:00 in NY, so the 2009 tick is not returned below.
734+
tz2 = pytz.timezone('America/New_York')
735+
x = [tz.localize(datetime.datetime(2010, 1, 1))
736+
+ datetime.timedelta(i) for i in range(2000)]
737+
locator = mdates.AutoDateLocator(interval_multiples=True, tz=tz2)
738+
locator.create_dummy_axis()
739+
locator.set_view_interval(mdates.date2num(x[0])+0.0,
740+
mdates.date2num(x[-1])+1.0)
741+
742+
np.testing.assert_allclose([733773.208333, 734138.208333,
743+
734503.208333, 734869.208333,
744+
735234.208333, 735599.208333], locator())
745+
expected = ['2010-01-01 00:00:00-05:00', '2011-01-01 00:00:00-05:00',
746+
'2012-01-01 00:00:00-05:00', '2013-01-01 00:00:00-05:00',
747+
'2014-01-01 00:00:00-05:00', '2015-01-01 00:00:00-05:00']
748+
st = list(map(str, mdates.num2date(locator(), tz=tz2)))
749+
assert st == expected
750+
751+
653752
def test_DayLocator():
654753
with pytest.raises(ValueError):
655754
mdates.DayLocator(interval=-1)

0 commit comments

Comments
 (0)