From 6a5c5d32dcea5921bbb3f19fd46da3690a324f6e Mon Sep 17 00:00:00 2001 From: Johann Lo <65318981+JoLo90@users.noreply.github.com> Date: Tue, 19 May 2026 10:20:03 +0200 Subject: [PATCH 1/9] refactor: deprecate pytz in favor of builtin zoneinfo --- docs/sphinx/source/whatsnew/v0.15.2.rst | 2 ++ pvlib/iotools/pvgis.py | 6 ++-- pvlib/location.py | 35 ++++++++++++------ pvlib/solarposition.py | 10 +++--- pvlib/tools.py | 17 ++++----- tests/iotools/test_midc.py | 1 - tests/test_clearsky.py | 4 +-- tests/test_location.py | 13 +++---- tests/test_solarposition.py | 47 ++++++++++++++----------- 9 files changed, 75 insertions(+), 60 deletions(-) diff --git a/docs/sphinx/source/whatsnew/v0.15.2.rst b/docs/sphinx/source/whatsnew/v0.15.2.rst index 1f4524d893..30ba7875f0 100644 --- a/docs/sphinx/source/whatsnew/v0.15.2.rst +++ b/docs/sphinx/source/whatsnew/v0.15.2.rst @@ -10,6 +10,8 @@ Breaking Changes Deprecations ~~~~~~~~~~~~ +* ``Location.pytz`` is deprecated. Use ``Location.tz`` instead. + (:ghuser:`JoLo90`, :pull:`2757`) Bug fixes diff --git a/pvlib/iotools/pvgis.py b/pvlib/iotools/pvgis.py index c69017344a..61f3eff695 100644 --- a/pvlib/iotools/pvgis.py +++ b/pvlib/iotools/pvgis.py @@ -20,7 +20,7 @@ import requests import numpy as np import pandas as pd -import pytz +import zoneinfo from pvlib.iotools import read_epw URL = 'https://re.jrc.ec.europa.eu/api/' @@ -413,10 +413,10 @@ def _coerce_and_roll_tmy(tmy_data, tz, year): re-interpreted as zero / UTC. """ if tz: - tzname = pytz.timezone(f'Etc/GMT{-tz:+d}') + tzname = zoneinfo.ZoneInfo(f'Etc/GMT{-tz:+d}') # noqa: E231 else: tz = 0 - tzname = pytz.timezone('UTC') + tzname = zoneinfo.ZoneInfo('UTC') new_index = pd.DatetimeIndex([ timestamp.replace(year=year, tzinfo=tzname) for timestamp in tmy_data.index], diff --git a/pvlib/location.py b/pvlib/location.py index 230ce26a66..221dd05837 100644 --- a/pvlib/location.py +++ b/pvlib/location.py @@ -14,6 +14,7 @@ from pvlib import solarposition, clearsky, atmosphere, irradiance from pvlib.tools import _degrees_to_index +from pvlib._deprecation import warn_deprecated class Location: @@ -22,13 +23,11 @@ class Location: 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 time-zone attributes: + Location objects have a time-zone attribute: * ``tz`` is an IANA time-zone string. - * ``pytz`` is a pytz-based time-zone object (read only). - The read-only ``pytz`` attribute will stay in sync with any changes made - using ``tz``. + The ``pytz`` attribute is deprecated. Use ``tz`` instead. Location objects support the print method. @@ -47,8 +46,8 @@ class Location: list of valid name strings. An `int` or `float` must be a whole-number hour offsets from UTC that can be converted to the IANA-supported 'Etc/GMT-N' format. (Note the limited range of the offset N and its - sign-change convention.) Time zones from the pytz and zoneinfo packages - may also be passed here, as they are subclasses of datetime.tzinfo. + sign-change convention.) Time zones from the zoneinfo packages may also + be passed here. The `tz` attribute is represented as a valid IANA time zone name string. @@ -108,7 +107,8 @@ def tz(self, tz_): if isinstance(tz_, str): self._zoneinfo = zoneinfo.ZoneInfo(tz_) elif isinstance(tz_, int): - self._zoneinfo = zoneinfo.ZoneInfo(f"Etc/GMT{-tz_:+d}") + tz_str = f"Etc/GMT{-tz_:+d}" # noqa: E231 + self._zoneinfo = zoneinfo.ZoneInfo(tz_str) elif isinstance(tz_, float): if tz_ % 1 != 0: raise TypeError( @@ -116,9 +116,10 @@ def tz(self, tz_): f"{tz_}. Only whole-number offsets are supported." ) - self._zoneinfo = zoneinfo.ZoneInfo(f"Etc/GMT{-int(tz_):+d}") + tz_str = f"Etc/GMT{-int(tz_):+d}" # noqa: E231 + self._zoneinfo = zoneinfo.ZoneInfo(tz_str) elif isinstance(tz_, datetime.tzinfo): - # Includes time zones generated by pytz and zoneinfo packages. + # Includes time zones generated by zoneinfo packages. self._zoneinfo = zoneinfo.ZoneInfo(str(tz_)) else: raise TypeError( @@ -128,8 +129,20 @@ def tz(self, tz_): ) @property - def pytz(self): - """The location's pytz time zone (read only).""" + def pytz(self): # pragma: no cover + """The location's pytz time zone (read only). + + .. deprecated:: + The ``pytz`` attribute is deprecated. Use the ``tz`` property + instead. + """ + warn_deprecated( + since='0.15.2', + removal='0.17.0', + name='pytz', + obj_type='attribute', + alternative='tz', + ) return pytz.timezone(str(self._zoneinfo)) @classmethod diff --git a/pvlib/solarposition.py b/pvlib/solarposition.py index 501daa1c21..cd87797bbe 100644 --- a/pvlib/solarposition.py +++ b/pvlib/solarposition.py @@ -1360,11 +1360,11 @@ def hour_angle(times, longitude, equation_of_time): Corresponding timestamps, must be localized to the timezone for the ``longitude``. - A `pytz.exceptions.AmbiguousTimeError` will be raised if any of the - given times are on a day when the local daylight savings transition - happens at midnight. If you're working with such a timezone, - consider converting to a non-DST timezone (e.g. GMT-4) before - calling this function. + An error (AmbiguousTimeError in older pandas, ValueError in newer) + will be raised if any of the given times are on a day when the local + daylight savings transition happens at midnight. If you're working + with such a timezone, consider converting to a non-DST timezone + (e.g. GMT-4) before calling this function. longitude : numeric Longitude in degrees equation_of_time : numeric diff --git a/pvlib/tools.py b/pvlib/tools.py index 6cb631f852..1f92b32ec9 100644 --- a/pvlib/tools.py +++ b/pvlib/tools.py @@ -4,11 +4,12 @@ import contextlib import datetime as dt +from datetime import timezone import warnings import numpy as np import pandas as pd -import pytz +import zoneinfo def cosd(angle): @@ -135,8 +136,8 @@ def localize_to_utc(time, location): """ if isinstance(time, dt.datetime): if time.tzinfo is None: - time = location.pytz.localize(time) - time_utc = time.astimezone(pytz.utc) + time = time.replace(tzinfo=location._zoneinfo) + time_utc = time.astimezone(timezone.utc) else: try: time_utc = time.tz_convert('UTC') @@ -162,11 +163,11 @@ def datetime_to_djd(time): """ if time.tzinfo is None: - time_utc = pytz.utc.localize(time) + time_utc = time.replace(tzinfo=timezone.utc) else: - time_utc = time.astimezone(pytz.utc) + time_utc = time.astimezone(timezone.utc) - djd_start = pytz.utc.localize(dt.datetime(1899, 12, 31, 12)) + djd_start = dt.datetime(1899, 12, 31, 12, tzinfo=timezone.utc) djd = (time_utc - djd_start).total_seconds() * 1.0/(60 * 60 * 24) return djd @@ -189,10 +190,10 @@ def djd_to_datetime(djd, tz='UTC'): The resultant datetime localized to tz """ - djd_start = pytz.utc.localize(dt.datetime(1899, 12, 31, 12)) + djd_start = dt.datetime(1899, 12, 31, 12, tzinfo=timezone.utc) utc_time = djd_start + dt.timedelta(days=djd) - return utc_time.astimezone(pytz.timezone(tz)) + return utc_time.astimezone(zoneinfo.ZoneInfo(tz)) def _pandas_to_doy(pd_object): diff --git a/tests/iotools/test_midc.py b/tests/iotools/test_midc.py index 636550d23c..78a642736e 100644 --- a/tests/iotools/test_midc.py +++ b/tests/iotools/test_midc.py @@ -1,6 +1,5 @@ import pandas as pd import pytest -import pytz from pvlib.iotools import midc from tests.conftest import TESTS_DATA_DIR, RERUNS, RERUNS_DELAY diff --git a/tests/test_clearsky.py b/tests/test_clearsky.py index 687dd9133e..638dfb0bc5 100644 --- a/tests/test_clearsky.py +++ b/tests/test_clearsky.py @@ -3,7 +3,7 @@ import numpy as np from numpy import nan import pandas as pd -import pytz +import zoneinfo from scipy.linalg import hankel import pytest @@ -770,7 +770,7 @@ def test_bird(): times = pd.date_range(start='1/1/2015 0:00', end='12/31/2015 23:00', freq='h') tz = -7 # test timezone - gmt_tz = pytz.timezone('Etc/GMT%+d' % -(tz)) + gmt_tz = zoneinfo.ZoneInfo(f'Etc/GMT{-tz:+d}') # noqa: E231 times = times.tz_localize(gmt_tz) # set timezone times_utc = times.tz_convert('UTC') # match test data from BIRD_08_16_2012.xls diff --git a/tests/test_location.py b/tests/test_location.py index 36d71e30be..df1bce8756 100644 --- a/tests/test_location.py +++ b/tests/test_location.py @@ -9,8 +9,6 @@ import pytest -import pytz - import pvlib from pvlib import location from pvlib.location import Location, lookup_altitude @@ -37,7 +35,7 @@ def test_location_all(): 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(zoneinfo.ZoneInfo('US/Arizona'), 'US/Arizona'), pytest.param(-6, 'Etc/GMT+6'), pytest.param(-11.0, 'Etc/GMT+11'), pytest.param(12, 'Etc/GMT-12'), @@ -45,8 +43,7 @@ def test_location_all(): ) def test_location_tz(tz, tz_expected): loc = Location(32.2, -111, tz) - assert isinstance(loc.pytz, datetime.tzinfo) # Abstract base class. - assert isinstance(loc.pytz, pytz.tzinfo.BaseTzInfo) + assert isinstance(loc._zoneinfo, datetime.tzinfo) # Abstract base class. assert type(loc.tz) is str assert loc.tz == tz_expected @@ -54,12 +51,10 @@ def test_location_tz(tz, tz_expected): def test_location_tz_update(): loc = Location(32.2, -111, -11) assert loc.tz == 'Etc/GMT+11' - assert loc.pytz == pytz.timezone('Etc/GMT+11') # Deprecated attribute. # Updating Location's tz updates read-only time-zone attributes. loc.tz = 7 assert loc.tz == 'Etc/GMT-7' - assert loc.pytz == pytz.timezone('Etc/GMT-7') # Deprecated attribute. @pytest.mark.parametrize( @@ -99,8 +94,8 @@ def test_location_print_all(): assert tus.__str__() == expected_str -def test_location_print_pytz(): - tus = Location(32.2, -111, pytz.timezone('US/Arizona'), 700, 'Tucson') +def test_location_print(): + tus = Location(32.2, -111, zoneinfo.ZoneInfo('US/Arizona'), 700, 'Tucson') expected_str = '\n'.join([ 'Location: ', ' name: Tucson', diff --git a/tests/test_solarposition.py b/tests/test_solarposition.py index a6cf6b4819..904062523e 100644 --- a/tests/test_solarposition.py +++ b/tests/test_solarposition.py @@ -1,21 +1,20 @@ import calendar import datetime +import math import warnings +import zoneinfo +from datetime import timezone import numpy as np import pandas as pd - -from .conftest import assert_frame_equal, assert_series_equal -from numpy.testing import assert_allclose import pytest -import pytz +from numpy.testing import assert_allclose -from pvlib.location import Location from pvlib import solarposition, spa +from pvlib.location import Location -from .conftest import ( - requires_ephem, requires_spa_c, requires_numba, requires_pandas_2_0 -) +from .conftest import (assert_frame_equal, assert_series_equal, requires_ephem, + requires_numba, requires_pandas_2_0, requires_spa_c) # setup times and locations to be tested. times = pd.date_range(start=datetime.datetime(2014, 6, 24), @@ -343,29 +342,26 @@ def test_pyephem_physical_dst(expected_solpos, golden): @requires_ephem def test_calc_time(): - import pytz - import math # validation from USNO solar position calculator online - epoch = datetime.datetime(1970, 1, 1) - epoch_dt = pytz.utc.localize(epoch) + epoch = datetime.datetime(1970, 1, 1, tzinfo=timezone.utc) loc = tus loc.pressure = 0 - actual_time = pytz.timezone(loc.tz).localize( - datetime.datetime(2014, 10, 10, 8, 30)) - lb = pytz.timezone(loc.tz).localize(datetime.datetime(2014, 10, 10, tol)) - ub = pytz.timezone(loc.tz).localize(datetime.datetime(2014, 10, 10, 10)) + tz = zoneinfo.ZoneInfo(loc.tz) + actual_time = datetime.datetime(2014, 10, 10, 8, 30, tzinfo=tz) + lb = datetime.datetime(2014, 10, 10, tol, tzinfo=tz) + ub = datetime.datetime(2014, 10, 10, 10, tzinfo=tz) alt = solarposition.calc_time(lb, ub, loc.latitude, loc.longitude, 'alt', math.radians(24.7)) az = solarposition.calc_time(lb, ub, loc.latitude, loc.longitude, 'az', math.radians(116.3)) - actual_timestamp = (actual_time - epoch_dt).total_seconds() + actual_timestamp = (actual_time - epoch).total_seconds() assert_allclose((alt.replace(second=0, microsecond=0) - - epoch_dt).total_seconds(), actual_timestamp) + epoch).total_seconds(), actual_timestamp) assert_allclose((az.replace(second=0, microsecond=0) - - epoch_dt).total_seconds(), actual_timestamp) + epoch).total_seconds(), actual_timestamp) @requires_ephem @@ -715,6 +711,15 @@ def test_hour_angle_with_tricky_timezones(): # GH 2132 # tests timezones that have a DST shift at midnight + try: # transitive dependency to pytz through pandas < 3 + import pytz + _NonExistentTimeError = pytz.exceptions.NonExistentTimeError + _AmbiguousTimeError = pytz.exceptions.AmbiguousTimeError + except ImportError: # pragma: no cover + # pandas 3.x dropped pytz; these are now raised as ValueError + _NonExistentTimeError = ValueError + _AmbiguousTimeError = ValueError + eot = np.array([-3.935172, -4.117227, -4.026295, -4.026295]) longitude = 70.6693 @@ -726,7 +731,7 @@ def test_hour_angle_with_tricky_timezones(): ]).tz_localize('America/Santiago', nonexistent='shift_forward') with pytest.raises(( - pytz.exceptions.NonExistentTimeError, # pandas 1.x, 2.x + _NonExistentTimeError, # pandas 1.x, 2.x ValueError, # pandas 3.x )): times.normalize() @@ -743,7 +748,7 @@ def test_hour_angle_with_tricky_timezones(): ]).tz_localize('America/Havana', ambiguous=[True, True, False, False]) with pytest.raises(( - pytz.exceptions.AmbiguousTimeError, # pandas 1.x, 2.x + _AmbiguousTimeError, # pandas 1.x, 2.x ValueError, # pandas 3.x )): solarposition.hour_angle(times, longitude, eot) From 6e9046891a83385daebe5a1d09ff82523047a71c Mon Sep 17 00:00:00 2001 From: Johann Lo <65318981+JoLo90@users.noreply.github.com> Date: Thu, 21 May 2026 22:13:22 +0200 Subject: [PATCH 2/9] docs: whatsnew --- docs/sphinx/source/whatsnew/v0.15.2.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/sphinx/source/whatsnew/v0.15.2.rst b/docs/sphinx/source/whatsnew/v0.15.2.rst index 30ba7875f0..2682e37baf 100644 --- a/docs/sphinx/source/whatsnew/v0.15.2.rst +++ b/docs/sphinx/source/whatsnew/v0.15.2.rst @@ -11,7 +11,7 @@ Breaking Changes Deprecations ~~~~~~~~~~~~ * ``Location.pytz`` is deprecated. Use ``Location.tz`` instead. - (:ghuser:`JoLo90`, :pull:`2757`) + (:issue:`2343`, :pull:`2757`) Bug fixes @@ -64,3 +64,5 @@ Contributors * Cliff Hansen (:ghuser:`cwhanse`) * Arthur Onno (:ghuser:`ArthurOnnoTerabase`) * Adam R. Jensen (:ghuser:`AdamRJensen`) +* :ghuser:`JoLo90` + From 6ce566e6fab04b64f3b643284030f3f26d0ac9fe Mon Sep 17 00:00:00 2001 From: Johann Lo <65318981+JoLo90@users.noreply.github.com> Date: Fri, 22 May 2026 08:59:43 +0200 Subject: [PATCH 3/9] doc: deprecated in pytz property Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> --- pvlib/location.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pvlib/location.py b/pvlib/location.py index 221dd05837..b79b7b34d4 100644 --- a/pvlib/location.py +++ b/pvlib/location.py @@ -27,6 +27,8 @@ class Location: * ``tz`` is an IANA time-zone string. + .. deprecated:: 0.15.2 + The ``pytz`` attribute is deprecated. Use ``tz`` instead. Location objects support the print method. From a3a030f9ce1d2315addeebb86f99ba0f606f40db Mon Sep 17 00:00:00 2001 From: Johann Lo <65318981+JoLo90@users.noreply.github.com> Date: Fri, 22 May 2026 09:00:30 +0200 Subject: [PATCH 4/9] docs: error comments Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> --- pvlib/solarposition.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/solarposition.py b/pvlib/solarposition.py index cd87797bbe..2878f41cf6 100644 --- a/pvlib/solarposition.py +++ b/pvlib/solarposition.py @@ -1360,7 +1360,7 @@ def hour_angle(times, longitude, equation_of_time): Corresponding timestamps, must be localized to the timezone for the ``longitude``. - An error (AmbiguousTimeError in older pandas, ValueError in newer) + An error (``AmbiguousTimeError`` in older pandas, ``ValueError`` in newer) will be raised if any of the given times are on a day when the local daylight savings transition happens at midnight. If you're working with such a timezone, consider converting to a non-DST timezone From 2f58cc6c24283f8f970a93ad468f84fb78354563 Mon Sep 17 00:00:00 2001 From: Johann Lo <65318981+JoLo90@users.noreply.github.com> Date: Fri, 22 May 2026 09:34:11 +0200 Subject: [PATCH 5/9] test: add deprecation check on pytz property --- tests/test_location.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tests/test_location.py b/tests/test_location.py index df1bce8756..519afcb740 100644 --- a/tests/test_location.py +++ b/tests/test_location.py @@ -5,7 +5,8 @@ import numpy as np from numpy import nan import pandas as pd -from .conftest import assert_frame_equal, assert_index_equal +from .conftest import assert_frame_equal, assert_index_equal, fail_on_pvlib_version +from pvlib._deprecation import pvlibDeprecationWarning import pytest @@ -20,9 +21,9 @@ def test_location_required(): Location(32.2, -111) - -def test_location_all(): - Location(32.2, -111, 'US/Arizona', 700, 'Tucson') +@pytest.fixture() +def some_location() -> Location: + return Location(32.2, -111, 'US/Arizona', 700, 'Tucson') @pytest.mark.parametrize( @@ -390,3 +391,9 @@ def test_location_lookup_altitude(mocker): tus = Location(32.2, -111, 'US/Arizona') location.lookup_altitude.assert_called_once_with(32.2, -111) assert tus.altitude == location.lookup_altitude(32.2, -111) + + +@fail_on_pvlib_version('0.17.0') +def test_location_pytz_warning(some_location): + with pytest.warns(pvlibDeprecationWarning): + assert str(some_location.pytz) == 'US/Arizona' \ No newline at end of file From 05d2781930bcc3d16a8fe76e261dd7b3a94e5281 Mon Sep 17 00:00:00 2001 From: Johann Lo <65318981+JoLo90@users.noreply.github.com> Date: Fri, 22 May 2026 09:38:36 +0200 Subject: [PATCH 6/9] fix: avoid using internal property _zoneinfo --- pvlib/tools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/tools.py b/pvlib/tools.py index 1f92b32ec9..1d9db70369 100644 --- a/pvlib/tools.py +++ b/pvlib/tools.py @@ -136,7 +136,7 @@ def localize_to_utc(time, location): """ if isinstance(time, dt.datetime): if time.tzinfo is None: - time = time.replace(tzinfo=location._zoneinfo) + time = time.replace(tzinfo=zoneinfo.ZoneInfo(location.tz)) time_utc = time.astimezone(timezone.utc) else: try: From dd89c33efe357eebfc05de5777e34406b226f537 Mon Sep 17 00:00:00 2001 From: Johann Lo <65318981+JoLo90@users.noreply.github.com> Date: Fri, 22 May 2026 10:02:36 +0200 Subject: [PATCH 7/9] docs: timezone location description Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> --- pvlib/location.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pvlib/location.py b/pvlib/location.py index b79b7b34d4..caac9f6835 100644 --- a/pvlib/location.py +++ b/pvlib/location.py @@ -23,9 +23,7 @@ class Location: time zone, and altitude data associated with a particular geographic location. You can also assign a name to a location object. - Location objects have a time-zone attribute: - - * ``tz`` is an IANA time-zone string. + Location objects have a time-zone attribute ``tz``, an IANA time-zone string. .. deprecated:: 0.15.2 From 15e60b00d1bffea4ba46ee4e3e37f817907f7cd5 Mon Sep 17 00:00:00 2001 From: Johann Lo <65318981+JoLo90@users.noreply.github.com> Date: Fri, 22 May 2026 10:03:07 +0200 Subject: [PATCH 8/9] docs: version deprecation in pytz Co-authored-by: Echedey Luis <80125792+echedey-ls@users.noreply.github.com> --- pvlib/location.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pvlib/location.py b/pvlib/location.py index caac9f6835..bd2949ed58 100644 --- a/pvlib/location.py +++ b/pvlib/location.py @@ -132,7 +132,7 @@ def tz(self, tz_): def pytz(self): # pragma: no cover """The location's pytz time zone (read only). - .. deprecated:: + .. deprecated:: 0.15.2 The ``pytz`` attribute is deprecated. Use the ``tz`` property instead. """ From dac983ee7f4f766a26da0e657e8fd42455f450c8 Mon Sep 17 00:00:00 2001 From: Johann Lo <65318981+JoLo90@users.noreply.github.com> Date: Fri, 22 May 2026 11:01:36 +0200 Subject: [PATCH 9/9] lint: flake8 lint --- pvlib/location.py | 2 +- pvlib/solarposition.py | 2 +- tests/test_location.py | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pvlib/location.py b/pvlib/location.py index bd2949ed58..e5568db529 100644 --- a/pvlib/location.py +++ b/pvlib/location.py @@ -23,7 +23,7 @@ class Location: time zone, and altitude data associated with a particular geographic location. You can also assign a name to a location object. - Location objects have a time-zone attribute ``tz``, an IANA time-zone string. + Location objects have a time-zone attribute ``tz`` (IANA timezone string). .. deprecated:: 0.15.2 diff --git a/pvlib/solarposition.py b/pvlib/solarposition.py index 2878f41cf6..7a0d5e4196 100644 --- a/pvlib/solarposition.py +++ b/pvlib/solarposition.py @@ -1360,7 +1360,7 @@ def hour_angle(times, longitude, equation_of_time): Corresponding timestamps, must be localized to the timezone for the ``longitude``. - An error (``AmbiguousTimeError`` in older pandas, ``ValueError`` in newer) + ``AmbiguousTimeError`` in older pandas, ``ValueError`` in newer will be raised if any of the given times are on a day when the local daylight savings transition happens at midnight. If you're working with such a timezone, consider converting to a non-DST timezone diff --git a/tests/test_location.py b/tests/test_location.py index 519afcb740..b2f780fcfc 100644 --- a/tests/test_location.py +++ b/tests/test_location.py @@ -5,7 +5,8 @@ import numpy as np from numpy import nan import pandas as pd -from .conftest import assert_frame_equal, assert_index_equal, fail_on_pvlib_version +from .conftest import (assert_frame_equal, assert_index_equal, + fail_on_pvlib_version) from pvlib._deprecation import pvlibDeprecationWarning import pytest @@ -21,6 +22,7 @@ def test_location_required(): Location(32.2, -111) + @pytest.fixture() def some_location() -> Location: return Location(32.2, -111, 'US/Arizona', 700, 'Tucson') @@ -396,4 +398,4 @@ def test_location_lookup_altitude(mocker): @fail_on_pvlib_version('0.17.0') def test_location_pytz_warning(some_location): with pytest.warns(pvlibDeprecationWarning): - assert str(some_location.pytz) == 'US/Arizona' \ No newline at end of file + assert str(some_location.pytz) == 'US/Arizona'