11"""
22Matplotlib 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
55By default, Matplotlib uses the units machinery described in
66`~matplotlib.units` to convert `datetime.datetime`, and `numpy.datetime64`
8383 Out[1]: 732401
8484
8585All 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
9192A wide range of specific and general purpose date tick locators and
9293formatters are provided in this module. See
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
202203UTC = 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' ))
@@ -395,7 +407,9 @@ def datestr2num(d, default=None):
395407 return date2num (dt )
396408 else :
397409 if default is not None :
398- d = [dateutil .parser .parse (s , default = default ) for s in d ]
410+ d = [date2num (dateutil .parser .parse (s , default = default ))
411+ for s in d ]
412+ return np .asarray (d )
399413 d = np .asarray (d )
400414 if not d .size :
401415 return d
@@ -506,8 +520,8 @@ def num2date(x, tz=None):
506520 Number of days (fraction part represents hours, minutes, seconds)
507521 since the epoch. See `.get_epoch` for the
508522 epoch, which can be changed by :rc:`date.epoch` or `.set_epoch`.
509- tz : str, default: :rc:`timezone`
510- 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`.
511525
512526 Returns
513527 -------
@@ -523,8 +537,7 @@ def num2date(x, tz=None):
523537 Gregorian calendar is assumed; this is not universal practice.
524538 For details, see the module docstring.
525539 """
526- if tz is None :
527- tz = _get_rc_timezone ()
540+ tz = _get_tzinfo (tz )
528541 return _from_ordinalf_np_vectorized (x , tz ).tolist ()
529542
530543
@@ -619,16 +632,14 @@ def __init__(self, fmt, tz=None, *, usetex=None):
619632 ----------
620633 fmt : str
621634 `~datetime.datetime.strftime` format string
622- tz : ` datetime.tzinfo`, default: :rc:`timezone`
635+ tz : str or `~ datetime.tzinfo`, default: :rc:`timezone`
623636 Ticks timezone.
624637 usetex : bool, default: :rc:`text.usetex`
625638 To enable/disable the use of TeX's math mode for rendering the
626639 results of the formatter.
627640 """
628- if tz is None :
629- tz = _get_rc_timezone ()
641+ self .tz = _get_tzinfo (tz )
630642 self .fmt = fmt
631- self .tz = tz
632643 self ._usetex = (usetex if usetex is not None else
633644 mpl .rcParams ['text.usetex' ])
634645
@@ -637,7 +648,7 @@ def __call__(self, x, pos=0):
637648 return _wrap_in_tex (result ) if self ._usetex else result
638649
639650 def set_tzinfo (self , tz ):
640- self .tz = tz
651+ self .tz = _get_tzinfo ( tz )
641652
642653
643654class ConciseDateFormatter (ticker .Formatter ):
@@ -654,8 +665,8 @@ class ConciseDateFormatter(ticker.Formatter):
654665 locator : `.ticker.Locator`
655666 Locator that this axis is using.
656667
657- tz : str, optional
658- Passed to `.dates.date2num `.
668+ tz : str or `~datetime.tzinfo`, default: :rc:`timezone`
669+ Passed to `.dates.num2date `.
659670
660671 formats : list of 6 strings, optional
661672 Format strings for 6 levels of tick labelling: mostly years,
@@ -755,7 +766,7 @@ def __init__(self, locator, tz=None, formats=None, offset_formats=None,
755766
756767 if offset_formats :
757768 if len (offset_formats ) != 6 :
758- raise ValueError ('offsetfmts argument must be a list of '
769+ raise ValueError ('offset_formats argument must be a list of '
759770 '6 format strings (or None)' )
760771 self .offset_formats = offset_formats
761772 else :
@@ -925,8 +936,8 @@ def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d', *,
925936 locator : `.ticker.Locator`
926937 Locator that this axis is using.
927938
928- tz : str, optional
929- Passed to `.dates.date2num `.
939+ tz : str or `~datetime.tzinfo` , optional
940+ Passed to `.dates.num2date `.
930941
931942 defaultfmt : str
932943 The default format to use if none of the values in ``self.scaled``
@@ -998,7 +1009,7 @@ def set(self, **kwargs):
9981009 def _update_rrule (self , ** kwargs ):
9991010 tzinfo = self ._base_tzinfo
10001011
1001- # rrule does not play nicely with time zones - especially pytz time
1012+ # rrule does not play nicely with timezones - especially pytz time
10021013 # zones, it's best to use naive zones and attach timezones once the
10031014 # datetimes are returned
10041015 if 'dtstart' in kwargs :
@@ -1101,17 +1112,15 @@ def __init__(self, tz=None):
11011112 """
11021113 Parameters
11031114 ----------
1104- tz : ` datetime.tzinfo`
1115+ tz : str or `~ datetime.tzinfo`, default: :rc:`timezone `
11051116 """
1106- if tz is None :
1107- tz = _get_rc_timezone ()
1108- self .tz = tz
1117+ self .tz = _get_tzinfo (tz )
11091118
11101119 def set_tzinfo (self , tz ):
11111120 """
1112- Set time zone info.
1121+ Set timezone info. str or `~datetime.tzinfo` .
11131122 """
1114- self .tz = tz
1123+ self .tz = _get_tzinfo ( tz )
11151124
11161125 def datalim_to_dt (self ):
11171126 """Convert axis data interval to datetime objects."""
@@ -1281,7 +1290,7 @@ def __init__(self, tz=None, minticks=5, maxticks=None,
12811290 """
12821291 Parameters
12831292 ----------
1284- tz : ` datetime.tzinfo`
1293+ tz : str or `~ datetime.tzinfo`, default: :rc:`timezone `
12851294 Ticks timezone.
12861295 minticks : int
12871296 The minimum number of ticks desired; controls whether ticks occur
@@ -1301,7 +1310,7 @@ def __init__(self, tz=None, minticks=5, maxticks=None,
13011310 the ticks to be at hours 0, 6, 12, 18 when hourly ticking is done
13021311 at 6 hour intervals.
13031312 """
1304- super ().__init__ (tz )
1313+ super ().__init__ (tz = tz )
13051314 self ._freq = YEARLY
13061315 self ._freqs = [YEARLY , MONTHLY , DAILY , HOURLY , MINUTELY ,
13071316 SECONDLY , MICROSECONDLY ]
@@ -1455,7 +1464,7 @@ def get_locator(self, dmin, dmax):
14551464 byhour = byhour , byminute = byminute ,
14561465 bysecond = bysecond )
14571466
1458- locator = RRuleLocator (rrule , self .tz )
1467+ locator = RRuleLocator (rrule , tz = self .tz )
14591468 else :
14601469 locator = MicrosecondLocator (interval , tz = self .tz )
14611470 if date2num (dmin ) > 70 * 365 and interval < 1000 :
@@ -1488,7 +1497,7 @@ def __init__(self, base=1, month=1, day=1, tz=None):
14881497 """
14891498 rule = rrulewrapper (YEARLY , interval = base , bymonth = month ,
14901499 bymonthday = day , ** self .hms0d )
1491- super ().__init__ (rule , tz )
1500+ super ().__init__ (rule , tz = tz )
14921501 self .base = ticker ._Edge_integer (base , 0 )
14931502
14941503 def _create_rrule (self , vmin , vmax ):
@@ -1532,7 +1541,7 @@ def __init__(self, bymonth=None, bymonthday=1, interval=1, tz=None):
15321541
15331542 rule = rrulewrapper (MONTHLY , bymonth = bymonth , bymonthday = bymonthday ,
15341543 interval = interval , ** self .hms0d )
1535- super ().__init__ (rule , tz )
1544+ super ().__init__ (rule , tz = tz )
15361545
15371546
15381547class WeekdayLocator (RRuleLocator ):
@@ -1560,7 +1569,7 @@ def __init__(self, byweekday=1, interval=1, tz=None):
15601569
15611570 rule = rrulewrapper (DAILY , byweekday = byweekday ,
15621571 interval = interval , ** self .hms0d )
1563- super ().__init__ (rule , tz )
1572+ super ().__init__ (rule , tz = tz )
15641573
15651574
15661575class DayLocator (RRuleLocator ):
@@ -1586,7 +1595,7 @@ def __init__(self, bymonthday=None, interval=1, tz=None):
15861595
15871596 rule = rrulewrapper (DAILY , bymonthday = bymonthday ,
15881597 interval = interval , ** self .hms0d )
1589- super ().__init__ (rule , tz )
1598+ super ().__init__ (rule , tz = tz )
15901599
15911600
15921601class HourLocator (RRuleLocator ):
@@ -1606,7 +1615,7 @@ def __init__(self, byhour=None, interval=1, tz=None):
16061615
16071616 rule = rrulewrapper (HOURLY , byhour = byhour , interval = interval ,
16081617 byminute = 0 , bysecond = 0 )
1609- super ().__init__ (rule , tz )
1618+ super ().__init__ (rule , tz = tz )
16101619
16111620
16121621class MinuteLocator (RRuleLocator ):
@@ -1626,7 +1635,7 @@ def __init__(self, byminute=None, interval=1, tz=None):
16261635
16271636 rule = rrulewrapper (MINUTELY , byminute = byminute , interval = interval ,
16281637 bysecond = 0 )
1629- super ().__init__ (rule , tz )
1638+ super ().__init__ (rule , tz = tz )
16301639
16311640
16321641class SecondLocator (RRuleLocator ):
@@ -1646,7 +1655,7 @@ def __init__(self, bysecond=None, interval=1, tz=None):
16461655 bysecond = range (60 )
16471656
16481657 rule = rrulewrapper (SECONDLY , bysecond = bysecond , interval = interval )
1649- super ().__init__ (rule , tz )
1658+ super ().__init__ (rule , tz = tz )
16501659
16511660
16521661class MicrosecondLocator (DateLocator ):
0 commit comments