From 459ece3dc8cd5123506ed00171794dfdb0731674 Mon Sep 17 00:00:00 2001 From: ijl Date: Tue, 15 Oct 2024 19:55:46 +0000 Subject: [PATCH] jiff --- Cargo.lock | 32 +++----------- Cargo.toml | 4 +- src/serialize/per_type/numpy.rs | 75 ++++++++++++++++++--------------- 3 files changed, 49 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5293ba6e..8ab7e46f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,12 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b993cd767a2bc7307dd87622311ca22c44329cc7a21366206bfa0896827b2bad" -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - [[package]] name = "bytecount" version = "0.6.8" @@ -53,15 +47,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "chrono" -version = "0.4.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" -dependencies = [ - "num-traits", -] - [[package]] name = "compact_str" version = "0.8.0" @@ -123,6 +108,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9028f49264629065d057f340a86acb84867925865f73bbf8d47b4d149a7e88b8" +[[package]] +name = "jiff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a45489186a6123c128fdf6016183fcfab7113e1820eb813127e036e287233fb" + [[package]] name = "libc" version = "0.2.159" @@ -146,15 +137,6 @@ dependencies = [ "syn", ] -[[package]] -name = "num-traits" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", -] - [[package]] name = "once_cell" version = "1.20.2" @@ -169,12 +151,12 @@ dependencies = [ "associative-cache", "bytecount", "cc", - "chrono", "compact_str", "encoding_rs", "half", "itoa", "itoap", + "jiff", "once_cell", "pyo3-build-config", "pyo3-ffi", diff --git a/Cargo.toml b/Cargo.toml index ee3436fd..bab6f081 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,12 +59,12 @@ strict_provenance = [] arrayvec = { version = "0.7", default-features = false, features = ["std", "serde"] } associative-cache = { version = "2", default-features = false } bytecount = { version = "^0.6.7", default-features = false, features = ["runtime-dispatch-simd"] } -chrono = { version = "=0.4.34", default-features = false } compact_str = { version = "0.8", default-features = false, features = ["serde"] } encoding_rs = { version = "0.8", default-features = false } half = { version = "2", default-features = false, features = ["std"] } itoa = { version = "1", default-features = false } -itoap = { version = "1", features = ["std", "simd"] } +itoap = { version = "1", default-features = false, features = ["std", "simd"] } +jiff = { version = "^0.1", default-features = false, features = ["alloc"] } once_cell = { version = "1", default-features = false, features = ["alloc", "race"] } pyo3-ffi = { path = "include/pyo3/pyo3-ffi", default-features = false, features = ["extension-module"]} ryu = { version = "1", default-features = false } diff --git a/src/serialize/per_type/numpy.rs b/src/serialize/per_type/numpy.rs index c7ea47fa..59a3c47e 100644 --- a/src/serialize/per_type/numpy.rs +++ b/src/serialize/per_type/numpy.rs @@ -6,8 +6,9 @@ use crate::serialize::per_type::{ }; use crate::serialize::serializer::PyObjectSerializer; use crate::typeref::{load_numpy_types, ARRAY_STRUCT_STR, DESCR_STR, DTYPE_STR, NUMPY_TYPES}; -use chrono::{Datelike, NaiveDate, NaiveDateTime, Timelike}; use core::ffi::{c_char, c_int, c_void}; +use jiff::civil::DateTime; +use jiff::Timestamp; use pyo3_ffi::*; use serde::ser::{self, Serialize, SerializeSeq, Serializer}; use std::fmt; @@ -1203,6 +1204,19 @@ impl NumpyDateTimeError { } } +macro_rules! to_jiff_datetime { + ($timestamp:expr, $self:expr, $val:expr) => { + Ok( + ($timestamp.map_err(|_| NumpyDateTimeError::Unrepresentable { + unit: *$self, + val: $val, + })?) + .to_zoned(jiff::tz::TimeZone::UTC) + .datetime(), + ) + }; +} + impl NumpyDatetimeUnit { /// Create a `NumpyDatetimeUnit` from a pointer to a Python object holding a /// numpy array. @@ -1255,17 +1269,19 @@ impl NumpyDatetimeUnit { #[cfg_attr(feature = "optimize", optimize(size))] fn datetime(&self, val: i64, opts: Opt) -> Result { match self { - Self::Years => Ok(NaiveDate::from_ymd_opt( + Self::Years => Ok(DateTime::new( (val + 1970) .try_into() .map_err(|_| NumpyDateTimeError::Unrepresentable { unit: *self, val })?, 1, 1, + 0, + 0, + 0, + 0, ) - .unwrap() - .and_hms_opt(0, 0, 0) .unwrap()), - Self::Months => Ok(NaiveDate::from_ymd_opt( + Self::Months => Ok(DateTime::new( (val / 12 + 1970) .try_into() .map_err(|_| NumpyDateTimeError::Unrepresentable { unit: *self, val })?, @@ -1273,38 +1289,24 @@ impl NumpyDatetimeUnit { .try_into() .map_err(|_| NumpyDateTimeError::Unrepresentable { unit: *self, val })?, 1, + 0, + 0, + 0, + 0, ) - .unwrap() - .and_hms_opt(0, 0, 0) .unwrap()), Self::Weeks => { - Ok(NaiveDateTime::from_timestamp_opt(val * 7 * 24 * 60 * 60, 0).unwrap()) + to_jiff_datetime!(Timestamp::from_second(val * 7 * 24 * 60 * 60), self, val) + } + Self::Days => to_jiff_datetime!(Timestamp::from_second(val * 24 * 60 * 60), self, val), + Self::Hours => to_jiff_datetime!(Timestamp::from_second(val * 60 * 60), self, val), + Self::Minutes => to_jiff_datetime!(Timestamp::from_second(val * 60), self, val), + Self::Seconds => to_jiff_datetime!(Timestamp::from_second(val), self, val), + Self::Milliseconds => to_jiff_datetime!(Timestamp::from_millisecond(val), self, val), + Self::Microseconds => to_jiff_datetime!(Timestamp::from_microsecond(val), self, val), + Self::Nanoseconds => { + to_jiff_datetime!(Timestamp::from_nanosecond(val as i128), self, val) } - Self::Days => Ok(NaiveDateTime::from_timestamp_opt(val * 24 * 60 * 60, 0).unwrap()), - Self::Hours => Ok(NaiveDateTime::from_timestamp_opt(val * 60 * 60, 0).unwrap()), - Self::Minutes => Ok(NaiveDateTime::from_timestamp_opt(val * 60, 0).unwrap()), - Self::Seconds => Ok(NaiveDateTime::from_timestamp_opt(val, 0).unwrap()), - Self::Milliseconds => Ok(NaiveDateTime::from_timestamp_opt( - val / 1_000, - (val % 1_000 * 1_000_000) - .try_into() - .map_err(|_| NumpyDateTimeError::Unrepresentable { unit: *self, val })?, - ) - .unwrap()), - Self::Microseconds => Ok(NaiveDateTime::from_timestamp_opt( - val / 1_000_000, - (val % 1_000_000 * 1_000) - .try_into() - .map_err(|_| NumpyDateTimeError::Unrepresentable { unit: *self, val })?, - ) - .unwrap()), - Self::Nanoseconds => Ok(NaiveDateTime::from_timestamp_opt( - val / 1_000_000_000, - (val % 1_000_000_000) - .try_into() - .map_err(|_| NumpyDateTimeError::Unrepresentable { unit: *self, val })?, - ) - .unwrap()), _ => Err(NumpyDateTimeError::UnsupportedUnit(*self)), } .map(|dt| NumpyDatetime64Repr { dt, opts }) @@ -1357,7 +1359,7 @@ macro_rules! forward_inner { } struct NumpyDatetime64Repr { - dt: NaiveDateTime, + dt: DateTime, opts: Opt, } @@ -1368,7 +1370,10 @@ impl DateTimeLike for NumpyDatetime64Repr { forward_inner!(hour, u8); forward_inner!(minute, u8); forward_inner!(second, u8); - forward_inner!(nanosecond, u32); + + fn nanosecond(&self) -> u32 { + self.dt.subsec_nanosecond() as u32 + } fn microsecond(&self) -> u32 { self.nanosecond() / 1_000