2323import scipy .optimize as so
2424import warnings
2525
26- from pvlib import atmosphere
26+ from pvlib import atmosphere , tools
2727from pvlib .tools import datetime_to_djd , djd_to_datetime
2828
2929
@@ -199,11 +199,7 @@ def spa_c(time, latitude, longitude, pressure=101325, altitude=0,
199199 raise ImportError ('Could not import built-in SPA calculator. ' +
200200 'You may need to recompile the SPA code.' )
201201
202- # if localized, convert to UTC. otherwise, assume UTC.
203- try :
204- time_utc = time .tz_convert ('UTC' )
205- except TypeError :
206- time_utc = time
202+ time_utc = tools ._pandas_to_utc (time )
207203
208204 spa_out = []
209205
@@ -378,7 +374,9 @@ def spa_python(time, latitude, longitude,
378374
379375 spa = _spa_python_import (how )
380376
381- delta_t = delta_t or spa .calculate_deltat (time .year , time .month )
377+ if not delta_t :
378+ time_utc = tools ._pandas_to_utc (time )
379+ delta_t = spa .calculate_deltat (time_utc .year , time_utc .month )
382380
383381 app_zenith , zenith , app_elevation , elevation , azimuth , eot = \
384382 spa .solar_position (unixtime , lat , lon , elev , pressure , temperature ,
@@ -452,12 +450,13 @@ def sun_rise_set_transit_spa(times, latitude, longitude, how='numpy',
452450 raise ValueError ('times must be localized' )
453451
454452 # must convert to midnight UTC on day of interest
455- utcday = pd . DatetimeIndex ( times .date ). tz_localize ('UTC' )
456- unixtime = _datetime_to_unixtime (utcday )
453+ times_utc = times .tz_convert ('UTC' )
454+ unixtime = _datetime_to_unixtime (times_utc . normalize () )
457455
458456 spa = _spa_python_import (how )
459457
460- delta_t = delta_t or spa .calculate_deltat (times .year , times .month )
458+ if not delta_t :
459+ delta_t = spa .calculate_deltat (times_utc .year , times_utc .month )
461460
462461 transit , sunrise , sunset = spa .transit_sunrise_sunset (
463462 unixtime , lat , lon , delta_t , numthreads )
@@ -581,12 +580,11 @@ def sun_rise_set_transit_ephem(times, latitude, longitude,
581580 sunrise = []
582581 sunset = []
583582 trans = []
584- for thetime in times :
585- thetime = thetime .to_pydatetime ()
583+ for thetime in tools ._pandas_to_utc (times ):
586584 # older versions of pyephem ignore timezone when converting to its
587585 # internal datetime format, so convert to UTC here to support
588586 # all versions. GH #1449
589- obs .date = ephem .Date (thetime . astimezone ( dt . timezone . utc ) )
587+ obs .date = ephem .Date (thetime )
590588 sunrise .append (_ephem_to_timezone (rising (sun ), tzinfo ))
591589 sunset .append (_ephem_to_timezone (setting (sun ), tzinfo ))
592590 trans .append (_ephem_to_timezone (transit (sun ), tzinfo ))
@@ -644,11 +642,7 @@ def pyephem(time, latitude, longitude, altitude=0, pressure=101325,
644642 except ImportError :
645643 raise ImportError ('PyEphem must be installed' )
646644
647- # if localized, convert to UTC. otherwise, assume UTC.
648- try :
649- time_utc = time .tz_convert ('UTC' )
650- except TypeError :
651- time_utc = time
645+ time_utc = tools ._pandas_to_utc (time )
652646
653647 sun_coords = pd .DataFrame (index = time )
654648
@@ -765,11 +759,7 @@ def ephemeris(time, latitude, longitude, pressure=101325, temperature=12):
765759 # the SPA algorithm needs time to be expressed in terms of
766760 # decimal UTC hours of the day of the year.
767761
768- # if localized, convert to UTC. otherwise, assume UTC.
769- try :
770- time_utc = time .tz_convert ('UTC' )
771- except TypeError :
772- time_utc = time
762+ time_utc = tools ._pandas_to_utc (time )
773763
774764 # strip out the day of the year and calculate the decimal hour
775765 DayOfYear = time_utc .dayofyear
@@ -956,7 +946,10 @@ def pyephem_earthsun_distance(time):
956946
957947 sun = ephem .Sun ()
958948 earthsun = []
959- for thetime in time :
949+ for thetime in tools ._pandas_to_utc (time ):
950+ # older versions of pyephem ignore timezone when converting to its
951+ # internal datetime format, so convert to UTC here to support
952+ # all versions. GH #1449
960953 sun .compute (ephem .Date (thetime ))
961954 earthsun .append (sun .earth_distance )
962955
@@ -1013,7 +1006,9 @@ def nrel_earthsun_distance(time, how='numpy', delta_t=67.0, numthreads=4):
10131006
10141007 spa = _spa_python_import (how )
10151008
1016- delta_t = delta_t or spa .calculate_deltat (time .year , time .month )
1009+ if not delta_t :
1010+ time_utc = tools ._pandas_to_utc (time )
1011+ delta_t = spa .calculate_deltat (time_utc .year , time_utc .month )
10171012
10181013 dist = spa .earthsun_distance (unixtime , delta_t , numthreads )
10191014
@@ -1386,22 +1381,26 @@ def hour_angle(times, longitude, equation_of_time):
13861381 equation_of_time_spencer71
13871382 equation_of_time_pvcdrom
13881383 """
1384+
1385+ # times must be localized
1386+ if not times .tz :
1387+ raise ValueError ('times must be localized' )
1388+
13891389 # hours - timezone = (times - normalized_times) - (naive_times - times)
1390- if times .tz is None :
1391- times = times .tz_localize ('utc' )
13921390 tzs = np .array ([ts .utcoffset ().total_seconds () for ts in times ]) / 3600
13931391
1394- hrs_minus_tzs = (times - times . normalize ()) / pd . Timedelta ( '1h' ) - tzs
1392+ hrs_minus_tzs = _times_to_hours_after_local_midnight (times ) - tzs
13951393
1396- # ensure array return instead of a version-dependent pandas <T>Index
1397- return np .asarray (
1398- 15. * (hrs_minus_tzs - 12. ) + longitude + equation_of_time / 4. )
1394+ return 15. * (hrs_minus_tzs - 12. ) + longitude + equation_of_time / 4.
13991395
14001396
14011397def _hour_angle_to_hours (times , hourangle , longitude , equation_of_time ):
14021398 """converts hour angles in degrees to hours as a numpy array"""
1403- if times .tz is None :
1404- times = times .tz_localize ('utc' )
1399+
1400+ # times must be localized
1401+ if not times .tz :
1402+ raise ValueError ('times must be localized' )
1403+
14051404 tzs = np .array ([ts .utcoffset ().total_seconds () for ts in times ]) / 3600
14061405 hours = (hourangle - longitude - equation_of_time / 4. ) / 15. + 12. + tzs
14071406 return np .asarray (hours )
@@ -1411,18 +1410,26 @@ def _local_times_from_hours_since_midnight(times, hours):
14111410 """
14121411 converts hours since midnight from an array of floats to localized times
14131412 """
1414- tz_info = times .tz # pytz timezone info
1415- naive_times = times .tz_localize (None ) # naive but still localized
1416- # normalize local, naive times to previous midnight and add the hours until
1413+
1414+ # times must be localized
1415+ if not times .tz :
1416+ raise ValueError ('times must be localized' )
1417+
1418+ # normalize local times to previous local midnight and add the hours until
14171419 # sunrise, sunset, and transit
1418- return pd .DatetimeIndex (
1419- naive_times .normalize () + pd .to_timedelta (hours , unit = 'h' ), tz = tz_info )
1420+ return times .normalize () + pd .to_timedelta (hours , unit = 'h' )
14201421
14211422
14221423def _times_to_hours_after_local_midnight (times ):
14231424 """convert local pandas datetime indices to array of hours as floats"""
1424- times = times .tz_localize (None )
1425+
1426+ # times must be localized
1427+ if not times .tz :
1428+ raise ValueError ('times must be localized' )
1429+
14251430 hrs = (times - times .normalize ()) / pd .Timedelta ('1h' )
1431+
1432+ # ensure array return instead of a version-dependent pandas <T>Index
14261433 return np .array (hrs )
14271434
14281435
@@ -1468,6 +1475,11 @@ def sun_rise_set_transit_geometric(times, latitude, longitude, declination,
14681475 CRC Press (2012)
14691476
14701477 """
1478+
1479+ # times must be localized
1480+ if not times .tz :
1481+ raise ValueError ('times must be localized' )
1482+
14711483 latitude_rad = np .radians (latitude ) # radians
14721484 sunset_angle_rad = np .arccos (- np .tan (declination ) * np .tan (latitude_rad ))
14731485 sunset_angle = np .degrees (sunset_angle_rad ) # degrees
0 commit comments