Enable with features = ["jiff"]. Bundles the IANA timezone database (tzdb-bundle-always) β€” no system tzdata required. Coexists with the time feature.

πŸ”—Type mapping

Rust typeR typeNotes
jiff::TimestampPOSIXct (UTC)Nanosecond precision
jiff::ZonedPOSIXct + tzone attrIANA name round-tripped
jiff::civil::DateDateDays since 1970-01-01
jiff::SignedDurationdifftime (secs)Signed, nanosecond precision
jiff::SpanExternalPtrVia RSpan adapter trait
jiff::civil::DateTimeExternalPtrVia RDateTime adapter trait
jiff::civil::TimeExternalPtrVia RTime adapter trait

All scalar types support Option<T>, Vec<T>, and Vec<Option<T>> variants.

πŸ”—Timezone policy

  • Zoned β†’ R: writes the IANA name from time_zone().iana_name() into the tzone attribute. Fixed-offset zones without an IANA name fall back to "UTC".
  • R β†’ Zoned: unknown tzone β†’ SexpError::InvalidValue. No silent UTC fallback β€” unlike the time feature, jiff can represent real IANA zones, so losing them is an error.
  • Empty or missing tzone: treated as UTC.
  • Vec<Zoned> β†’ R: a single tzone attribute applies to the whole vector; the first element’s timezone is used. Mixed-timezone vectors log a warning (requires log feature).

πŸ”—Fractional seconds

Floor-based split into whole seconds + nanoseconds, matching time_impl.rs. Correct for negative timestamps: -1.2s β†’ -2s + 800_000_000ns.

πŸ”—Adapter traits

For types with no base-R scalar analog, wrap in #[derive(ExternalPtr)] and implement the relevant trait:

  • RSpan β€” component getters (years/months/weeks/days/hours/minutes/seconds/ms/Β΅s/ns), is_zero, is_negative, negate, abs
  • RDateTime β€” year/month/day/hour/minute/second, to_date, to_time, in_tz
  • RTime β€” hour/minute/second/subsec_nanosecond, on
  • RTimestamp β€” as_second, as_millisecond, subsec_nanosecond, to_zoned_in, strftime
  • RZoned β€” year/month/day/hour/minute/second, iana_name, in_tz, start_of_day, strftime
  • RDate β€” year/month/day/weekday/day_of_year, first_of_month, last_of_month, tomorrow, yesterday, strftime
  • RSignedDuration β€” as_seconds_f64, as_milliseconds, whole_seconds/minutes/hours/days, subsec_nanoseconds, is_negative, is_zero, abs

πŸ”—ALTREP

JiffTimestampVec β€” lazy REALSXP backed by Arc<Vec<Timestamp>>. Elements are projected to seconds-since-epoch on access; no upfront conversion. Apply POSIXct class after construction.

JiffZonedVec β€” lazy REALSXP backed by Arc<Vec<Zoned>>, single-timezone strict. Constructor (JiffZonedVec::new) validates that all elements share the same IANA timezone name; returns Err if any element differs. On success, into_sexp() produces a POSIXct ALTREP with class = c("POSIXct", "POSIXt") and tzone = <iana>. TryFromSexp reconstructs each element using the SEXP’s tzone attribute.

πŸ”—vctrs rcrd constructors

Requires features = ["jiff", "vctrs"]. Public helpers in jiff_impl::vctrs_support:

  • span_vec_to_rcrd(&[Span]) -> SEXP β€” fields: years/months/weeks/days/hours/minutes/seconds/ms/Β΅s/ns (all INTSXP)
  • zoned_vec_to_rcrd(&[Zoned]) -> SEXP β€” fields: timestamp (REALSXP, seconds-since-epoch), tz (STRSXP)
  • datetime_vec_to_rcrd(&[DateTime]) -> SEXP β€” fields: year/month/day/hour/minute/second/subsec_nanosecond
  • time_vec_to_rcrd(&[Time]) -> SEXP β€” fields: hour/minute/second/subsec_nanosecond

All constructors return vctrs rcrd SEXPs with class c("<type>", "vctrs_rcrd", "vctrs_vctr").

πŸ”—Follow-ups

  • #305 β€” expand adapter-trait test coverage (formatting/arithmetic methods, ALTREP laziness counter)