nstd_sys/os/unix/
time.rs

1//! Unix time utilities.
2use crate::{
3    core::{
4        optional::{gen_optional, NSTDOptional},
5        time::{
6            nstd_core_time_duration_get, nstd_core_time_duration_nanoseconds,
7            nstd_core_time_duration_new, nstd_core_time_duration_seconds, NSTDDuration,
8        },
9    },
10    NSTDFloat64, NSTDInt64, NSTDUInt32,
11};
12use core::mem::MaybeUninit;
13use libc::{clock_gettime, timespec, CLOCK_REALTIME};
14use nstdapi::nstdapi;
15
16/// A structure representing system time since January 1st 1970.
17#[nstdapi]
18#[derive(Clone, Copy, PartialEq)]
19pub struct NSTDUnixTime {
20    /// The time span since January 1st 1970.
21    duration: NSTDDuration,
22}
23impl NSTDUnixTime {
24    /// Creates a new [`NSTDUnixTime`] object from an [`NSTDDuration`].
25    #[inline]
26    #[allow(dead_code)]
27    pub(crate) const fn from_duration(duration: NSTDDuration) -> Self {
28        Self { duration }
29    }
30}
31impl From<timespec> for NSTDUnixTime {
32    /// Converts a [timespec] into an [`NSTDUnixTime`] object.
33    #[allow(clippy::cast_precision_loss)]
34    fn from(value: timespec) -> Self {
35        /// The number of nanoseconds in a full second.
36        const NANOS_IN_SEC: NSTDFloat64 = 1_000_000_000.0;
37        let mut seconds = value.tv_sec as _;
38        seconds += value.tv_nsec as NSTDFloat64 / NANOS_IN_SEC;
39        #[allow(unused_unsafe)]
40        // SAFETY: This operation is safe.
41        unsafe {
42            Self {
43                duration: nstd_core_time_duration_new(seconds),
44            }
45        }
46    }
47}
48gen_optional!(NSTDUnixOptionalTime, NSTDUnixTime);
49
50/// Returns the current system time as an `NSTDUnixTime` object.
51///
52/// # Returns
53///
54/// `NSTDUnixOptionalTime time` - The current time on success, or an uninitialized "none" value on
55/// failure.
56#[inline]
57#[nstdapi]
58pub fn nstd_os_unix_time_now() -> NSTDUnixOptionalTime {
59    let mut timespec = MaybeUninit::uninit();
60    // SAFETY: `clock_gettime` is safe.
61    if unsafe { clock_gettime(CLOCK_REALTIME, timespec.as_mut_ptr()) } == 0 {
62        // SAFETY: `timespec` is initialized.
63        return NSTDOptional::Some(NSTDUnixTime::from(unsafe { timespec.assume_init() }));
64    }
65    NSTDOptional::None
66}
67
68/// Returns the number of seconds stored in an `NSTDUnixTime` object as an `NSTDFloat64`.
69///
70/// # Parameters:
71///
72/// - `NSTDUnixTime time` - The time object.
73///
74/// # Returns
75///
76/// `NSTDFloat64 seconds` - The number of seconds in a time object represented as an
77/// `NSTDFloat64`.
78#[inline]
79#[nstdapi]
80pub const fn nstd_os_unix_time_get(time: NSTDUnixTime) -> NSTDFloat64 {
81    nstd_core_time_duration_get(time.duration)
82}
83
84/// Returns the number of seconds in an `NSTDUnixTime` object.
85///
86/// # Parameters:
87///
88/// - `NSTDUnixTime time` - The time object.
89///
90/// # Returns
91///
92/// `NSTDInt64 seconds` - The number of seconds held in `time`.
93#[inline]
94#[nstdapi]
95pub const fn nstd_os_unix_time_seconds(time: NSTDUnixTime) -> NSTDInt64 {
96    nstd_core_time_duration_seconds(time.duration)
97}
98
99/// Returns the number of nanoseconds in an `NSTDUnixTime` object.
100///
101/// # Parameters:
102///
103/// - `NSTDUnixTime time` - The time object.
104///
105/// # Returns
106///
107/// `NSTDUInt32 nanoseconds` - The number of nanoseconds held in `time`.
108#[inline]
109#[nstdapi]
110pub fn nstd_os_unix_time_nanoseconds(time: NSTDUnixTime) -> NSTDUInt32 {
111    nstd_core_time_duration_nanoseconds(time.duration)
112}
113
114/// Computes the addition of an `NSTDUnixTime` object and an `NSTDDuration`.
115///
116/// # Parameters:
117///
118/// - `NSTDUnixTime time` - The time object
119///
120/// - `NSTDDuration duration` - The duration to add.
121///
122/// # Returns
123///
124/// `NSTDUnixTime time` - The result of the addition.
125#[inline]
126#[nstdapi]
127pub fn nstd_os_unix_time_add(time: NSTDUnixTime, duration: NSTDDuration) -> NSTDUnixTime {
128    let secs = nstd_core_time_duration_get(time.duration) + nstd_core_time_duration_get(duration);
129    NSTDUnixTime {
130        duration: nstd_core_time_duration_new(secs),
131    }
132}
133
134/// Computes the subtraction between an `NSTDUnixTime` object and an `NSTDDuration`.
135///
136/// # Parameters:
137///
138/// - `NSTDUnixTime time` - The time object
139///
140/// - `NSTDDuration duration` - The duration to subtract.
141///
142/// # Returns
143///
144/// `NSTDUnixTime time` - The result of the subtraction.
145#[inline]
146#[nstdapi]
147pub fn nstd_os_unix_time_sub(time: NSTDUnixTime, duration: NSTDDuration) -> NSTDUnixTime {
148    let secs = nstd_core_time_duration_get(time.duration) - nstd_core_time_duration_get(duration);
149    NSTDUnixTime {
150        duration: nstd_core_time_duration_new(secs),
151    }
152}