@@ -30,15 +30,40 @@ time and time zone functionality in python and pvlib.
3030 import pandas as pd
3131 import pytz
3232
33- You can obtain a list of all valid time zone strings with
34- ``pytz.all_timezones ``. It's a long list, so we only print every 20th
35- time zone.
33+ Finding a time zone
34+ *******************
35+
36+ pytz is based on the Olson time zone database. You can obtain a list of
37+ all valid time zone strings with ``pytz.all_timezones ``. It's a long
38+ list, so we only print every 20th time zone.
3639
3740.. ipython :: python
3841
3942 len (pytz.all_timezones)
4043 pytz.all_timezones[::20 ]
4144
45+ Wikipedia's `List of tz database time zones
46+ <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones> `_ is also
47+ good reference.
48+
49+ The ``pytz.country_timezones `` function is useful, too.
50+
51+ .. ipython :: python
52+
53+ pytz.country_timezones(' US' )
54+
55+ And don't forget about Python's :py:func: `python:filter ` function.
56+
57+ .. ipython :: python
58+
59+ list (filter (lambda x : ' GMT' in x, pytz.all_timezones))
60+
61+ Note that while pytz has ``'EST' `` and ``'MST' ``, it does not have
62+ ``'PST' ``. Use ``'Etc/GMT+8' `` instead, or see :ref: `fixedoffsets `.
63+
64+ Timestamps
65+ **********
66+
4267:py:class: `pandas.Timestamp ` and :py:class: `pandas.DatetimeIndex `
4368can be created in many ways. Here we focus on the time zone issues
4469surrounding them; see the pandas documentation for more information.
@@ -57,11 +82,11 @@ You can specify the time zone using the ``tz`` keyword argument or the
5782 pd.Timestamp(' 2015-1-1 00:00' , tz = ' America/Denver' )
5883 pd.Timestamp(' 2015-1-1 00:00' ).tz_localize(' America/Denver' )
5984
60- Localized `` Timestamps `` can be converted from one time zone to another.
85+ Localized Timestamps can be converted from one time zone to another.
6186
6287.. ipython :: python
6388
64- midnight_mst = pd.Timestamp(' 2015-1-1 00:00' , tz = ' MST ' )
89+ midnight_mst = pd.Timestamp(' 2015-1-1 00:00' , tz = ' America/Denver ' )
6590 corresponding_utc = midnight_mst.tz_convert(' UTC' ) # returns a new Timestamp
6691 corresponding_utc
6792
@@ -78,6 +103,9 @@ The difference between ``tz_localize`` and ``tz_convert`` is a common
78103source of confusion for new users. Just remember: localize first,
79104convert later.
80105
106+ Daylight savings time
107+ *********************
108+
81109Some time zones are aware of daylight savings time and some are not. For
82110example the winter time results are the same for US/Mountain and MST,
83111but the summer time results are not.
@@ -87,57 +115,78 @@ Note the UTC offset in winter...
87115.. ipython :: python
88116
89117 pd.Timestamp(' 2015-1-1 00:00' ).tz_localize(' US/Mountain' )
90- pd.Timestamp(' 2015-1-1 00:00' ).tz_localize(' MST ' )
118+ pd.Timestamp(' 2015-1-1 00:00' ).tz_localize(' Etc/GMT+7 ' )
91119
92120 vs. the UTC offset in summer...
93121
94122.. ipython :: python
95123
96124 pd.Timestamp(' 2015-6-1 00:00' ).tz_localize(' US/Mountain' )
97- pd.Timestamp(' 2015-6-1 00:00' ).tz_localize(' MST ' )
125+ pd.Timestamp(' 2015-6-1 00:00' ).tz_localize(' Etc/GMT+7 ' )
98126
99127 pandas and pytz make this time zone handling possible because pandas
100128stores all times as integer nanoseconds since January 1, 1970.
101- Here is the pandas time representation of the integer 1 .
129+ Here is the pandas time representation of the integers 1 and 1e9 .
102130
103131.. ipython :: python
104132
105133 pd.Timestamp(1 )
134+ pd.Timestamp(1e9 )
106135
107136 So if we specify times consistent with the specified time zone, pandas
108137will use the same integer to represent them.
109138
110139.. ipython :: python
111140
112141 # US/Mountain
113- pd.Timestamp(' 2015-6-1 01:00' ).tz_localize( ' US/Mountain' ).value
142+ pd.Timestamp(' 2015-6-1 01:00' , tz = ' US/Mountain' ).value
114143
115144 # MST
116- pd.Timestamp(' 2015-6-1 00:00' ).tz_localize(' MST' ).value
145+ pd.Timestamp(' 2015-6-1 00:00' , tz = ' Etc/GMT+7' ).value
146+
147+ # Europe/Berlin
148+ pd.Timestamp(' 2015-6-1 09:00' , tz = ' Europe/Berlin' ).value
117149
118150 # UTC
119- pd.Timestamp(' 2015-6-1 07:00' ).tz_localize( ' UTC' ).value
151+ pd.Timestamp(' 2015-6-1 07:00' , tz = ' UTC' ).value
120152
121153 # UTC
122154 pd.Timestamp(' 2015-6-1 07:00' ).value
123155
156+ It's ultimately these integers that are used when calculating quantities
157+ in pvlib such as solar position.
158+
124159As stated above, pandas will assume UTC if you do not specify a time
125160zone. This is dangerous, and we recommend using localized timeseries,
126161even if it is UTC.
127162
128- Timezones can also be specified with a fixed offset in minutes from UTC.
163+
164+ .. _fixedoffsets :
165+
166+ Fixed offsets
167+ *************
168+
169+ The ``'Etc/GMT*' `` time zones mentioned above provide fixed offset
170+ specifications, but watch out for the counter-intuitive sign convention.
171+
172+ .. ipython :: python
173+
174+ pd.Timestamp(' 2015-1-1 00:00' , tz = ' Etc/GMT-2' )
175+
176+ Fixed offset time zones can also be specified as offset minutes
177+ from UTC using ``pytz.FixedOffset ``.
129178
130179.. ipython :: python
131180
132- pd.Timestamp(' 2015-1-1 00:00' ).tz_localize( pytz.FixedOffset(120 ))
181+ pd.Timestamp(' 2015-1-1 00:00' , tz = pytz.FixedOffset(120 ))
133182
134- You can also specify the fixed offset directly in the tz_localize
183+ You can also specify the fixed offset directly in the `` tz_localize ``
135184method, however, be aware that this is not documented and that the
136185offset must be in seconds, not minutes.
137186
138187.. ipython :: python
139188
140- pd.Timestamp(' 2015-1-1 00:00' ).tz_localize( 7200 )
189+ pd.Timestamp(' 2015-1-1 00:00' , tz = 7200 )
141190
142191 Yet another way to specify a time zone with a fixed offset is by using
143192the string formulation.
@@ -146,9 +195,17 @@ the string formulation.
146195
147196 pd.Timestamp(' 2015-1-1 00:00+0200' )
148197
149- pandas Timestamp objects can also be created from time zone aware or
150- naive :py:class: `python:datetime.datetime ` objects.
151- The behavior is as expected.
198+
199+ Native Python objects
200+ *********************
201+
202+ Sometimes it's convenient to use native Python
203+ :py:class: `python:datetime.date ` and
204+ :py:class: `python:datetime.datetime ` objects, so we demonstrate their
205+ use next. pandas Timestamp objects can also be created from time zone
206+ aware or naive
207+ :py:class: `python:datetime.datetime ` objects. The behavior is as
208+ expected.
152209
153210.. ipython :: python
154211
@@ -170,13 +227,13 @@ passed to ``Timestamp``.
170227
171228.. ipython :: python
172229
173- # tz naive python datetime.date object
230+ # tz naive python datetime.date object (no time info)
174231 naive_python_date = datetime.date(2015 , 6 , 1 )
175232
176- # tz naive pandas Timestamp object
233+ # tz naive pandas Timestamp object (time=midnight)
177234 pd.Timestamp(naive_python_date)
178235
179- You cannot localize a pure Python date object.
236+ You cannot localize a native Python date object.
180237
181238.. ipython :: python
182239 :okexcept:
@@ -200,7 +257,10 @@ most common places to get tripped up with time and time zone issues in
200257solar power analysis occur during data import and solar position
201258calculations.
202259
203- Let's first examine how pvlib handles time when it imports a tmy3 file.
260+ Data import
261+ ***********
262+
263+ Let's first examine how pvlib handles time when it imports a TMY3 file.
204264
205265.. ipython :: python
206266
@@ -231,6 +291,9 @@ print just a few of the rows and columns of the large dataframe.
231291 The :py:func: `~pvlib.tmy.readtmy2 ` function also returns a DataFrame
232292with a localized DatetimeIndex.
233293
294+ Solar position
295+ **************
296+
234297The correct solar position can be immediately calculated from the
235298DataFrame's index since the index has been localized.
236299
@@ -262,6 +325,9 @@ on January 1, 1997 at Sand Point, Alaska, sunrise was at 10:09 am, solar
262325noon was at 1:46 pm, and sunset was at 5:23 pm. This is consistent with
263326the data plotted above (and depressing).
264327
328+ Solar position (assumed UTC)
329+ ****************************
330+
265331What if we had a DatetimeIndex that was not localized, such as the one
266332below? The solar position calculator will assume UTC time.
267333
@@ -286,6 +352,9 @@ below? The solar position calculator will assume UTC time.
286352
287353 This looks like the plot above, but shifted by 9 hours.
288354
355+ Solar position (calculate and convert)
356+ **************************************
357+
289358In principle, one could localize the tz-naive solar position data to
290359UTC, and then convert it to the desired time zone.
291360
0 commit comments