Resubmission of 0.2.0, which CRAN's incoming checks rejected on 2026-09-08. Three problems, all now fixed.
write_cache() failed on Windows. The connection to the temporary file was
closed by on.exit(), which registers against the enclosing function's
frame rather than the tryCatch block, so the handle was still open when
file.rename() ran. Unix renames an open file without complaint; Windows
refuses, so every cache write silently returned FALSE on that platform.
The connection is now closed before the rename. This was invisible locally
and only surfaced on CRAN's Windows builder.
The DESCRIPTION cited the bare NCEI Data Service endpoint, which answers
HTTP 400 to a request with no query parameters and so reads as a broken
link. It now points at the NCEI API user documentation. The endpoint the
package actually calls is unchanged.
The README linked WMO guidance on library.wmo.int, a host that is
currently unreachable and returned an HTTP/2 protocol error. Replaced with
a plain citation to WMO-No. 1203, which cannot rot.
Every \donttest{} example that reaches the NCEI API is wrapped in try().
9 blocks were affected. CRAN runs these in its additional-issues
donttest check, on build machines the upstream host routinely refuses or
rate-limits, and an example that could not reach it was an ERROR rather
than a printed condition. The options(op) cache restore stays outside the
try() so it runs either way.
This is the CRAN Repository Policy requirement that a package using an internet resource fail gracefully when the resource is unavailable. It is the rule obr was archived under on 2026-08-22.
noaa_normals() works for all periods. period = "annual" requested
normals-annual-1991-2020, which NCEI does not recognise; the annual
normals are published as normals-annualseasonal-1991-2020.
period = "daily" sent no date window, which that dataset requires. Both
previously failed with HTTP 400 on every call, leaving "monthly" as the
only period that worked. period = "hourly" has been added.
Hourly datasets no longer lose their timestamps. global-hourly and
local-climatological-data publish ISO 8601 timestamps, which the date
parser did not recognise and silently converted to NA, discarding the
time axis of every hourly request. These now return a POSIXct column
in UTC.
Station identifiers are no longer corrupted. Values were type-guessed on
read, so ISD and GSOD identifiers with leading zeros lost them: Heathrow's
"03772099999" became the number 3772099999. All columns are now read as
character and coerced explicitly.
Requests for many stations no longer fail. The cache filename embedded the full station list, so a request for roughly fifteen or more stations exceeded the 255-character filename limit and aborted. Cache keys now use a readable prefix plus a digest, and stay within the limit for any request.
Empty responses are no longer cached. A request whose window ran past what NCEI had published was written to the cache and served from there indefinitely, so the missing days never appeared even after NOAA published them. Responses with no observations are now never cached, and an empty result returns a zero-row data frame instead of raising an error.
Missing elevations are NA rather than -999.9. The GHCN-Daily sentinel
value was returned as though it were a real measurement for 4,619 stations.
noaa_stations(text = ) matches literally. The search string was passed
straight to grepl() as a regular expression, so a name containing
punctuation such as "ST. LOUIS (" raised an invalid-regex error, and
metacharacters silently matched more than intended. Pass regex = TRUE
for the old behaviour.
API errors report what actually went wrong. A failed request reported only
its status code, discarding the explanation NCEI returns in the response
body, such as boundingBox: A bounding box is required.
list_datasets() no longer advertises noaa-global-surface-temperature,
which the data service rejects as an unsupported dataset. A requires
column records the datasets that need a date window or a bounding box.
Column names containing hyphens now use underscores rather than dots, so a
normals column matches the code that was requested: MLY-TAVG-NORMAL
returns as mly_tavg_normal.
Retries now cover HTTP 500, 502, and 504 alongside 429 and 503.
noaa_coverage() reports the first and last year of data for every
element a station records, from the GHCN-Daily element inventory. This
answers how current a station is before you request data from it, which
matters because coverage varies from a few days for US stations to over a
year for some international ones, and some listed stations stopped
reporting years ago.
noaa_stations() and noaa_nearby() accept element and active_since
to return only stations that record a given variable, or that were still
reporting in a given year.
cache_info() lists cached responses with their size and age.
All data functions accept refresh to bypass the cache for a single call.
Cached responses now expire. A request whose window reaches into the last
five weeks is treated as provisional and expires after one day, because
NCEI publishes recent observations with a lag and revises them; older
windows expire after 30 days. Previously nothing ever expired, so a result
fetched during the publication lag was served indefinitely. Configurable
through readnoaa.cache_days_recent and readnoaa.cache_days.
Cache writes are atomic, so an interrupted download cannot leave a truncated file that is later served as valid data.
Requests that do not name datatypes now drop columns containing no data
at all. An unfiltered daily-summaries request returned 152 columns of
which around 130 were entirely empty. Pass drop_empty = FALSE to keep
them.
list_datatypes() reports what a station actually records, read from the
element inventory, rather than the dataset's full column schema. It
previously reported 149 codes for a station recording about 20. It also
accepts start_date and end_date to show only elements recorded during a
window, and no longer probes a hard-coded week in 2024.
noaa_stations() and noaa_nearby() return the station metadata that was
previously discarded when parsing: state, gsn_flag, hcn_crn_flag,
and wmo_id.
Multi-year daily requests union their column sets across chunks rather than assuming every year returns the same elements.
noaa_normals() documents that the NCEI normals datasets are published in
US customary units and ignore the units parameter.
README station identifiers corrected. Five of the nine listed were wrong:
USW00014739 is Boston, not Chicago O'Hare (USW00094846); UKW00035054
is West Malling, not Heathrow (UKM00003772); UKE00105915 is Hampstead;
FRE00104898 does not exist (Paris-Montsouris is FRM00007156); and
Sydney Observatory Hill stopped reporting in 2020.
tempdir() instead of the user's home directory,
fixing CRAN policy compliance for \donttest examples.options(readnoaa.cache_dir = ...).