From e9448cc521f0e26a1e749bd09f0d6c85fc6e1592 Mon Sep 17 00:00:00 2001 From: Kevin Ness <46825870+nekevss@users.noreply.github.com> Date: Mon, 3 Feb 2025 19:46:59 -0600 Subject: [PATCH] Implement `ZonedDateTime::offset` and `ZonedDateTime::offset_nanoseconds` (#185) Per title, this implements the accessor methods for returning `ZonedDateTime`'s offset and offsetNanoseconds values. --- src/builtins/compiled/zoneddatetime.rs | 16 +++++++++ src/builtins/core/zoneddatetime.rs | 50 +++++++++++++++++++++++++- 2 files changed, 65 insertions(+), 1 deletion(-) diff --git a/src/builtins/compiled/zoneddatetime.rs b/src/builtins/compiled/zoneddatetime.rs index 9c939968..8dab866f 100644 --- a/src/builtins/compiled/zoneddatetime.rs +++ b/src/builtins/compiled/zoneddatetime.rs @@ -125,6 +125,22 @@ impl ZonedDateTime { self.millisecond_with_provider(&*provider) } + + /// Returns the current offset as a formatted offset string. + pub fn offset(&self) -> TemporalResult { + let provider = TZ_PROVIDER + .lock() + .map_err(|_| TemporalError::general("Unable to acquire lock"))?; + self.offset_with_provider(&*provider) + } + + /// Returns the current offset in nanoseconds + pub fn offset_nanoseconds(&self) -> TemporalResult { + let provider = TZ_PROVIDER + .lock() + .map_err(|_| TemporalError::general("Unable to acquire lock"))?; + self.offset_nanoseconds_with_provider(&*provider) + } } // ==== Experimental TZ_PROVIDER calendar method implementations ==== diff --git a/src/builtins/core/zoneddatetime.rs b/src/builtins/core/zoneddatetime.rs index 04052bf2..c2ad3eb3 100644 --- a/src/builtins/core/zoneddatetime.rs +++ b/src/builtins/core/zoneddatetime.rs @@ -19,7 +19,7 @@ use crate::{ ResolvedRoundingOptions, RoundingIncrement, TemporalRoundingMode, TemporalUnit, ToStringRoundingOptions, }, - parsers::{self, IxdtfStringBuilder}, + parsers::{self, FormattableOffset, FormattableTime, IxdtfStringBuilder, Precision}, partial::{PartialDate, PartialTime}, provider::TimeZoneProvider, rounding::{IncrementRounder, Round}, @@ -542,6 +542,54 @@ impl ZonedDateTime { let iso = self.tz.get_iso_datetime_for(&self.instant, provider)?; Ok(iso.time.nanosecond) } + + pub fn offset_with_provider(&self, provider: &impl TimeZoneProvider) -> TemporalResult { + let offset = self + .tz + .get_offset_nanos_for(self.epoch_nanoseconds(), provider)?; + Ok(nanoseconds_to_formattable_offset(offset).to_string()) + } + + pub fn offset_nanoseconds_with_provider( + &self, + provider: &impl TimeZoneProvider, + ) -> TemporalResult { + let offset = self + .tz + .get_offset_nanos_for(self.epoch_nanoseconds(), provider)?; + Ok(offset as i64) + } +} + +pub(crate) fn nanoseconds_to_formattable_offset(nanoseconds: i128) -> FormattableOffset { + let sign = if nanoseconds >= 0 { + Sign::Positive + } else { + Sign::Negative + }; + let nanos = nanoseconds.unsigned_abs(); + let hour = (nanos / 3_600_000_000_000) as u8; + let minute = ((nanos / 60_000_000_000) % 60) as u8; + let second = ((nanos / 1_000_000_000) % 60) as u8; + let nanosecond = (nanos % 1_000_000_000) as u32; + + let precision = if second == 0 && nanosecond == 0 { + Precision::Minute + } else { + Precision::Auto + }; + + FormattableOffset { + sign, + time: FormattableTime { + hour, + minute, + second, + nanosecond, + precision, + include_sep: true, + }, + } } // ==== Core calendar method implementations ====