Skip to content

Commit 1158778

Browse files
author
Oscar Gustafsson
committed
All classes and methods in dates support both string and tzinfo as tz-argument
1 parent ff79835 commit 1158778

File tree

3 files changed

+117
-71
lines changed

3 files changed

+117
-71
lines changed

lib/matplotlib/dates.py

Lines changed: 55 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""
22
Matplotlib provides sophisticated date plotting capabilities, standing on the
3-
shoulders of python :mod:`datetime` and the add-on module :mod:`dateutil`.
3+
shoulders of python :mod:`datetime` and the add-on module dateutil_.
44
55
By default, Matplotlib uses the units machinery described in
66
`~matplotlib.units` to convert `datetime.datetime`, and `numpy.datetime64`
@@ -83,10 +83,11 @@
8383
Out[1]: 732401
8484
8585
All the Matplotlib date converters, tickers and formatters are timezone aware.
86-
If no explicit timezone is provided, :rc:`timezone` is assumed. If you want to
87-
use a custom time zone, pass a `datetime.tzinfo` instance with the tz keyword
88-
argument to `num2date`, `.Axis.axis_date`, and any custom date tickers or
89-
locators you create.
86+
If no explicit timezone is provided, :rc:`timezone` is assumed, provided as a
87+
string. If you want to use a different timezone, pass the *tz* keyword
88+
argument of `num2date` to any date tickers or locators you create. This can
89+
be either a `datetime.tzinfo` instance or a string with the timezone name that
90+
can be parsed by `~dateutil.tz.gettz`.
9091
9192
A wide range of specific and general purpose date tick locators and
9293
formatters are provided in this module. See
@@ -141,10 +142,10 @@
141142
142143
* `YearLocator`: Locate years that are multiples of base.
143144
144-
* `RRuleLocator`: Locate using a `matplotlib.dates.rrulewrapper`.
145-
`.rrulewrapper` is a simple wrapper around dateutil_'s `dateutil.rrule` which
146-
allow almost arbitrary date tick specifications. See :doc:`rrule example
147-
</gallery/ticks/date_demo_rrule>`.
145+
* `RRuleLocator`: Locate using a ``matplotlib.dates.rrulewrapper``.
146+
``rrulewrapper`` is a simple wrapper around dateutil_'s `dateutil.rrule`
147+
which allow almost arbitrary date tick specifications.
148+
See :doc:`rrule example </gallery/ticks/date_demo_rrule>`.
148149
149150
* `AutoDateLocator`: On autoscale, this class picks the best `DateLocator`
150151
(e.g., `RRuleLocator`) to set the view limits and the tick locations. If
@@ -202,12 +203,24 @@
202203
UTC = datetime.timezone.utc
203204

204205

205-
def _get_rc_timezone():
206-
"""Retrieve the preferred timezone from the rcParams dictionary."""
207-
s = mpl.rcParams['timezone']
208-
if s == 'UTC':
209-
return UTC
210-
return dateutil.tz.gettz(s)
206+
def _get_tzinfo(tz=None):
207+
"""
208+
Generate tzinfo from a string or return tzinfo. If None,
209+
retrieve the preferred timezone from the rcParams dictionary.
210+
"""
211+
if tz is None:
212+
tz = mpl.rcParams['timezone']
213+
if tz == 'UTC':
214+
return UTC
215+
if isinstance(tz, str):
216+
tzinfo = dateutil.tz.gettz(tz)
217+
if tzinfo is None:
218+
raise ValueError(f"{tz} is not a valid timezone as parsed by"
219+
" dateutil.tz.gettz.")
220+
return tzinfo
221+
if isinstance(tz, datetime.tzinfo):
222+
return tz
223+
raise TypeError("tz must be string or tzinfo subclass.")
211224

212225

213226
"""
@@ -341,8 +354,7 @@ def _from_ordinalf(x, tz=None):
341354
:rc:`timezone`.
342355
"""
343356

344-
if tz is None:
345-
tz = _get_rc_timezone()
357+
tz = _get_tzinfo(tz)
346358

347359
dt = (np.datetime64(get_epoch()) +
348360
np.timedelta64(int(np.round(x * MUSECONDS_PER_DAY)), 'us'))
@@ -508,8 +520,8 @@ def num2date(x, tz=None):
508520
Number of days (fraction part represents hours, minutes, seconds)
509521
since the epoch. See `.get_epoch` for the
510522
epoch, which can be changed by :rc:`date.epoch` or `.set_epoch`.
511-
tz : str, default: :rc:`timezone`
512-
Timezone of *x*.
523+
tz : str or `~datetime.tzinfo`, default: :rc:`timezone`
524+
Timezone of *x*. If a string, *tz* is passed to `dateutil.tz`.
513525
514526
Returns
515527
-------
@@ -525,8 +537,7 @@ def num2date(x, tz=None):
525537
Gregorian calendar is assumed; this is not universal practice.
526538
For details, see the module docstring.
527539
"""
528-
if tz is None:
529-
tz = _get_rc_timezone()
540+
tz = _get_tzinfo(tz)
530541
return _from_ordinalf_np_vectorized(x, tz).tolist()
531542

532543

@@ -621,16 +632,14 @@ def __init__(self, fmt, tz=None, *, usetex=None):
621632
----------
622633
fmt : str
623634
`~datetime.datetime.strftime` format string
624-
tz : `datetime.tzinfo`, default: :rc:`timezone`
635+
tz : str or `~datetime.tzinfo`, default: :rc:`timezone`
625636
Ticks timezone.
626637
usetex : bool, default: :rc:`text.usetex`
627638
To enable/disable the use of TeX's math mode for rendering the
628639
results of the formatter.
629640
"""
630-
if tz is None:
631-
tz = _get_rc_timezone()
641+
self.tz = _get_tzinfo(tz)
632642
self.fmt = fmt
633-
self.tz = tz
634643
self._usetex = (usetex if usetex is not None else
635644
mpl.rcParams['text.usetex'])
636645

@@ -639,7 +648,7 @@ def __call__(self, x, pos=0):
639648
return _wrap_in_tex(result) if self._usetex else result
640649

641650
def set_tzinfo(self, tz):
642-
self.tz = tz
651+
self.tz = _get_tzinfo(tz)
643652

644653

645654
class ConciseDateFormatter(ticker.Formatter):
@@ -656,8 +665,8 @@ class ConciseDateFormatter(ticker.Formatter):
656665
locator : `.ticker.Locator`
657666
Locator that this axis is using.
658667
659-
tz : str, optional
660-
Passed to `.dates.date2num`.
668+
tz : str or `~datetime.tzinfo`, default: :rc:`timezone`
669+
Passed to `.dates.num2date`.
661670
662671
formats : list of 6 strings, optional
663672
Format strings for 6 levels of tick labelling: mostly years,
@@ -757,7 +766,7 @@ def __init__(self, locator, tz=None, formats=None, offset_formats=None,
757766

758767
if offset_formats:
759768
if len(offset_formats) != 6:
760-
raise ValueError('offsetfmts argument must be a list of '
769+
raise ValueError('offset_formats argument must be a list of '
761770
'6 format strings (or None)')
762771
self.offset_formats = offset_formats
763772
else:
@@ -927,8 +936,8 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d', *,
927936
locator : `.ticker.Locator`
928937
Locator that this axis is using.
929938
930-
tz : str, optional
931-
Passed to `.dates.date2num`.
939+
tz : str or `~datetime.tzinfo`, optional
940+
Passed to `.dates.num2date`.
932941
933942
defaultfmt : str
934943
The default format to use if none of the values in ``self.scaled``
@@ -1000,7 +1009,7 @@ def set(self, **kwargs):
10001009
def _update_rrule(self, **kwargs):
10011010
tzinfo = self._base_tzinfo
10021011

1003-
# rrule does not play nicely with time zones - especially pytz time
1012+
# rrule does not play nicely with timezones - especially pytz time
10041013
# zones, it's best to use naive zones and attach timezones once the
10051014
# datetimes are returned
10061015
if 'dtstart' in kwargs:
@@ -1103,17 +1112,15 @@ def __init__(self, tz=None):
11031112
"""
11041113
Parameters
11051114
----------
1106-
tz : `datetime.tzinfo`
1115+
tz : str or `~datetime.tzinfo`, default: :rc:`timezone`
11071116
"""
1108-
if tz is None:
1109-
tz = _get_rc_timezone()
1110-
self.tz = tz
1117+
self.tz = _get_tzinfo(tz)
11111118

11121119
def set_tzinfo(self, tz):
11131120
"""
1114-
Set time zone info.
1121+
Set timezone info. str or `~datetime.tzinfo`.
11151122
"""
1116-
self.tz = tz
1123+
self.tz = _get_tzinfo(tz)
11171124

11181125
def datalim_to_dt(self):
11191126
"""Convert axis data interval to datetime objects."""
@@ -1283,7 +1290,7 @@ def __init__(self, tz=None, minticks=5, maxticks=None,
12831290
"""
12841291
Parameters
12851292
----------
1286-
tz : `datetime.tzinfo`
1293+
tz : str or `~datetime.tzinfo`, default: :rc:`timezone`
12871294
Ticks timezone.
12881295
minticks : int
12891296
The minimum number of ticks desired; controls whether ticks occur
@@ -1303,7 +1310,7 @@ def __init__(self, tz=None, minticks=5, maxticks=None,
13031310
the ticks to be at hours 0, 6, 12, 18 when hourly ticking is done
13041311
at 6 hour intervals.
13051312
"""
1306-
super().__init__(tz)
1313+
super().__init__(tz=tz)
13071314
self._freq = YEARLY
13081315
self._freqs = [YEARLY, MONTHLY, DAILY, HOURLY, MINUTELY,
13091316
SECONDLY, MICROSECONDLY]
@@ -1457,7 +1464,7 @@ def get_locator(self, dmin, dmax):
14571464
byhour=byhour, byminute=byminute,
14581465
bysecond=bysecond)
14591466

1460-
locator = RRuleLocator(rrule, self.tz)
1467+
locator = RRuleLocator(rrule, tz=self.tz)
14611468
else:
14621469
locator = MicrosecondLocator(interval, tz=self.tz)
14631470
if date2num(dmin) > 70 * 365 and interval < 1000:
@@ -1490,7 +1497,7 @@ def __init__(self, base=1, month=1, day=1, tz=None):
14901497
"""
14911498
rule = rrulewrapper(YEARLY, interval=base, bymonth=month,
14921499
bymonthday=day, **self.hms0d)
1493-
super().__init__(rule, tz)
1500+
super().__init__(rule, tz=tz)
14941501
self.base = ticker._Edge_integer(base, 0)
14951502

14961503
def _create_rrule(self, vmin, vmax):
@@ -1534,7 +1541,7 @@ def __init__(self, bymonth=None, bymonthday=1, interval=1, tz=None):
15341541

15351542
rule = rrulewrapper(MONTHLY, bymonth=bymonth, bymonthday=bymonthday,
15361543
interval=interval, **self.hms0d)
1537-
super().__init__(rule, tz)
1544+
super().__init__(rule, tz=tz)
15381545

15391546

15401547
class WeekdayLocator(RRuleLocator):
@@ -1562,7 +1569,7 @@ def __init__(self, byweekday=1, interval=1, tz=None):
15621569

15631570
rule = rrulewrapper(DAILY, byweekday=byweekday,
15641571
interval=interval, **self.hms0d)
1565-
super().__init__(rule, tz)
1572+
super().__init__(rule, tz=tz)
15661573

15671574

15681575
class DayLocator(RRuleLocator):
@@ -1588,7 +1595,7 @@ def __init__(self, bymonthday=None, interval=1, tz=None):
15881595

15891596
rule = rrulewrapper(DAILY, bymonthday=bymonthday,
15901597
interval=interval, **self.hms0d)
1591-
super().__init__(rule, tz)
1598+
super().__init__(rule, tz=tz)
15921599

15931600

15941601
class HourLocator(RRuleLocator):
@@ -1608,7 +1615,7 @@ def __init__(self, byhour=None, interval=1, tz=None):
16081615

16091616
rule = rrulewrapper(HOURLY, byhour=byhour, interval=interval,
16101617
byminute=0, bysecond=0)
1611-
super().__init__(rule, tz)
1618+
super().__init__(rule, tz=tz)
16121619

16131620

16141621
class MinuteLocator(RRuleLocator):
@@ -1628,7 +1635,7 @@ def __init__(self, byminute=None, interval=1, tz=None):
16281635

16291636
rule = rrulewrapper(MINUTELY, byminute=byminute, interval=interval,
16301637
bysecond=0)
1631-
super().__init__(rule, tz)
1638+
super().__init__(rule, tz=tz)
16321639

16331640

16341641
class SecondLocator(RRuleLocator):
@@ -1648,7 +1655,7 @@ def __init__(self, bysecond=None, interval=1, tz=None):
16481655
bysecond = range(60)
16491656

16501657
rule = rrulewrapper(SECONDLY, bysecond=bysecond, interval=interval)
1651-
super().__init__(rule, tz)
1658+
super().__init__(rule, tz=tz)
16521659

16531660

16541661
class MicrosecondLocator(DateLocator):

0 commit comments

Comments
 (0)