Skip to content

Commit

Permalink
Remove hooks in favor of user defined values
Browse files Browse the repository at this point in the history
  • Loading branch information
nekevss committed Feb 1, 2025
1 parent be816ab commit c97405a
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 94 deletions.
36 changes: 25 additions & 11 deletions src/builtins/compiled/now.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
use crate::builtins::{
core::{Now, PlainDate, PlainDateTime, PlainTime},
core::{Now, PlainDate, PlainDateTime, PlainTime, ZonedDateTime},
TZ_PROVIDER,
};
use crate::{TemporalError, TemporalResult, TimeZone};

#[cfg(feature = "sys")]
use crate::sys::DefaultSystemHooks;
use crate::sys;
use crate::{time::EpochNanoseconds, TemporalError, TemporalResult, TimeZone};

#[cfg(feature = "sys")]
impl Now {
/// Returns the current system time as a [`PlainDateTime`] with an optional
/// [`TimeZone`].
pub fn zoneddatetime_iso(timezone: Option<TimeZone>) -> TemporalResult<ZonedDateTime> {
let timezone =
timezone.unwrap_or(TimeZone::IanaIdentifier(crate::sys::get_system_timezone()?));
let system_nanos = sys::get_system_nanoseconds()?;
let epoch_nanos = EpochNanoseconds::try_from(system_nanos)?;
Now::zoneddatetime_iso_with_system_values(epoch_nanos, timezone)
}

/// Returns the current system time as a [`PlainDateTime`] with an optional
/// [`TimeZone`].
///
Expand All @@ -17,8 +25,10 @@ impl Now {
let provider = TZ_PROVIDER
.lock()
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
Now::plain_datetime_iso_with_hooks_and_provider(timezone, &DefaultSystemHooks, &*provider)
.map(Into::into)
let timezone = timezone.unwrap_or(TimeZone::IanaIdentifier(sys::get_system_timezone()?));
let system_nanos = sys::get_system_nanoseconds()?;
let epoch_nanos = EpochNanoseconds::try_from(system_nanos)?;
Now::plain_datetime_iso_with_provider(epoch_nanos, timezone, &*provider)
}

/// Returns the current system time as a [`PlainDate`] with an optional
Expand All @@ -29,8 +39,10 @@ impl Now {
let provider = TZ_PROVIDER
.lock()
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
Now::plain_date_iso_with_hooks_and_provider(timezone, &DefaultSystemHooks, &*provider)
.map(Into::into)
let timezone = timezone.unwrap_or(TimeZone::IanaIdentifier(sys::get_system_timezone()?));
let system_nanos = sys::get_system_nanoseconds()?;
let epoch_nanos = EpochNanoseconds::try_from(system_nanos)?;
Now::plain_date_iso_with_provider(epoch_nanos, timezone, &*provider)
}

/// Returns the current system time as a [`PlainTime`] with an optional
Expand All @@ -41,7 +53,9 @@ impl Now {
let provider = TZ_PROVIDER
.lock()
.map_err(|_| TemporalError::general("Unable to acquire lock"))?;
Now::plain_time_iso_with_hooks_and_provider(timezone, &DefaultSystemHooks, &*provider)
.map(Into::into)
let timezone = timezone.unwrap_or(TimeZone::IanaIdentifier(sys::get_system_timezone()?));
let system_nanos = sys::get_system_nanoseconds()?;
let epoch_nanos = EpochNanoseconds::try_from(system_nanos)?;
Now::plain_time_iso_with_provider(epoch_nanos, timezone, &*provider)
}
}
154 changes: 96 additions & 58 deletions src/builtins/core/now.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@
use crate::iso::IsoDateTime;
use crate::provider::TimeZoneProvider;
use crate::sys::SystemHooks;
use crate::time::EpochNanoseconds;
use crate::TemporalResult;
use alloc::string::String;

#[cfg(feature = "sys")]
use crate::sys::DefaultSystemHooks;
use alloc::string::String;

use super::{
calendar::Calendar, timezone::TimeZone, Instant, PlainDate, PlainDateTime, PlainTime,
Expand All @@ -18,47 +17,61 @@ use super::{
pub struct Now;

impl Now {
pub fn instant_with_hooks(system_hooks: &impl SystemHooks) -> TemporalResult<Instant> {
let epoch_nanoseconds = system_hooks.get_system_nanoseconds()?;
Ok(Instant::from(epoch_nanoseconds))
}

pub fn system_time_zone_identifier_with_hooks(
system_hooks: &impl SystemHooks,
) -> TemporalResult<String> {
system_hooks.get_system_time_zone()
pub fn instant_with_epoch_nanoseconds(epoch_nanoseconds: EpochNanoseconds) -> Instant {
Instant::from(epoch_nanoseconds)
}

pub fn system_datetime_with_hooks_and_provider(
time_zone: Option<TimeZone>,
system_hooks: &impl SystemHooks,
/// Returns the current system `DateTime` based off the provided system args
///
/// ## Order of operations
///
/// The order of operations for this method requires the `GetSystemTimeZone` call
/// to occur prior to calling system time and resolving the `EpochNanoseconds`
/// value.
///
/// A correct implementation will follow the following steps:
///
/// 1. Resolve user input `TimeZone` with the `SystemTimeZone`.
/// 2. Get the `SystemNanoseconds`
///
/// For an example implementation see [`Self::zoneddatetime_iso`]
///
pub(crate) fn system_datetime_with_provider(
epoch_nanoseconds: EpochNanoseconds,
timezone: TimeZone,
provider: &impl TimeZoneProvider,
) -> TemporalResult<IsoDateTime> {
// 1. If temporalTimeZoneLike is undefined, then
// a. Let timeZone be SystemTimeZoneIdentifier().
// 2. Else,
// a. Let timeZone be ? ToTemporalTimeZoneIdentifier(temporalTimeZoneLike).
let tz = time_zone.unwrap_or(TimeZone::IanaIdentifier(
system_hooks.get_system_time_zone()?,
));
// 3. Let epochNs be SystemUTCEpochNanoseconds().
let epoch_ns = system_hooks.get_system_nanoseconds()?;
// 4. Return GetISODateTimeFor(timeZone, epochNs).
tz.get_iso_datetime_for(&Instant::from(epoch_ns), provider)
timezone.get_iso_datetime_for(&Instant::from(epoch_nanoseconds), provider)
}

/// Returns the current system time as a `ZonedDateTime` with an ISO8601 calendar.
///
/// The time zone will be set to either the `TimeZone` if a value is provided, or
/// according to the system timezone if no value is provided.
pub fn zoneddatetime_iso_with_hooks(
timezone: Option<TimeZone>,
system_hooks: &impl SystemHooks,
///
/// ## Order of operations
///
/// The order of operations for this method requires the `GetSystemTimeZone` call
/// to occur prior to calling system time and resolving the `EpochNanoseconds`
/// value.
///
/// A correct implementation will follow the following steps:
///
/// 1. Resolve user input `TimeZone` with the `SystemTimeZone`.
/// 2. Get the `SystemNanoseconds`
///
/// For an example implementation see [`Self::zoneddatetime_iso`]
pub fn zoneddatetime_iso_with_system_values(
epoch_nanos: EpochNanoseconds,
timezone: TimeZone,
) -> TemporalResult<ZonedDateTime> {
let timezone = timezone.unwrap_or(TimeZone::IanaIdentifier(
system_hooks.get_system_time_zone()?,
));
let instant = Self::instant_with_hooks(system_hooks)?;
let instant = Self::instant_with_epoch_nanoseconds(epoch_nanos);
Ok(ZonedDateTime::new_unchecked(
instant,
Calendar::default(),
Expand All @@ -71,79 +84,104 @@ impl Now {
impl Now {
/// Returns the current instant
pub fn instant() -> TemporalResult<Instant> {
Self::instant_with_hooks(&DefaultSystemHooks)
let system_nanos = crate::sys::get_system_nanoseconds()?;
let epoch_nanos = EpochNanoseconds::try_from(system_nanos)?;
Ok(Self::instant_with_epoch_nanoseconds(epoch_nanos))
}

/// Returns the current time zone.
pub fn time_zone_identifier() -> TemporalResult<String> {
Self::system_time_zone_identifier_with_hooks(&DefaultSystemHooks)
crate::sys::get_system_timezone()
}
}

impl Now {
/// Returns the current system time as a `PlainDateTime` with an ISO8601 calendar.
///
/// The time zone used to calculate the `PlainDateTime` will be set to either the
/// `TimeZone` if a value is provided, or according to the system timezone if no
/// value is provided.
pub fn plain_datetime_iso_with_hooks_and_provider(
timezone: Option<TimeZone>,
system_hooks: &impl SystemHooks,
/// ## Order of operations
///
/// The order of operations for this method requires the `GetSystemTimeZone` call
/// to occur prior to calling system time and resolving the `EpochNanoseconds`
/// value.
///
/// A correct implementation will follow the following steps:
///
/// 1. Resolve user input `TimeZone` with the `SystemTimeZone`.
/// 2. Get the `SystemNanoseconds`
///
/// For an example implementation see [`Self::plain_date_time_iso`]
pub fn plain_datetime_iso_with_provider(
epoch_nanos: EpochNanoseconds,
timezone: TimeZone,
provider: &impl TimeZoneProvider,
) -> TemporalResult<PlainDateTime> {
let iso = Self::system_datetime_with_hooks_and_provider(timezone, system_hooks, provider)?;
let iso = Self::system_datetime_with_provider(epoch_nanos, timezone, provider)?;
Ok(PlainDateTime::new_unchecked(iso, Calendar::default()))
}

/// Returns the current system time as a `PlainDate` with an ISO8601 calendar.
///
/// The time zone used to calculate the `PlainDate` will be set to either the
/// `TimeZone` if a value is provided, or according to the system timezone if no
/// value is provided.
pub fn plain_date_iso_with_hooks_and_provider(
timezone: Option<TimeZone>,
system_hooks: &impl SystemHooks,
/// ## Order of operations
///
/// The order of operations for this method requires the `GetSystemTimeZone` call
/// to occur prior to calling system time and resolving the `EpochNanoseconds`
/// value.
///
/// A correct implementation will follow the following steps:
///
/// 1. Resolve user input `TimeZone` with the `SystemTimeZone`.
/// 2. Get the `SystemNanoseconds`
///
/// For an example implementation see [`Self::plain_date_iso`]
pub fn plain_date_iso_with_provider(
epoch_nanos: EpochNanoseconds,
timezone: TimeZone,
provider: &impl TimeZoneProvider,
) -> TemporalResult<PlainDate> {
let iso = Self::system_datetime_with_hooks_and_provider(timezone, system_hooks, provider)?;
let iso = Self::system_datetime_with_provider(epoch_nanos, timezone, provider)?;
Ok(PlainDate::new_unchecked(iso.date, Calendar::default()))
}

/// Returns the current system time as a `PlainTime` according to an ISO8601 calendar.
///
/// The time zone used to calculate the `PlainTime` will be set to either the
/// `TimeZone` if a value is provided, or according to the system timezone if no
/// value is provided.
pub fn plain_time_iso_with_hooks_and_provider(
timezone: Option<TimeZone>,
system_hooks: &impl SystemHooks,
/// ## Order of operations
///
/// The order of operations for this method requires the `GetSystemTimeZone` call
/// to occur prior to calling system time and resolving the `EpochNanoseconds`
/// value.
///
/// A correct implementation will follow the following steps:
///
/// 1. Resolve user input `TimeZone` with the `SystemTimeZone`.
/// 2. Get the `SystemNanoseconds`
///
/// For an example implementation see [`Self::plain_time_iso`]
pub fn plain_time_iso_with_provider(
epoch_nanos: EpochNanoseconds,
timezone: TimeZone,
provider: &impl TimeZoneProvider,
) -> TemporalResult<PlainTime> {
let iso = Self::system_datetime_with_hooks_and_provider(timezone, system_hooks, provider)?;
let iso = Self::system_datetime_with_provider(epoch_nanos, timezone, provider)?;
Ok(PlainTime::new_unchecked(iso.time))
}
}

#[cfg(all(feature = "tzdb", feature = "sys"))]
#[cfg(test)]
mod tests {
use crate::builtins::core::Now;
use std::thread;
use std::time::Duration as StdDuration;

use crate::builtins::core::Now;
use crate::{options::DifferenceSettings, sys::DefaultSystemHooks, tzdb::FsTzdbProvider};
use crate::options::DifferenceSettings;

#[test]
fn now_datetime_test() {
let provider = &FsTzdbProvider::default();
let system_hooks = DefaultSystemHooks;
let sleep = 2;

let before =
Now::plain_datetime_iso_with_hooks_and_provider(None, &system_hooks, provider).unwrap();
let before = Now::plain_datetime_iso(None).unwrap();
thread::sleep(StdDuration::from_secs(sleep));
let after =
Now::plain_datetime_iso_with_hooks_and_provider(None, &system_hooks, provider).unwrap();
let after = Now::plain_datetime_iso(None).unwrap();

let diff = after.since(&before, DifferenceSettings::default()).unwrap();

Expand Down
5 changes: 3 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,12 @@ pub mod options;
pub mod parsers;
pub mod primitive;
pub mod provider;
pub mod sys;

mod epoch_nanoseconds;
#[cfg(feature = "sys")]
pub(crate) mod sys;

mod builtins;
mod epoch_nanoseconds;

#[cfg(feature = "tzdb")]
pub mod tzdb;
Expand Down
27 changes: 4 additions & 23 deletions src/sys.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,16 @@
use alloc::string::String;

use crate::{time::EpochNanoseconds, TemporalResult};
use crate::TemporalResult;

#[cfg(feature = "sys")]
use crate::TemporalError;
#[cfg(feature = "sys")]
use alloc::string::ToString;
#[cfg(feature = "sys")]
use web_time::{SystemTime, UNIX_EPOCH};

// TODO: Need to implement SystemTime handling for non_std.

pub trait SystemHooks {
/// Returns the current system time in `EpochNanoseconds`.
fn get_system_nanoseconds(&self) -> TemporalResult<EpochNanoseconds>;
/// Returns the current system IANA Time Zone Identifier.
fn get_system_time_zone(&self) -> TemporalResult<String>;
}

#[cfg(feature = "sys")]
pub struct DefaultSystemHooks;

#[cfg(feature = "sys")]
impl SystemHooks for DefaultSystemHooks {
fn get_system_nanoseconds(&self) -> TemporalResult<EpochNanoseconds> {
EpochNanoseconds::try_from(get_system_nanoseconds()?)
}

fn get_system_time_zone(&self) -> TemporalResult<String> {
iana_time_zone::get_timezone().map_err(|e| TemporalError::general(e.to_string()))
}
#[inline]
pub(crate) fn get_system_timezone() -> TemporalResult<String> {
iana_time_zone::get_timezone().map_err(|e| TemporalError::general(e.to_string()))
}

/// Returns the system time in nanoseconds.
Expand Down

0 comments on commit c97405a

Please sign in to comment.