Skip to content

Perform dayofyear-based calculations according to UTC, not local time#2055

Merged
kandersolar merged 55 commits into
pvlib:mainfrom
yhkee0404:clearsky-timezone
Sep 24, 2024
Merged

Perform dayofyear-based calculations according to UTC, not local time#2055
kandersolar merged 55 commits into
pvlib:mainfrom
yhkee0404:clearsky-timezone

Conversation

@yhkee0404

@yhkee0404 yhkee0404 commented May 19, 2024

Copy link
Copy Markdown
Contributor

A similar solution as #333

@yhkee0404
yhkee0404 marked this pull request as ready for review May 19, 2024 22:33
@yhkee0404 yhkee0404 changed the title Clearsky timezone Fix tz-naive linke_turbidity and dni_extra to be tz-aware May 19, 2024
@yhkee0404 yhkee0404 closed this May 26, 2024
@yhkee0404
yhkee0404 deleted the clearsky-timezone branch May 26, 2024 02:53
@yhkee0404
yhkee0404 restored the clearsky-timezone branch May 26, 2024 03:17
@yhkee0404 yhkee0404 reopened this May 26, 2024
@yhkee0404
yhkee0404 force-pushed the clearsky-timezone branch from f4d42e8 to 6d1ab57 Compare May 26, 2024 05:54
Comment thread pvlib/clearsky.py Outdated
Comment thread pvlib/irradiance.py
Comment thread docs/sphinx/source/whatsnew/v0.11.0.rst Outdated
Comment thread pvlib/tests/test_irradiance.py Outdated
Comment thread pvlib/tests/test_irradiance.py Outdated
Comment thread pvlib/tools.py
Comment thread pvlib/tools.py
Comment thread pvlib/tools.py Outdated
Co-authored-by: Cliff Hansen <cwhanse@sandia.gov>
@yhkee0404 yhkee0404 closed this Jun 5, 2024
@cwhanse

cwhanse commented Jun 5, 2024

Copy link
Copy Markdown
Member

@yhkee0404 did you close this intentionally? If you aren't able to complete the PR, let us know and one of us could take it from here.

@yhkee0404

yhkee0404 commented Jun 5, 2024

Copy link
Copy Markdown
Contributor Author

@cwhanse Oh, sorry for confusion. I was in the midst of my struggle with the problem and was going to reopen it after several hours. Thank you for your suggestions! Now I think it is better to keep it open. Any help would be welcome!

@yhkee0404 yhkee0404 reopened this Jun 5, 2024
@yhkee0404
yhkee0404 force-pushed the clearsky-timezone branch from 28a94d5 to fe5b5c1 Compare June 5, 2024 22:58

@kandersolar kandersolar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @yhkee0404 for this thorough PR! I have a few questions below that I hope you can help me understand.

I also think the title of this PR should be edited to reflect the broader scope of the changes.

Comment thread docs/examples/irradiance-transposition/plot_seasonal_tilt.py Outdated
Comment thread benchmarks/benchmarks/solarposition.py Outdated
Comment thread pvlib/iotools/solrad.py
Comment thread pvlib/solarposition.py
Comment on lines +1385 to -1391
# times must be localized
if not times.tz:
raise ValueError('times must be localized')

# hours - timezone = (times - normalized_times) - (naive_times - times)
if times.tz is None:
times = times.tz_localize('utc')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I agree with this change. The docstring says the input timestamps "must be localized to the timezone for the longitude", which is inconsistent with the previous behavior (localize to UTC if not already localized), so I can see some change being needed here. But why is this the correct change?

@yhkee0404 yhkee0404 Sep 6, 2024

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was added in accordance with sun_rise_set_transit_spa and sun_rise_set_transit_ephem as well as the docstring. I agree with the previous convention of raising a ValueError since it prevents users from unwittingly calling the functions naively without assuming any timezones and ignoring the fact that an hour angle is counted up from zero at noon in a predefined local timezone. Please refer to the followings:

# times must be localized
if times.tz:
tzinfo = times.tz
else:
raise ValueError('times must be localized')

# times must be localized
if times.tz:
tzinfo = times.tz
else:
raise ValueError('times must be localized')

Comment thread pvlib/tests/test_solarposition.py
Co-authored-by: Kevin Anderson <kevin.anderso@gmail.com>
@yhkee0404

yhkee0404 commented Sep 6, 2024

Copy link
Copy Markdown
Contributor Author

Many thanks to @cwhanse for leading this PR into the right way, and @kandersolar for taking time for a further reconciliation from other aspects! Please feel free to fix or revert any including the title or whatsnew with your excellent ideas.

@cwhanse

cwhanse commented Sep 11, 2024

Copy link
Copy Markdown
Member

@yhkee0404 we should add a few tests to improve coverage. Let me know if you would like my help with that.

@yhkee0404

yhkee0404 commented Sep 12, 2024

Copy link
Copy Markdown
Contributor Author

@cwhanse I have just made some patchs to improve coverage but I am not sure they would work. I would really appreciate if you could please help me. This is my first time to work with Codecov. Is there a way to see the difference locally on my own, or should I just wait for your manual approval for codecov workflow?

@cwhanse

cwhanse commented Sep 12, 2024

Copy link
Copy Markdown
Member

@yhkee0404 the additional tests are good enough. I don't see why codecov is flagging that one line. Like you I don't know how to run codecov locally, and just let the CI do it for me.

@yhkee0404

yhkee0404 commented Sep 13, 2024

Copy link
Copy Markdown
Contributor Author

Great! It seems calling solarposition.spa_c in test_spa_c_physical and test_spa_c_physical_dst on pvlib/tests/test_solarposition.py both fail on Codecov because of lack of spa_c_files which makes these lines fail accordingly: from pvlib.spa_c_files.spa_py import spa_calc, has_spa_c and requires_spa_c. It is different from the case of other libraries like ephem and numba since both has_ephem and has_numba are True on Codecov while has_spa_c() is evaluated as False: https://app.codecov.io/gh/pvlib/pvlib-python/pull/1944/blob/pvlib/tests/conftest.py#L136 In another word, to test spa_c which is not imported, we should install it on Codecov somehow like this direction: https://pvlib-python.readthedocs.io/en/stable/user_guide/installation.html?highlight=spa_c_files#nrel-spa-algorithm

@kandersolar kandersolar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I have finally understood this PR. It it looks correct to me. I have only a couple revisions to the what's new text to fully communicate the changes.

In another word, to test spa_c which is not imported, we should install it on Codecov somehow like this direction

Unfortunately, licensing reasons prevent us from testing the spa_c code in CI. Any coverage issues related to spa_c should be ignored :)

Comment thread docs/sphinx/source/whatsnew/v0.11.1.rst Outdated
Comment thread docs/sphinx/source/whatsnew/v0.11.1.rst Outdated
@kandersolar kandersolar changed the title Fix tz-naive linke_turbidity and dni_extra to be tz-aware Perform dayofyear-based calculations according to UTC, not local time Sep 17, 2024
@yhkee0404

Copy link
Copy Markdown
Contributor Author

Thank you for your thorough review and suggestion that clarifies this PR in more datail👍!

@kandersolar kandersolar mentioned this pull request Sep 23, 2024
11 tasks
@kandersolar
kandersolar merged commit d45790a into pvlib:main Sep 24, 2024
@kandersolar

Copy link
Copy Markdown
Member

Thanks again @yhkee0404 for finding, investigating, and fixing this complex issue!

cwhanse pushed a commit that referenced this pull request Jul 16, 2026
…2820)

sun_rise_set_transit_spa normalized timestamps to midnight *after*
converting to UTC (introduced in v0.11.1 by #2055). An evening-local
timestamp is the next calendar day in UTC, so its day of interest was
shifted forward and the function returned the following day's
sunrise, sunset, and transit.

Use the input's local calendar date as the day of interest, restoring
the pre-v0.11.1 behavior. The SPA routine requires 00:00 UTC input, so
the local date is re-labeled (not converted) to UTC. The timezone label
is stripped before normalize() so truncation runs on a naive index:
normalizing a tz-aware index would build local midnight, which does not
exist (spring-forward) or is ambiguous (fall-back) on DST-transition
days and would raise. This yields unixtimes byte-for-byte identical to
the v0.11.0 implementation for all valid inputs. Adds an inline comment
explaining the timezone handling (requested in the issue) and a
regression test covering negative and positive offsets and a
midnight-DST zone.

Fixes #2238

This change was drafted with AI assistance (Claude); all AI-generated
material has been vetted for accuracy and is license-compliant.

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clearsky functions handling tz-aware datetimes as tz-naive, contrary to user guide

4 participants