The help pages now say what every accessor returns, that duration_compare() takes a zoned relative_to, and which base R classes each constructor converts. They no longer cite sections of the internal design document.
A value that no constructor made is now a zutempo_type_error instead of a crash or a wrong result: a zoned_date_time() whose zone codes were dropped, kept at the wrong length or point past its zone table (as data.table::rbindlist() or diff() can leave them), an instant with a fractional part, a plain value outside its type’s range, and a duration whose fields are not ten doubles of one length or not a valid duration. d$hours <- 5 on a duration is a type error, as d[["hours"]] <- 5 was. The native routines also check the type and length of every argument.
Condition messages are marked as UTF-8, and an excerpt of the input that they quote is never cut inside a character.
The time zone file reader refuses an abbreviation index past the abbreviations, a UTC offset of a day or more, and a TZ rule abbreviation with characters other than letters, digits, + and -.
The zone cache is freed when the package’s DLL unloads, and loading the package again no longer adds a second copy of its vctrs and pillar hooks.
An error about an option argument has a field option with the argument’s name, so code can tell which option was wrong without reading the message: tryCatch(..., zutempo_error = function(e) e[["option"]]).
Operators on dates and times are a zutempo_type_error that names the function to use, such as temporal_add() or temporal_equals(). Before, base R’s operators ran on the stored numbers and gave wrong values (instant(x) + 0.5) or answers that disagreed with temporal_equals() (z1 == z2). min(), max() and range() return a value of the same type, in the order sort() uses; a plain_month_day() has no order, so they are errors there, as sum() and the others are on every type.
The system time zone reads TZ in the forms the C library accepts: a leading : is dropped, and a path under a zone directory names its zone. A zone that is set but cannot be read gives "UTC" with a zutempo_tz_warning, where before it gave "UTC" silently.
as.POSIXct() and as.POSIXlt() of a zoned value give an offset of -13:00 or -14:00 the tzone"UTC" rather than an Etc/GMT zone tzdata lacks, and keep the tzone of zones that are equal under TimeZoneEquals, such as Asia/Calcutta and Asia/Kolkata. The help page says that as.POSIXlt() of mixed zones does not round-trip.
Documentation: a README from Temporal to R, a table of every Temporal member and its R function on each type’s help page, ?zutempo_options for the options the functions share, and articles on the package website: “Get started”, following one zoned value from construction to base R, and articles on plain dates and times, durations, instants and time zones, strings and formatting, and base R and data frames.
Checked against test262’s Temporal tests (39,263 cases from 2,715 files) and against base R’s offsets for every zone. Fixes from that: the constructors read a zoned_date_time() (plain_date(z), plain_time(z), plain_date_time(z), instant(z)); relative_to = "-271821-04-19" works; temporal_since() and temporal_until() on year-months raise a range error when the first of a month is not a valid date; a time zone string whose offset has seconds is an error even when they are zero; and a duration field computed from a large total is the nearest double.
On macOS the time zone database is R’s own copy first, then the system’s, as base R reads it, so zutempo and POSIXct agree; TZDIR = "macOS" selects the system’s.
Operations on zoned values no longer look for the time zone database on every call: the directory is found once per setting of zutempo.tzdir and TZDIR, and again after zutempo_tz_reset(). Many short calls run several times faster.
Conversions with base R’s dates and times: as.Date(), as.POSIXct() and as.POSIXlt() on the zutempo types, temporal_to_difftime() for a plain_time() or duration(), and the other way through the constructors: plain_date(<Date>), instant(<POSIXct>), zoned_date_time(<POSIXct>), plain_date_time(<POSIXlt>), plain_time(<difftime>) and duration(<difftime>). A POSIXct is read at its double’s exact value, rounded half to even to the nanosecond, and written as the nearest double second.
Strings are read with every RFC 9557 annotation: any number of key-value annotations after the time zone, [u-ca=iso8601] in any case, and the ! critical flag, which makes an unknown annotation or a second calendar an error. A calendar other than ISO 8601 is a zutempo_range_error on the types with a date and is ignored by instant() and plain_time(), as in Temporal. A zutempo_parse_error carries position, the byte where the string failed. Time zone and calendar arguments take an ISO string that names one (time_zone = "2026-03-07T12:00+01:00").
temporal_to_string() and format() take the options of each type’s Temporal toString(): fractional_second_digits, smallest_unit and rounding_mode on the types with a time and on durations, calendar_name on the types with a date, and time_zone_name and offset on a zoned_date_time().
zutempo_parse(x, type) reads a character vector as any of the eight types, with NA for the strings it cannot read, and zutempo_parse_errors() lists them with their index, byte position, class and message.
Named IANA time zones resolve from the time zone database base R reads, in base R’s lookup order (option zutempo.tzdir, TZDIR, then the platform’s copies), on fat and slim files alike, with case-insensitive identifiers returned in the database’s case. temporal_to_string() on an instant() takes a named time_zone; zutempo_tz_reset() forgets the parsed zones; zutempo_info() reports the database’s directory, tzdata version and form (fat or slim) and the link table’s version. A named zone without a database is a zutempo_tz_error naming the directories tried.
zutempo_info() reports the package and zufast versions, whether the 128-bit arithmetic uses the compiler’s __int128, and the pinned commits of the Temporal specification and of test262 with the tzdata release the fixtures come from.
The condition classes of the design: zutempo_error, zutempo_range_error, zutempo_parse_error, zutempo_type_error and zutempo_tz_error, each carrying the index of the first failing element.