nautilus_core/python/
datetime.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Nautech Systems Pty Ltd. All rights reserved.
3//  https://nautechsystems.io
4//
5//  Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6//  You may not use this file except in compliance with the License.
7//  You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9//  Unless required by applicable law or agreed to in writing, software
10//  distributed under the License is distributed on an "AS IS" BASIS,
11//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//  See the License for the specific language governing permissions and
13//  limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16use pyo3::prelude::*;
17
18use super::to_pyvalue_err;
19use crate::{
20    UnixNanos,
21    datetime::{
22        is_within_last_24_hours, last_weekday_nanos, micros_to_nanos, millis_to_nanos,
23        nanos_to_micros, nanos_to_millis, nanos_to_secs, secs_to_millis, secs_to_nanos,
24        unix_nanos_to_iso8601, unix_nanos_to_iso8601_millis,
25    },
26};
27
28/// Return round nanoseconds (ns) converted from the given seconds.
29///
30/// Parameters
31/// ----------
32/// secs : float
33///     The seconds to convert.
34///
35/// Returns
36/// -------
37/// int
38#[must_use]
39#[pyfunction(name = "secs_to_nanos")]
40pub fn py_secs_to_nanos(secs: f64) -> u64 {
41    secs_to_nanos(secs)
42}
43
44/// Return round milliseconds (ms) converted from the given seconds.
45///
46/// Parameters
47/// ----------
48/// secs : float
49///     The seconds to convert.
50///
51/// Returns
52/// -------
53/// int
54#[must_use]
55#[pyfunction(name = "secs_to_millis")]
56pub fn py_secs_to_millis(secs: f64) -> u64 {
57    secs_to_millis(secs)
58}
59
60/// Return round nanoseconds (ns) converted from the given milliseconds (ms).
61///
62/// Parameters
63/// ----------
64/// millis : float
65///     The milliseconds to convert.
66///
67/// Returns
68/// -------
69/// int
70#[must_use]
71#[pyfunction(name = "millis_to_nanos")]
72pub fn py_millis_to_nanos(millis: f64) -> u64 {
73    millis_to_nanos(millis)
74}
75
76/// Return round nanoseconds (ns) converted from the given microseconds (μs).
77///
78/// Parameters
79/// ----------
80/// micros : float
81///     The microseconds to convert.
82///
83/// Returns
84/// -------
85/// int
86#[must_use]
87#[pyfunction(name = "micros_to_nanos")]
88pub fn py_micros_to_nanos(micros: f64) -> u64 {
89    micros_to_nanos(micros)
90}
91
92/// Return seconds converted from the given nanoseconds (ns).
93///
94/// Parameters
95/// ----------
96/// nanos : int
97///     The nanoseconds to convert.
98///
99/// Returns
100/// -------
101/// float
102#[must_use]
103#[pyfunction(name = "nanos_to_secs")]
104pub fn py_nanos_to_secs(nanos: u64) -> f64 {
105    nanos_to_secs(nanos)
106}
107
108/// Return round milliseconds (ms) converted from the given nanoseconds (ns).
109///
110/// Parameters
111/// ----------
112/// nanos : int
113///     The nanoseconds to convert.
114///
115/// Returns
116/// -------
117/// int
118#[must_use]
119#[pyfunction(name = "nanos_to_millis")]
120pub const fn py_nanos_to_millis(nanos: u64) -> u64 {
121    nanos_to_millis(nanos)
122}
123
124/// Return round microseconds (μs) converted from the given nanoseconds (ns).
125///
126/// Parameters
127/// ----------
128/// nanos : int
129///     The nanoseconds to convert.
130///
131/// Returns
132/// -------
133/// int
134#[must_use]
135#[pyfunction(name = "nanos_to_micros")]
136pub const fn py_nanos_to_micros(nanos: u64) -> u64 {
137    nanos_to_micros(nanos)
138}
139
140/// Return UNIX nanoseconds as an ISO 8601 (RFC 3339) format string.
141///
142/// Parameters
143/// ----------
144/// timestamp_ns : int
145///     The UNIX timestamp (nanoseconds).
146/// nanos_precision : bool, default True
147///     If True, use nanosecond precision. If False, use millisecond precision.
148///
149/// Returns
150/// -------
151/// str
152///
153/// Raises
154/// ------
155/// ValueError
156///     If `timestamp_ns` is invalid.
157#[must_use]
158#[pyfunction(name = "unix_nanos_to_iso8601", signature = (timestamp_ns, nanos_precision=true))]
159pub fn py_unix_nanos_to_iso8601(timestamp_ns: u64, nanos_precision: Option<bool>) -> String {
160    let unix_nanos = timestamp_ns.into();
161    if nanos_precision.unwrap_or(true) {
162        unix_nanos_to_iso8601(unix_nanos)
163    } else {
164        unix_nanos_to_iso8601_millis(unix_nanos)
165    }
166}
167
168/// Return UNIX nanoseconds at midnight (UTC) of the last weekday (Mon-Fri).
169///
170/// Parameters
171/// ----------
172/// year : int
173///     The year from the datum date.
174/// month : int
175///     The month from the datum date.
176/// day : int
177///     The day from the datum date.
178///
179/// Returns
180/// -------
181/// int
182///
183/// Raises
184/// ------
185/// ValueError
186///     If given an invalid date.
187#[pyfunction(name = "last_weekday_nanos")]
188#[allow(clippy::missing_errors_doc)]
189pub fn py_last_weekday_nanos(year: i32, month: u32, day: u32) -> PyResult<u64> {
190    Ok(last_weekday_nanos(year, month, day)
191        .map_err(to_pyvalue_err)?
192        .as_u64())
193}
194
195/// Return whether the given UNIX nanoseconds timestamp is within the last 24 hours.
196///
197/// Parameters
198/// ----------
199/// timestamp_ns : int
200///     The UNIX nanoseconds timestamp datum.
201///
202/// Returns
203/// -------
204/// bool
205///
206/// Raises
207/// ------
208/// ValueError
209///     If `timestamp` is invalid.
210#[pyfunction(name = "is_within_last_24_hours")]
211#[allow(clippy::missing_errors_doc)]
212pub fn py_is_within_last_24_hours(timestamp_ns: u64) -> PyResult<bool> {
213    is_within_last_24_hours(UnixNanos::from(timestamp_ns)).map_err(to_pyvalue_err)
214}