@@ -30,15 +30,40 @@ time and time zone functionality in python and pvlib.
30
30
import pandas as pd
31
31
import pytz
32
32
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.
36
39
37
40
.. ipython :: python
38
41
39
42
len (pytz.all_timezones)
40
43
pytz.all_timezones[::20 ]
41
44
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
+
42
67
:py:class: `pandas.Timestamp ` and :py:class: `pandas.DatetimeIndex `
43
68
can be created in many ways. Here we focus on the time zone issues
44
69
surrounding 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
57
82
pd.Timestamp(' 2015-1-1 00:00' , tz = ' America/Denver' )
58
83
pd.Timestamp(' 2015-1-1 00:00' ).tz_localize(' America/Denver' )
59
84
60
- Localized `` Timestamps `` can be converted from one time zone to another.
85
+ Localized Timestamps can be converted from one time zone to another.
61
86
62
87
.. ipython :: python
63
88
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 ' )
65
90
corresponding_utc = midnight_mst.tz_convert(' UTC' ) # returns a new Timestamp
66
91
corresponding_utc
67
92
@@ -78,6 +103,9 @@ The difference between ``tz_localize`` and ``tz_convert`` is a common
78
103
source of confusion for new users. Just remember: localize first,
79
104
convert later.
80
105
106
+ Daylight savings time
107
+ *********************
108
+
81
109
Some time zones are aware of daylight savings time and some are not. For
82
110
example the winter time results are the same for US/Mountain and MST,
83
111
but the summer time results are not.
@@ -87,57 +115,78 @@ Note the UTC offset in winter...
87
115
.. ipython :: python
88
116
89
117
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 ' )
91
119
92
120
vs. the UTC offset in summer...
93
121
94
122
.. ipython :: python
95
123
96
124
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 ' )
98
126
99
127
pandas and pytz make this time zone handling possible because pandas
100
128
stores 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 .
102
130
103
131
.. ipython :: python
104
132
105
133
pd.Timestamp(1 )
134
+ pd.Timestamp(1e9 )
106
135
107
136
So if we specify times consistent with the specified time zone, pandas
108
137
will use the same integer to represent them.
109
138
110
139
.. ipython :: python
111
140
112
141
# 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
114
143
115
144
# 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
117
149
118
150
# UTC
119
- pd.Timestamp(' 2015-6-1 07:00' ).tz_localize( ' UTC' ).value
151
+ pd.Timestamp(' 2015-6-1 07:00' , tz = ' UTC' ).value
120
152
121
153
# UTC
122
154
pd.Timestamp(' 2015-6-1 07:00' ).value
123
155
156
+ It's ultimately these integers that are used when calculating quantities
157
+ in pvlib such as solar position.
158
+
124
159
As stated above, pandas will assume UTC if you do not specify a time
125
160
zone. This is dangerous, and we recommend using localized timeseries,
126
161
even if it is UTC.
127
162
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 ``.
129
178
130
179
.. ipython :: python
131
180
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 ))
133
182
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 ``
135
184
method, however, be aware that this is not documented and that the
136
185
offset must be in seconds, not minutes.
137
186
138
187
.. ipython :: python
139
188
140
- pd.Timestamp(' 2015-1-1 00:00' ).tz_localize( 7200 )
189
+ pd.Timestamp(' 2015-1-1 00:00' , tz = 7200 )
141
190
142
191
Yet another way to specify a time zone with a fixed offset is by using
143
192
the string formulation.
@@ -146,9 +195,17 @@ the string formulation.
146
195
147
196
pd.Timestamp(' 2015-1-1 00:00+0200' )
148
197
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.
152
209
153
210
.. ipython :: python
154
211
@@ -170,13 +227,13 @@ passed to ``Timestamp``.
170
227
171
228
.. ipython :: python
172
229
173
- # tz naive python datetime.date object
230
+ # tz naive python datetime.date object (no time info)
174
231
naive_python_date = datetime.date(2015 , 6 , 1 )
175
232
176
- # tz naive pandas Timestamp object
233
+ # tz naive pandas Timestamp object (time=midnight)
177
234
pd.Timestamp(naive_python_date)
178
235
179
- You cannot localize a pure Python date object.
236
+ You cannot localize a native Python date object.
180
237
181
238
.. ipython :: python
182
239
:okexcept:
@@ -200,7 +257,10 @@ most common places to get tripped up with time and time zone issues in
200
257
solar power analysis occur during data import and solar position
201
258
calculations.
202
259
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.
204
264
205
265
.. ipython :: python
206
266
@@ -231,6 +291,9 @@ print just a few of the rows and columns of the large dataframe.
231
291
The :py:func: `~pvlib.tmy.readtmy2 ` function also returns a DataFrame
232
292
with a localized DatetimeIndex.
233
293
294
+ Solar position
295
+ **************
296
+
234
297
The correct solar position can be immediately calculated from the
235
298
DataFrame's index since the index has been localized.
236
299
@@ -262,6 +325,9 @@ on January 1, 1997 at Sand Point, Alaska, sunrise was at 10:09 am, solar
262
325
noon was at 1:46 pm, and sunset was at 5:23 pm. This is consistent with
263
326
the data plotted above (and depressing).
264
327
328
+ Solar position (assumed UTC)
329
+ ****************************
330
+
265
331
What if we had a DatetimeIndex that was not localized, such as the one
266
332
below? The solar position calculator will assume UTC time.
267
333
@@ -286,6 +352,9 @@ below? The solar position calculator will assume UTC time.
286
352
287
353
This looks like the plot above, but shifted by 9 hours.
288
354
355
+ Solar position (calculate and convert)
356
+ **************************************
357
+
289
358
In principle, one could localize the tz-naive solar position data to
290
359
UTC, and then convert it to the desired time zone.
291
360
0 commit comments