23
23
import scipy .optimize as so
24
24
import warnings
25
25
26
- from pvlib import atmosphere
26
+ from pvlib import atmosphere , tools
27
27
from pvlib .tools import datetime_to_djd , djd_to_datetime
28
28
29
29
@@ -199,11 +199,7 @@ def spa_c(time, latitude, longitude, pressure=101325, altitude=0,
199
199
raise ImportError ('Could not import built-in SPA calculator. ' +
200
200
'You may need to recompile the SPA code.' )
201
201
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 )
207
203
208
204
spa_out = []
209
205
@@ -378,7 +374,9 @@ def spa_python(time, latitude, longitude,
378
374
379
375
spa = _spa_python_import (how )
380
376
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 )
382
380
383
381
app_zenith , zenith , app_elevation , elevation , azimuth , eot = \
384
382
spa .solar_position (unixtime , lat , lon , elev , pressure , temperature ,
@@ -452,12 +450,13 @@ def sun_rise_set_transit_spa(times, latitude, longitude, how='numpy',
452
450
raise ValueError ('times must be localized' )
453
451
454
452
# 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 () )
457
455
458
456
spa = _spa_python_import (how )
459
457
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 )
461
460
462
461
transit , sunrise , sunset = spa .transit_sunrise_sunset (
463
462
unixtime , lat , lon , delta_t , numthreads )
@@ -581,12 +580,11 @@ def sun_rise_set_transit_ephem(times, latitude, longitude,
581
580
sunrise = []
582
581
sunset = []
583
582
trans = []
584
- for thetime in times :
585
- thetime = thetime .to_pydatetime ()
583
+ for thetime in tools ._pandas_to_utc (times ):
586
584
# older versions of pyephem ignore timezone when converting to its
587
585
# internal datetime format, so convert to UTC here to support
588
586
# all versions. GH #1449
589
- obs .date = ephem .Date (thetime . astimezone ( dt . timezone . utc ) )
587
+ obs .date = ephem .Date (thetime )
590
588
sunrise .append (_ephem_to_timezone (rising (sun ), tzinfo ))
591
589
sunset .append (_ephem_to_timezone (setting (sun ), tzinfo ))
592
590
trans .append (_ephem_to_timezone (transit (sun ), tzinfo ))
@@ -644,11 +642,7 @@ def pyephem(time, latitude, longitude, altitude=0, pressure=101325,
644
642
except ImportError :
645
643
raise ImportError ('PyEphem must be installed' )
646
644
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 )
652
646
653
647
sun_coords = pd .DataFrame (index = time )
654
648
@@ -765,11 +759,7 @@ def ephemeris(time, latitude, longitude, pressure=101325, temperature=12):
765
759
# the SPA algorithm needs time to be expressed in terms of
766
760
# decimal UTC hours of the day of the year.
767
761
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 )
773
763
774
764
# strip out the day of the year and calculate the decimal hour
775
765
DayOfYear = time_utc .dayofyear
@@ -956,7 +946,10 @@ def pyephem_earthsun_distance(time):
956
946
957
947
sun = ephem .Sun ()
958
948
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
960
953
sun .compute (ephem .Date (thetime ))
961
954
earthsun .append (sun .earth_distance )
962
955
@@ -1013,7 +1006,9 @@ def nrel_earthsun_distance(time, how='numpy', delta_t=67.0, numthreads=4):
1013
1006
1014
1007
spa = _spa_python_import (how )
1015
1008
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 )
1017
1012
1018
1013
dist = spa .earthsun_distance (unixtime , delta_t , numthreads )
1019
1014
@@ -1386,22 +1381,26 @@ def hour_angle(times, longitude, equation_of_time):
1386
1381
equation_of_time_spencer71
1387
1382
equation_of_time_pvcdrom
1388
1383
"""
1384
+
1385
+ # times must be localized
1386
+ if not times .tz :
1387
+ raise ValueError ('times must be localized' )
1388
+
1389
1389
# hours - timezone = (times - normalized_times) - (naive_times - times)
1390
- if times .tz is None :
1391
- times = times .tz_localize ('utc' )
1392
1390
tzs = np .array ([ts .utcoffset ().total_seconds () for ts in times ]) / 3600
1393
1391
1394
- hrs_minus_tzs = (times - times . normalize ()) / pd . Timedelta ( '1h' ) - tzs
1392
+ hrs_minus_tzs = _times_to_hours_after_local_midnight (times ) - tzs
1395
1393
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.
1399
1395
1400
1396
1401
1397
def _hour_angle_to_hours (times , hourangle , longitude , equation_of_time ):
1402
1398
"""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
+
1405
1404
tzs = np .array ([ts .utcoffset ().total_seconds () for ts in times ]) / 3600
1406
1405
hours = (hourangle - longitude - equation_of_time / 4. ) / 15. + 12. + tzs
1407
1406
return np .asarray (hours )
@@ -1411,18 +1410,26 @@ def _local_times_from_hours_since_midnight(times, hours):
1411
1410
"""
1412
1411
converts hours since midnight from an array of floats to localized times
1413
1412
"""
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
1417
1419
# 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' )
1420
1421
1421
1422
1422
1423
def _times_to_hours_after_local_midnight (times ):
1423
1424
"""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
+
1425
1430
hrs = (times - times .normalize ()) / pd .Timedelta ('1h' )
1431
+
1432
+ # ensure array return instead of a version-dependent pandas <T>Index
1426
1433
return np .array (hrs )
1427
1434
1428
1435
@@ -1468,6 +1475,11 @@ def sun_rise_set_transit_geometric(times, latitude, longitude, declination,
1468
1475
CRC Press (2012)
1469
1476
1470
1477
"""
1478
+
1479
+ # times must be localized
1480
+ if not times .tz :
1481
+ raise ValueError ('times must be localized' )
1482
+
1471
1483
latitude_rad = np .radians (latitude ) # radians
1472
1484
sunset_angle_rad = np .arccos (- np .tan (declination ) * np .tan (latitude_rad ))
1473
1485
sunset_angle = np .degrees (sunset_angle_rad ) # degrees
0 commit comments