Skip to content

Document the index convention of read_epw - #2894

Open
cdeil wants to merge 3 commits into
pvlib:mainfrom
cdeil:epw-index-convention
Open

cdeil wants to merge 3 commits into
pvlib:mainfrom
cdeil:epw-index-convention

Conversation

@cdeil

@cdeil cdeil commented Oct 9, 2026 •

Copy link
Copy Markdown

read_epw labels hourly EPW records with the start of the hour, while read_tmy3 uses end-of-hour labels. This PR documents that distinction and the one-hour index shift for users who want labels matching the EPW file time. It does not change parser behavior.

The warning distinguishes radiation totals and illuminance averages over an interval from temperature, humidity and pressure observations at the file time. Shifting the index retains every record, including the final timestamp at midnight on 1 January of the following year.

This incorporates the requested review wording and US “labeled” spelling in the v0.16.2 release note. Current main is merged, resolving the release-note conflict while preserving its other entries and contributors. The longer-term API discussion remains in #1156; this documentation-only PR does not close it.

Validation of the updated tree:

  • pytest tests/iotools/test_epw.py -q -p no:cacheprovider -m 'not remote_data': 3 passed, 1 remote-data case deselected.
  • Strict scoped Sphinx 7.3.7 build of the edited docstring and complete v0.16.2 notes: passed. The full gallery/docs build was not run.
  • Executable Python code is unchanged; the index-shift control preserves all 8,760 rows and values.

read_epw labels each EPW record with the start of its hour (EPW hour 1
becomes 00:00), while read_tmy3 labels each record with the end of its
hour, so the same data read from an EPW and a TMY3 file are one hour
apart. Say so in a warning, as read_tmy3 does, and show how to label
the records with the time given in the EPW file. See pvlib#1156.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown

Hey @cdeil! 🎉

Thanks for opening your first pull request! We appreciate your
contribution. Please ensure you have reviewed and understood the
contributing guidelines.

If AI is used for any portion of this PR, you must vet the content
for technical accuracy.

Finally, be sure the PR description includes the PR
checklist,
and complete the items you are able to.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@RDaxini RDaxini 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.

A docs-only change was never agreed in #1156 as an appropriate solution. Your own thoughts on the questions raised in the original issue regarding read_epw and end-of-hour labels would be welcome. A discussion there (in the issue thread) first, leading to a more comprehensive and lasting fix, could be more helpful.

Having said all that, thanks for your contribution. The docstring clarification is still useful, at least in the interim. I have recommended some wording revisions, but other than that this LGTM.

I'd leave #1156 open since this PR does not resolve it.

Comment thread pvlib/iotools/epw.py Outdated
Comment on lines +211 to +221
.. warning:: EPW irradiance and illuminance values are totals over the
hour *ending* at the time in the file, while temperatures, humidity
and pressure are values *at* that time [1]_. ``read_epw`` labels
each record with the *start* of its hour: EPW hour 1 (00:00-01:00)
becomes 00:00, so a full year runs from 00:00 on 1 January to 23:00
on 31 December. :py:func:`~pvlib.iotools.read_tmy3` labels each record
with the *end* of its hour instead, so the same data read from an EPW
file and from a TMY3 file are one hour apart. To label the records
with the time given in the EPW file, add one hour to the index:
``data.index = data.index + pd.Timedelta('1h')``.

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.

As far as I understand, illuminance values are averages, not totals.
Suggested some minor clarification regarding time labels and year-end record too.

Suggested change
.. warning:: EPW irradiance and illuminance values are totals over the
hour *ending* at the time in the file, while temperatures, humidity
and pressure are values *at* that time [1]_. ``read_epw`` labels
each record with the *start* of its hour: EPW hour 1 (00:00-01:00)
becomes 00:00, so a full year runs from 00:00 on 1 January to 23:00
on 31 December. :py:func:`~pvlib.iotools.read_tmy3` labels each record
with the *end* of its hour instead, so the same data read from an EPW
file and from a TMY3 file are one hour apart. To label the records
with the time given in the EPW file, add one hour to the index:
``data.index = data.index + pd.Timedelta('1h')``.
.. warning:: In hourly EPW files, radiation totals and illuminance
averages cover the hour *ending* at the file time; temperature,
humidity and pressure are values *at* that time [1]_.
``read_epw`` labels all fields with the *start* of the hour (EPW
hour 1 becomes 00:00), while :py:func:`~pvlib.iotools.read_tmy3`
uses the *end*.
To use end-of-hour labels, add one hour to the index:
``data.index = data.index + pd.Timedelta('1h')``. The record for
31 December's final hour then has the label 1 January 00:00 of
the following year. No records are added or removed.

Comment thread docs/sphinx/source/whatsnew/v0.16.2.rst Outdated
* Fix the :py:func:`pvlib.spa.solar_position` docstring, which listed
outputs ``elevation`` and ``apparent_elevation`` in the wrong order.
(:issue:`2886`, :pull:`2887`)
* Document in :py:func:`pvlib.iotools.read_epw` that each record is labelled

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.

pvlib uses US English

Suggested change
* Document in :py:func:`pvlib.iotools.read_epw` that each record is labelled
* Document in :py:func:`pvlib.iotools.read_epw` that each record is labeled

@RDaxini RDaxini added this to the v0.16.2 milestone Oct 12, 2026
Preserve current release notes and use the exact approved warning and US spelling.

Co-authored-by: Codex (GPT-6.1 Sol) <noreply@openai.com>
@cdeil

cdeil commented Nov 6, 2026

Copy link
Copy Markdown
Author

@RDaxini, thanks for the review! I’ve applied your feedback and resolved the merge conflict.

@RDaxini

RDaxini commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

@RDaxini, thanks for the review! I’ve applied your feedback and resolved the merge conflict.

Thanks for responding.
We will need to wait for the discussion in the associated issue to be resolved first before this can move forward.

If you don't mind me saying, as a side note, committing the review recommendations directly with a single click on the commit button on the comments in this PR would be far more energy efficient and reliable than using Chat GPT 6.1 Sol. I only recommended some basic documentation updates. Although these were related to technical accuracy, GPT 6.1 is an incredibly resource-expensive way to handle these suggestions. Your own personal review following by, if agreed upon, committing the human review suggestions (from me) also ensures the diff remains more easily traceable back to discussions, individuals/authorship, etc. Having a coding agent handle everything, including commits, with no oversight(?), is a slippery slope for open-source software. It may also be the cause of these lapses in technical accuracy that I highlighted in the review, which could easily have been avoided with domain-specific oversight of the AI output from a human, which is in fact required by the pvlib contributing guidelines.

Not the say that your contribution is not welcome, contributions are certainly welcome. This is just a personal opinion I wanted to share since we currently have a lot of people submitting AI PRs without providing the necessary technical oversight.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants