-
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 11 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 |
---|---|---|
@@ -1,9 +1,12 @@ | ||
import pytest | ||
from datetime import datetime | ||
from zoneinfo import ZoneInfo | ||
|
||
from pvlib import tools | ||
import numpy as np | ||
import pandas as pd | ||
from numpy.testing import assert_allclose | ||
import pandas as pd | ||
import pytest | ||
|
||
from pvlib import location, tools | ||
|
||
|
||
@pytest.mark.parametrize('keys, input_dict, expected', [ | ||
|
@@ -144,3 +147,192 @@ def test_get_pandas_index(args, args_idx): | |
def test_normalize_max2one(data_in, expected): | ||
result = tools.normalize_max2one(data_in) | ||
assert_allclose(result, expected) | ||
|
||
|
||
@pytest.mark.parametrize( | ||
'input,expected', | ||
[ | ||
( | ||
{ | ||
"time": datetime( | ||
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. Using a I'm interested in feedback from others: is this parameterization style easier or more difficult, as a reviewer? 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. My 2 cents: a more compact representation of the changing values is helpful for reviewing, and is worth a bit of processing inside the test function itself. For example, it seems like the following: (
{
"time": pd.DatetimeIndex(
["1974-06-22T18:30:15"],
tz=ZoneInfo("Etc/GMT+5"),
),
"location": location.Location(
43.19262774396091, -77.58782907414867, tz="Etc/GMT+5"
)
},
pd.DatetimeIndex(["1974-06-22T23:30:15"], tz=ZoneInfo("UTC")),
),
(
{
"time": pd.DatetimeIndex(["1974-06-22T18:30:15"]),
"location": location.Location(
43.19262774396091, -77.58782907414867, tz="Etc/GMT+5"
)
},
pd.DatetimeIndex(["1974-06-22T23:30:15"], tz=ZoneInfo("UTC")),
), could be replaced with something like this: ("1974-06-22T18:30:15", "Etc/GMT+5", 43, -77, "Etc/GMT+5", "1974-06-22T23:30:15+00:00"),
("1974-06-22T18:30:15", None, 43, -77, "Etc/GMT+5", "1974-06-22T23:30:15+00:00"), And the test function could then contain the necessary calls to I think the latter format makes it easier to see what changes between each set of parameters. I found my eyes having to flick back and forth and subsequently getting lost with the former format. 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. In the end I think this was simplified to @pytest.mark.parametrize(
'tz,tz_expected', [
pytest.param('UTC', 'UTC'),
pytest.param('Etc/GMT+5', 'Etc/GMT+5'),
pytest.param('US/Mountain', 'US/Mountain'),
pytest.param('America/Phoenix', 'America/Phoenix'),
pytest.param('Asia/Kathmandu', 'Asia/Kathmandu'),
pytest.param('Asia/Yangon', 'Asia/Yangon'),
pytest.param(datetime.timezone.utc, 'UTC'),
pytest.param(zoneinfo.ZoneInfo('Etc/GMT-7'), 'Etc/GMT-7'),
pytest.param(pytz.timezone('US/Arizona'), 'US/Arizona'),
pytest.param(-6, 'Etc/GMT+6'),
pytest.param(-11.0, 'Etc/GMT+11'),
pytest.param(12, 'Etc/GMT-12'),
],
)
... |
||
1974, 6, 22, 18, 30, 15, tzinfo=ZoneInfo("Etc/GMT+5"), | ||
), | ||
"location": location.Location( | ||
43.19262774396091, -77.58782907414867, tz="Etc/GMT+5" | ||
) | ||
}, | ||
datetime(1974, 6, 22, 23, 30, 15, tzinfo=ZoneInfo("UTC")), | ||
), | ||
( | ||
{ | ||
"time": datetime(1974, 6, 22, 18, 30, 15), | ||
"location": location.Location( | ||
43.19262774396091, -77.58782907414867, tz="Etc/GMT+5" | ||
) | ||
}, | ||
datetime(1974, 6, 22, 23, 30, 15, tzinfo=ZoneInfo("UTC")), | ||
), | ||
( | ||
{ | ||
"time": pd.DatetimeIndex( | ||
["1974-06-22T18:30:15"], | ||
tz=ZoneInfo("Etc/GMT+5"), | ||
), | ||
"location": location.Location( | ||
43.19262774396091, -77.58782907414867, tz="Etc/GMT+5" | ||
) | ||
}, | ||
pd.DatetimeIndex(["1974-06-22T23:30:15"], tz=ZoneInfo("UTC")), | ||
), | ||
( | ||
{ | ||
"time": pd.DatetimeIndex(["1974-06-22T18:30:15"]), | ||
"location": location.Location( | ||
43.19262774396091, -77.58782907414867, tz="Etc/GMT+5" | ||
) | ||
}, | ||
pd.DatetimeIndex(["1974-06-22T23:30:15"], tz=ZoneInfo("UTC")), | ||
), | ||
( | ||
{ | ||
"time": pd.Series( | ||
[24.42], | ||
index=pd.DatetimeIndex( | ||
["1974-06-22T18:30:15"], | ||
tz=ZoneInfo("Etc/GMT+5"), | ||
), | ||
), | ||
"location": location.Location( | ||
43.19262774396091, -77.58782907414867, tz="Etc/GMT+5" | ||
) | ||
}, | ||
pd.Series( | ||
[24.42], | ||
pd.DatetimeIndex(["1974-06-22T23:30:15"], tz=ZoneInfo("UTC")), | ||
), | ||
), | ||
( | ||
{ | ||
"time": pd.Series( | ||
[24.42], | ||
index=pd.DatetimeIndex(["1974-06-22T18:30:15"]), | ||
), | ||
"location": location.Location( | ||
43.19262774396091, -77.58782907414867, tz="Etc/GMT+5" | ||
) | ||
}, | ||
pd.Series( | ||
[24.42], | ||
pd.DatetimeIndex(["1974-06-22T23:30:15"], tz=ZoneInfo("UTC")), | ||
), | ||
), | ||
( | ||
{ | ||
"time": pd.DataFrame( | ||
[[24.42]], | ||
index=pd.DatetimeIndex( | ||
["1974-06-22T18:30:15"], | ||
tz=ZoneInfo("Etc/GMT+5"), | ||
), | ||
), | ||
"location": location.Location( | ||
43.19262774396091, -77.58782907414867, tz="Etc/GMT+5" | ||
) | ||
}, | ||
pd.DataFrame( | ||
[[24.42]], | ||
pd.DatetimeIndex(["1974-06-22T23:30:15"], tz=ZoneInfo("UTC")), | ||
), | ||
), | ||
( | ||
{ | ||
"time": pd.DataFrame( | ||
[[24.42]], | ||
index=pd.DatetimeIndex(["1974-06-22T18:30:15"]), | ||
), | ||
"location": location.Location( | ||
43.19262774396091, -77.58782907414867, tz="Etc/GMT+5" | ||
) | ||
}, | ||
pd.DataFrame( | ||
[[24.42]], | ||
pd.DatetimeIndex(["1974-06-22T23:30:15"], tz=ZoneInfo("UTC")), | ||
), | ||
), | ||
], | ||
ids=[ | ||
"datetime.datetime with tzinfo", | ||
"datetime.datetime", | ||
"pandas.DatetimeIndex with tzinfo", | ||
"pandas.DatetimeIndex", | ||
"pandas.Series with tzinfo", | ||
"pandas.Series", | ||
"pandas.DataFrame with tzinfo", | ||
"pandas.DataFrame", | ||
], | ||
) | ||
def test_localize_to_utc(input, expected): | ||
got = tools.localize_to_utc(**input) | ||
|
||
if isinstance(got, (pd.Series, pd.DataFrame)): | ||
# Older pandas versions have wonky dtype equality check on timestamp | ||
# index, so check the values as numpy.ndarray and indices one by one. | ||
np.testing.assert_array_equal(got.to_numpy(), expected.to_numpy()) | ||
|
||
for index_got, index_expected in zip(got.index, expected.index): | ||
assert index_got == index_expected | ||
else: | ||
assert got == expected | ||
|
||
|
||
@pytest.mark.parametrize( | ||
'input,expected', | ||
[ | ||
( | ||
{ | ||
"time": datetime( | ||
1974, 6, 22, 18, 30, 15, tzinfo=ZoneInfo("Etc/GMT+5") | ||
) | ||
}, | ||
27201.47934027778, | ||
), | ||
( | ||
{ | ||
"time": datetime(1974, 6, 22, 23, 30, 15) | ||
}, | ||
27201.47934027778, | ||
), | ||
], | ||
ids=["datetime.datetime with tzinfo", "datetime.datetime"], | ||
) | ||
def test_datetime_to_djd(input, expected): | ||
assert tools.datetime_to_djd(input["time"]) == expected | ||
|
||
|
||
@pytest.mark.parametrize( | ||
'input,expected', | ||
[ | ||
( | ||
{ | ||
"djd": 27201.47934027778, | ||
"tz": "Etc/GMT+5", | ||
}, | ||
datetime(1974, 6, 22, 18, 30, 15, tzinfo=ZoneInfo("Etc/GMT+5")), | ||
), | ||
( | ||
{ | ||
"djd": 27201.47934027778, | ||
"tz": None, | ||
}, | ||
datetime(1974, 6, 22, 23, 30, 15, tzinfo=ZoneInfo("UTC")), | ||
), | ||
], | ||
ids=["djd with tzinfo", "djd"], | ||
) | ||
def test_djd_to_datetime(input, expected): | ||
if input["tz"] is not None: | ||
got = tools.djd_to_datetime(input["djd"]) | ||
else: | ||
got = tools.djd_to_datetime(input["djd"], tz="Etc/GMT+5") | ||
|
||
assert got == expected |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -119,7 +119,7 @@ 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 | ||||||
---------- | ||||||
|
@@ -129,7 +129,7 @@ def localize_to_utc(time, location): | |||||
|
||||||
Returns | ||||||
------- | ||||||
pandas object localized to UTC. | ||||||
datetime.datetime or pandas object localized to UTC. | ||||||
""" | ||||||
if isinstance(time, dt.datetime): | ||||||
if time.tzinfo is None: | ||||||
|
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.