nautilus_core/python/
datetime.rs

1// -------------------------------------------------------------------------------------------------
2//  Copyright (C) 2015-2025 Posei Systems Pty Ltd. All rights reserved.
3//  https://poseitrader.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
16//! Date/time utility wrappers exposed to Python.
17
18use pyo3::prelude::*;
19
20use super::to_pyvalue_err;
21use crate::{
22    UnixNanos,
23    datetime::{
24        is_within_last_24_hours, last_weekday_nanos, micros_to_nanos, millis_to_nanos,
25        nanos_to_micros, nanos_to_millis, nanos_to_secs, secs_to_millis, secs_to_nanos,
26        unix_nanos_to_iso8601, unix_nanos_to_iso8601_millis,
27    },
28};
29
30/// Return round nanoseconds (ns) converted from the given seconds.
31///
32/// Parameters
33/// ----------
34/// secs : float
35///     The seconds to convert.
36///
37/// Returns
38/// -------
39/// int
40#[must_use]
41#[pyfunction(name = "secs_to_nanos")]
42pub fn py_secs_to_nanos(secs: f64) -> u64 {
43    secs_to_nanos(secs)
44}
45
46/// Return round milliseconds (ms) converted from the given seconds.
47///
48/// Parameters
49/// ----------
50/// secs : float
51///     The seconds to convert.
52///
53/// Returns
54/// -------
55/// int
56#[must_use]
57#[pyfunction(name = "secs_to_millis")]
58pub fn py_secs_to_millis(secs: f64) -> u64 {
59    secs_to_millis(secs)
60}
61
62/// Return round nanoseconds (ns) converted from the given milliseconds (ms).
63///
64/// Parameters
65/// ----------
66/// millis : float
67///     The milliseconds to convert.
68///
69/// Returns
70/// -------
71/// int
72#[must_use]
73#[pyfunction(name = "millis_to_nanos")]
74pub fn py_millis_to_nanos(millis: f64) -> u64 {
75    millis_to_nanos(millis)
76}
77
78/// Return round nanoseconds (ns) converted from the given microseconds (μs).
79///
80/// Parameters
81/// ----------
82/// micros : float
83///     The microseconds to convert.
84///
85/// Returns
86/// -------
87/// int
88#[must_use]
89#[pyfunction(name = "micros_to_nanos")]
90pub fn py_micros_to_nanos(micros: f64) -> u64 {
91    micros_to_nanos(micros)
92}
93
94/// Return seconds converted from the given nanoseconds (ns).
95///
96/// Parameters
97/// ----------
98/// nanos : int
99///     The nanoseconds to convert.
100///
101/// Returns
102/// -------
103/// float
104#[must_use]
105#[pyfunction(name = "nanos_to_secs")]
106pub fn py_nanos_to_secs(nanos: u64) -> f64 {
107    nanos_to_secs(nanos)
108}
109
110/// Return round milliseconds (ms) converted from the given nanoseconds (ns).
111///
112/// Parameters
113/// ----------
114/// nanos : int
115///     The nanoseconds to convert.
116///
117/// Returns
118/// -------
119/// int
120#[must_use]
121#[pyfunction(name = "nanos_to_millis")]
122pub const fn py_nanos_to_millis(nanos: u64) -> u64 {
123    nanos_to_millis(nanos)
124}
125
126/// Return round microseconds (μs) converted from the given nanoseconds (ns).
127///
128/// Parameters
129/// ----------
130/// nanos : int
131///     The nanoseconds to convert.
132///
133/// Returns
134/// -------
135/// int
136#[must_use]
137#[pyfunction(name = "nanos_to_micros")]
138pub const fn py_nanos_to_micros(nanos: u64) -> u64 {
139    nanos_to_micros(nanos)
140}
141
142/// Return UNIX nanoseconds as an ISO 8601 (RFC 3339) format string.
143///
144/// Parameters
145/// ----------
146/// `timestamp_ns` : int
147///     The UNIX timestamp (nanoseconds).
148/// `nanos_precision` : bool, default True
149///     If True, use nanosecond precision. If False, use millisecond precision.
150///
151/// Returns
152/// -------
153/// str
154///
155/// Raises
156/// ------
157/// `ValueError`
158///     If `timestamp_ns` is invalid.
159#[must_use]
160#[pyfunction(name = "unix_nanos_to_iso8601", signature = (timestamp_ns, nanos_precision=true))]
161pub fn py_unix_nanos_to_iso8601(timestamp_ns: u64, nanos_precision: Option<bool>) -> String {
162    let unix_nanos = timestamp_ns.into();
163    if nanos_precision.unwrap_or(true) {
164        unix_nanos_to_iso8601(unix_nanos)
165    } else {
166        unix_nanos_to_iso8601_millis(unix_nanos)
167    }
168}
169
170/// Return UNIX nanoseconds at midnight (UTC) of the last weekday (Mon-Fri).
171///
172/// Parameters
173/// ----------
174/// year : int
175///     The year from the datum date.
176/// month : int
177///     The month from the datum date.
178/// day : int
179///     The day from the datum date.
180///
181/// Returns
182/// -------
183/// int
184///
185/// Raises
186/// ------
187/// `ValueError`
188///     If given an invalid date.
189///
190/// # Errors
191///
192/// Returns a `PyErr` if the provided date is invalid.
193#[pyfunction(name = "last_weekday_nanos")]
194pub fn py_last_weekday_nanos(year: i32, month: u32, day: u32) -> PyResult<u64> {
195    Ok(last_weekday_nanos(year, month, day)
196        .map_err(to_pyvalue_err)?
197        .as_u64())
198}
199
200/// Return whether the given UNIX nanoseconds timestamp is within the last 24 hours.
201///
202/// Parameters
203/// ----------
204/// `timestamp_ns` : int
205///     The UNIX nanoseconds timestamp datum.
206///
207/// Returns
208/// -------
209/// bool
210///
211/// Raises
212/// ------
213/// `ValueError`
214///     If `timestamp` is invalid.
215///
216/// # Errors
217///
218/// Returns a `PyErr` if the provided timestamp is invalid.
219#[pyfunction(name = "is_within_last_24_hours")]
220pub fn py_is_within_last_24_hours(timestamp_ns: u64) -> PyResult<bool> {
221    is_within_last_24_hours(UnixNanos::from(timestamp_ns)).map_err(to_pyvalue_err)
222}