@@ -5,7 +5,7 @@ Time and time zones
55
66Dealing with time and time zones can be a frustrating experience in any
77programming language and for any application. pvlib-python relies on
8- :py:mod: `pandas ` and ` pytz < http://pythonhosted.org/pytz/ >`_ to handle
8+ :py:mod: `pandas ` and the builtin :py:mod: ` python:zoneinfo ` to handle
99time and time zones. Therefore, the vast majority of the information in
1010this document applies to any time series analysis using pandas and is
1111not specific to pvlib-python.
@@ -14,52 +14,53 @@ General functionality
1414---------------------
1515
1616pvlib makes extensive use of pandas due to its excellent time series
17- functionality. Take the time to become familiar with pandas' `Time
18- Series / Date functionality page
19- <http://pandas.pydata.org/pandas-docs/version/0.18.0/timeseries.html> `_.
17+ functionality. Take the time to become familiar with pandas'
18+ :external+pandas:doc: `Time Series / Date functionality page <user_guide/timeseries >`.
2019It is also worthwhile to become familiar with pure Python's
21- :py:mod: `python:datetime ` module, although we usually recommend
22- using the corresponding pandas functionality where possible.
20+ :py:mod: `python:datetime ` module, although we usually recommend using the
21+ corresponding pandas functionality where possible.
2322
2423First, we'll import the libraries that we'll use to explore the basic
2524time and time zone functionality in python and pvlib.
2625
2726.. ipython :: python
2827
2928 import datetime
29+ import zoneinfo
3030 import pandas as pd
31- import pytz
3231
3332
3433 Finding a time zone
3534*******************
3635
37- pytz is based on the Olson time zone database. You can obtain a list of
38- all valid time zone strings with ``pytz.all_timezones ``. It's a long
39- list, so we only print every 20th time zone.
36+ ``zoneinfo `` is based on the IANA (Olson) time zone database. You can obtain
37+ a set of all valid time zone strings with ``zoneinfo.available_timezones() ``.
38+ It's a large set, so we only print every 20th time zone (sorted for
39+ consistency).
4040
4141.. ipython :: python
4242
43- len (pytz.all_timezones )
44- pytz.all_timezones [::20 ]
43+ len (zoneinfo.available_timezones() )
44+ sorted (zoneinfo.available_timezones()) [::20 ]
4545
4646 Wikipedia's `List of tz database time zones
4747<https://en.wikipedia.org/wiki/List_of_tz_database_time_zones> `_ is also
4848good reference.
4949
50- The ``pytz.country_timezones `` function is useful, too.
50+ You can filter the available time zones using Python's built-in
51+ :py:func: `python:filter ` function.
5152
5253.. ipython :: python
5354
54- pytz.country_timezones( ' US ' )
55+ sorted ( filter ( lambda x : ' America ' in x, zoneinfo.available_timezones()) )
5556
56- And don't forget about Python's :py:func: ` python: filter` function.
57+ And you can also filter for GMT-based fixed offset zones:
5758
5859.. ipython :: python
5960
60- list (filter (lambda x : ' GMT' in x, pytz.all_timezones ))
61+ sorted (filter (lambda x : ' GMT' in x, zoneinfo.available_timezones() ))
6162
62- Note that while pytz has ``'EST' `` and ``'MST' ``, it does not have
63+ Note that while the IANA database has ``'EST' `` and ``'MST' ``, it does not have
6364``'PST' ``. Use ``'Etc/GMT+8' `` instead, or see :ref: `fixedoffsets `.
6465
6566Timestamps
@@ -125,7 +126,7 @@ vs. the UTC offset in summer...
125126 pd.Timestamp(' 2015-6-1 00:00' ).tz_localize(' US/Mountain' )
126127 pd.Timestamp(' 2015-6-1 00:00' ).tz_localize(' Etc/GMT+7' )
127128
128- pandas and pytz make this time zone handling possible because pandas
129+ pandas makes this time zone handling possible because pandas
129130stores all times as integer nanoseconds since January 1, 1970.
130131Here is the pandas time representation of the integers 1 and 1e9.
131132
@@ -174,12 +175,13 @@ specifications, but watch out for the counter-intuitive sign convention.
174175
175176 pd.Timestamp(' 2015-1-1 00:00' , tz = ' Etc/GMT-2' )
176177
177- Fixed offset time zones can also be specified as offset minutes
178- from UTC using ``pytz.FixedOffset ``.
178+ Fixed offset time zones can also be specified using
179+ :py:class: `python:datetime.timezone ` with a
180+ :py:class: `python:datetime.timedelta ` offset.
179181
180182.. ipython :: python
181183
182- pd.Timestamp(' 2015-1-1 00:00' , tz = pytz.FixedOffset( 120 ))
184+ pd.Timestamp(' 2015-1-1 00:00' , tz = datetime.timezone(datetime.timedelta( hours = 2 ) ))
183185
184186 You can also specify the fixed offset directly in the ``tz_localize ``
185187method, however, be aware that this is not documented and that the
@@ -216,8 +218,8 @@ expected.
216218 # tz naive pandas Timestamp object
217219 pd.Timestamp(naive_python_dt)
218220
219- # tz aware python datetime.datetime object
220- aware_python_dt = pytz.timezone( ' US/Mountain' ).localize(naive_python_dt )
221+ # tz aware python datetime.datetime object using zoneinfo
222+ aware_python_dt = naive_python_dt.replace( tzinfo = zoneinfo.ZoneInfo( ' US/Mountain' ))
221223
222224 # tz aware pandas Timestamp object
223225 pd.Timestamp(aware_python_dt)
@@ -234,13 +236,14 @@ passed to ``Timestamp``.
234236 # tz naive pandas Timestamp object (time=midnight)
235237 pd.Timestamp(naive_python_date)
236238
237- You cannot localize a native Python date object.
239+ You cannot localize a native Python date object directly; you must first
240+ convert it to a :py:class: `python:datetime.datetime `.
238241
239242.. ipython :: python
240243 :okexcept:
241244
242- # fail
243- pytz.timezone( ' US/Mountain' ).localize(naive_python_date )
245+ # fail: datetime.date has no tzinfo support via replace
246+ naive_python_date.replace( tzinfo = zoneinfo.ZoneInfo( ' US/Mountain' ))
244247
245248
246249 pvlib-specific functionality
@@ -348,7 +351,7 @@ UTC, and then convert it to the desired time zone.
348351
349352.. ipython :: python
350353
351- fixed_tz = pytz.FixedOffset( tmy3_metadata[' TZ' ] * 60 )
354+ fixed_tz = datetime.timezone(datetime.timedelta( hours = tmy3_metadata[' TZ' ]) )
352355 solar_position_hack = solar_position_notz.tz_localize(' UTC' ).tz_convert(fixed_tz)
353356
354357 solar_position_hack.index
0 commit comments