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 = ...).