Skip to content

Commit 4856552

Browse files
committed
fix first and last hour issue are 1AM and midnite
* elaborate on warning regarding definition of TMY and possibly unexpected behavior when coercing the year * add more comments * use mod instead of subtracting hour to change midnite from 24 to zero * shift all midnite rows one day forward * check for leapday (2/29) and shift to March 1st * add copious comments and a note that if pandas is updated to 0.24 then we can use the `array` property to detect leapday * add test to confirm that TMY3 1st hour is 1AM and last hour is midnite
1 parent dc72d34 commit 4856552

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

pvlib/iotools/tmy.py

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import io
77
import re
88
from urllib.request import urlopen, Request
9+
import numpy as np
910
import pandas as pd
1011

1112

@@ -139,8 +140,15 @@ def read_tmy3(filename=None, coerce_year=None, recolumn=True):
139140
TMYData.PresWthUncertainty Present weather code uncertainty, see [2]_.
140141
============================= ======================================================================================================================================================
141142
142-
.. warning:: when coercing the year, the last index in the dataframe will
143-
actually be the first hour of the year
143+
.. warning:: TMY3 irradiance data corresponds to the previous hour, so the
144+
first hour is 1AM, corresponding to the net irradiance from midnite to
145+
1AM, and the last hour is midnite of the *next* year, unless the year
146+
has been coerced. EG: if TMY3 was 1988-12-31 24:00:00 this becomes
147+
1989-01-01 00:00:00
148+
149+
.. warning:: When coercing the year, the last index in the dataframe will
150+
be the first hour of the same year, EG: if TMY3 was 1988-12-31 24:00:00
151+
and year is coerced to 1990 this becomes 1990-01-01
144152
145153
References
146154
----------
@@ -191,9 +199,22 @@ def read_tmy3(filename=None, coerce_year=None, recolumn=True):
191199
# header is actually the second line in file, but tell pandas to look for
192200
# header information on the 1st line (0 indexing) because we've already
193201
# advanced past the true first line with the readline call above.
194-
data = pd.read_csv(csvdata, header=0, index_col='Date (MM/DD/YYYY)')
195-
data.index = pd.to_datetime(data.index, format='%m/%d/%Y')
196-
shifted_hour = data['Time (HH:MM)'].str[:2].astype(int) - 1
202+
data = pd.read_csv(csvdata, header=0)
203+
# get the date column as a pd.Series of numpy datetime64
204+
data_ymd = pd.to_datetime(data['Date (MM/DD/YYYY)'], format='%m/%d/%Y')
205+
# shift the time column so that midnite is 00:00 instead of 24:00
206+
shifted_hour = data['Time (HH:MM)'].str[:2].astype(int) % 24
207+
# shift the dates at midnite so they correspond to the next day
208+
data_ymd[shifted_hour == 0] += datetime.timedelta(days=1)
209+
# NOTE: as of pandas>=0.24 the pd.Series.array has a month attribute, but
210+
# in pandas-0.18.1, only DatetimeIndex has month, but indices are immutable
211+
# so we need to continue to work with the panda series of dates `data_ymd`
212+
data_index = pd.DatetimeIndex(data_ymd)
213+
# use indices to check for a leap day and advance it to March 1st
214+
leapday = (data_index.month == 2) & (data_index.day == 29)
215+
data_ymd[leapday] += datetime.timedelta(days=1)
216+
# is this necessary? convert the series to DatetimeIndex
217+
data.index = pd.DatetimeIndex(data_ymd)
197218
# shifted_hour is a pd.Series, so use pd.to_timedelta to get a pd.Series of
198219
# timedeltas
199220
# NOTE: as of pvlib-0.6.3, min req is pandas-0.18.1, so pd.to_timedelta

pvlib/tests/iotools/test_tmy.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,7 @@ def test_gh865_read_tmy3_feb_leapyear_hr24():
6969
assert all(data.index.year == 1990)
7070
# let's do a quick sanity check, are the indices monotonically increasing?
7171
assert all(np.diff(data.index[:-1].astype(int)) == 3600000000000)
72+
# according to the TMY3 manual, each record corresponds to the previous
73+
# hour so check that the 1st hour is 1AM and the last hour is midnite
74+
assert data.index[0].hour == 1
75+
assert data.index[-1].hour == 0

0 commit comments

Comments
 (0)