pvlib / pvlib-python

A set of documented functions for simulating the performance of photovoltaic energy systems.
https://pvlib-python.readthedocs.io
BSD 3-Clause "New" or "Revised" License
1.16k stars 979 forks source link

`NonExistentTimeError` when calling `hour_angle` #2132

Open scttnlsn opened 1 month ago

scttnlsn commented 1 month ago

Describe the bug

Cannot compute hour_angle in timezones and on a day where a daylight savings transition happens at midnight.

To Reproduce

from datetime import datetime, timedelta
import pytz
import pandas as pd
import pvlib

date = datetime(2014, 9, 7, 0, 0, 0, tzinfo=pytz.UTC)
times = pd.DatetimeIndex(
    [date + timedelta(hours=hour) for hour in range(24)]
).tz_convert("America/Santiago")

day_of_year = date.timetuple().tm_yday

equation_of_time = pvlib.solarposition.equation_of_time_spencer71(day_of_year)
declination = pvlib.solarposition.declination_spencer71(day_of_year)
hour_angle = pvlib.solarposition.hour_angle(
    times, 70.6693, equation_of_time
)

The call to times.normalize() inside hour_angle raises an exception:

pytz.exceptions.NonExistentTimeError: 2014-09-07 00:00:00

Expected behavior

I'm not entirely sure. Pandas' tz_localize includes arguments for handling these sort of situations (https://pandas.pydata.org/docs/reference/api/pandas.Series.dt.tz_localize.html) and I suspect we could normalize the times like this:

tz = times.tz
normalized_times = times.tz_localize(None).normalize().tz_localize(tz, nonexistent="shift_forward")

This would normalize the times to 1:00am instead of 12:00am (which didn't exist on that date). Here's some related discussion from a Pandas issue: https://github.com/pandas-dev/pandas/issues/40517

I suspect we'd need to similarly handle ambiguous times when daylight savings ends.

Does this seem like a reasonable approach? I can put a small PR together if so.

Versions:

cwhanse commented 1 month ago

Confirmed the issue with pvlib v0.11.0.

The discussion around the pandas issue suggests this occurs when DST adjustment occurs in a way that midnight local never "happens".

Short of a worldwide deprecation of daylight savings times, or handling of this case by pandas.normalize, I suppose we ought to patch pvlib with liberal comments. rdtools worked around the problem in the similar way as proposed here https://github.com/NREL/rdtools/pull/373/files

cwhanse commented 1 month ago

@scttnlsn re-reading my comment, I don't think I was very clear: PR welcome along the lines you propose.

scttnlsn commented 1 month ago

@cwhanse Sounds good - I'll put something together