-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add tests for time conversions in tools package #2341
base: main
Are you sure you want to change the base?
Changes from 19 commits
9347f12
0638773
c1df9a7
77c0f81
6704d06
dbb1805
6750709
1144106
14715ed
545c196
271fd97
01263c2
60a5d94
9ab2ecf
ddef8d1
4f17f49
a3c3e03
5f59417
c84801f
195efbc
1a5efed
e5af9ae
67e9844
e35eb42
a1a0261
8373ac4
eee6f51
9662c1f
32284ba
01e4cfc
c09a328
4ef4b69
7490792
a5f7646
1382e30
059e35f
f9f07d7
75db2aa
1164c96
5f6ad14
f691bb6
7cfb170
ef5c60f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -12,12 +12,21 @@ Enhancements | |||||
~~~~~~~~~~~~ | ||||||
|
||||||
|
||||||
Bug Fixes | ||||||
~~~~~~~~~ | ||||||
* Ensure proper tz and pytz types in pvlib.location.Location. | ||||||
(:issue:`2340`, :pull:`2341`) | ||||||
|
||||||
|
||||||
Documentation | ||||||
~~~~~~~~~~~~~ | ||||||
|
||||||
|
||||||
Testing | ||||||
~~~~~~~ | ||||||
* Add tests for timezone types in pvlib.location.Location. | ||||||
(:issue:`2340`, :pull:`2341`) | ||||||
* Add tests for time conversions in pvlib.tools. (:issue:`2340`, :pull:`2341`) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
|
||||||
Requirements | ||||||
|
@@ -26,5 +35,4 @@ Requirements | |||||
|
||||||
Contributors | ||||||
~~~~~~~~~~~~ | ||||||
|
||||||
|
||||||
* Mark Campanellli (:ghuser:`markcampanelli`) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -18,13 +18,15 @@ | |||||||||
class Location: | ||||||||||
""" | ||||||||||
Location objects are convenient containers for latitude, longitude, | ||||||||||
timezone, and altitude data associated with a particular | ||||||||||
geographic location. You can also assign a name to a location object. | ||||||||||
time zone, and altitude data associated with a particular geographic | ||||||||||
location. You can also assign a name to a location object. | ||||||||||
|
||||||||||
Location objects have two timezone attributes: | ||||||||||
Location objects have two time-zone attributes, either of which can be | ||||||||||
individually changed after the Location object has been instantiated and | ||||||||||
the other will stay in sync: | ||||||||||
|
||||||||||
* ``tz`` is a IANA timezone string. | ||||||||||
* ``pytz`` is a pytz timezone object. | ||||||||||
* ``tz`` is a IANA time-zone string. | ||||||||||
* ``pytz`` is a pytz time-zone object. | ||||||||||
|
||||||||||
Location objects support the print method. | ||||||||||
|
||||||||||
|
@@ -38,12 +40,16 @@ class Location: | |||||||||
Positive is east of the prime meridian. | ||||||||||
Use decimal degrees notation. | ||||||||||
|
||||||||||
tz : str, int, float, or pytz.timezone, default 'UTC'. | ||||||||||
See | ||||||||||
http://en.wikipedia.org/wiki/List_of_tz_database_time_zones | ||||||||||
for a list of valid time zones. | ||||||||||
pytz.timezone objects will be converted to strings. | ||||||||||
ints and floats must be in hours from UTC. | ||||||||||
tz : time zone as str, int, float, or datetime.tzinfo (inc. subclasses | ||||||||||
from the pytz and zoneinfo packages), default 'UTC'. | ||||||||||
See http://en.wikipedia.org/wiki/List_of_tz_database_time_zones for a | ||||||||||
list of valid name strings for IANA time zones. | ||||||||||
ints and floats must be non-fractional N-hour offsets from UTC, which | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
are converted to the 'Etc/GMT-N' format (note limited range of N and | ||||||||||
its conventional sign change). | ||||||||||
Raises TypeError for time zone conversion issues or | ||||||||||
pytz.exceptions.UnknownTimeZoneError when (stringified) time zone is | ||||||||||
not recognized by pytz.timezone. | ||||||||||
|
||||||||||
altitude : float, optional | ||||||||||
Altitude from sea level in meters. | ||||||||||
|
@@ -59,38 +65,54 @@ class Location: | |||||||||
pvlib.pvsystem.PVSystem | ||||||||||
""" | ||||||||||
|
||||||||||
def __init__(self, latitude, longitude, tz='UTC', altitude=None, | ||||||||||
name=None): | ||||||||||
|
||||||||||
def __init__( | ||||||||||
self, latitude, longitude, tz='UTC', altitude=None, name=None | ||||||||||
): | ||||||||||
self.latitude = latitude | ||||||||||
self.longitude = longitude | ||||||||||
|
||||||||||
if isinstance(tz, str): | ||||||||||
self.tz = tz | ||||||||||
self.pytz = pytz.timezone(tz) | ||||||||||
elif isinstance(tz, datetime.timezone): | ||||||||||
self.tz = 'UTC' | ||||||||||
self.pytz = pytz.UTC | ||||||||||
elif isinstance(tz, datetime.tzinfo): | ||||||||||
self.tz = tz.zone | ||||||||||
self.pytz = tz | ||||||||||
elif isinstance(tz, (int, float)): | ||||||||||
self.tz = tz | ||||||||||
cwhanse marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||
self.pytz = pytz.FixedOffset(tz*60) | ||||||||||
else: | ||||||||||
raise TypeError('Invalid tz specification') | ||||||||||
self.tz = tz | ||||||||||
|
||||||||||
if altitude is None: | ||||||||||
altitude = lookup_altitude(latitude, longitude) | ||||||||||
|
||||||||||
self.altitude = altitude | ||||||||||
|
||||||||||
self.name = name | ||||||||||
|
||||||||||
def __repr__(self): | ||||||||||
attrs = ['name', 'latitude', 'longitude', 'altitude', 'tz'] | ||||||||||
# Use None as getattr default in case __repr__ is called during | ||||||||||
# initialization before all attributes have been assigned. | ||||||||||
return ('Location: \n ' + '\n '.join( | ||||||||||
f'{attr}: {getattr(self, attr)}' for attr in attrs)) | ||||||||||
f'{attr}: {getattr(self, attr, None)}' for attr in attrs)) | ||||||||||
|
||||||||||
@property | ||||||||||
def tz(self): | ||||||||||
# self.pytz holds the single source of time-zone truth. | ||||||||||
return self.pytz.zone | ||||||||||
|
||||||||||
@tz.setter | ||||||||||
def tz(self, tz_): | ||||||||||
if isinstance(tz_, str): | ||||||||||
self.pytz = pytz.timezone(tz_) | ||||||||||
elif isinstance(tz_, int): | ||||||||||
self.pytz = pytz.timezone(f"Etc/GMT{-tz_:+d}") | ||||||||||
elif isinstance(tz_, float): | ||||||||||
if tz_ % 1 != 0: | ||||||||||
raise TypeError( | ||||||||||
"floating point tz does not have zero fractional part: " | ||||||||||
f"{tz_}" | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
) | ||||||||||
|
||||||||||
self.pytz = pytz.timezone(f"Etc/GMT{-int(tz_):+d}") | ||||||||||
elif isinstance(tz_, datetime.tzinfo): | ||||||||||
# Includes time zones generated by pytz and zoneinfo packages. | ||||||||||
self.pytz = pytz.timezone(str(tz_)) | ||||||||||
else: | ||||||||||
raise TypeError( | ||||||||||
f"invalid tz specification: {tz_}, must be an IANA time zone " | ||||||||||
"string, a non-fractional int/float UTC offset, or a " | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||
"datetime.tzinfo object (including subclasses)" | ||||||||||
) | ||||||||||
|
||||||||||
@classmethod | ||||||||||
def from_tmy(cls, tmy_metadata, tmy_data=None, **kwargs): | ||||||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -119,21 +119,21 @@ def atand(number): | |||||
|
||||||
def localize_to_utc(time, location): | ||||||
""" | ||||||
Converts or localizes a time series to UTC. | ||||||
Converts time to UTC, localizing if necessary using location. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Parameters | ||||||
---------- | ||||||
time : datetime.datetime, pandas.DatetimeIndex, | ||||||
or pandas.Series/DataFrame with a DatetimeIndex. | ||||||
location : pvlib.Location object | ||||||
location : pvlib.Location object (unused if time is localized) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
Returns | ||||||
------- | ||||||
pandas object localized to UTC. | ||||||
datetime.datetime or pandas object localized to UTC. | ||||||
""" | ||||||
if isinstance(time, dt.datetime): | ||||||
if time.tzinfo is None: | ||||||
time = pytz.timezone(location.tz).localize(time) | ||||||
time = location.pytz.localize(time) | ||||||
time_utc = time.astimezone(pytz.utc) | ||||||
else: | ||||||
try: | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.