Replace deprecated chrono with jiff (#8436)

See: chronotope/chrono#1768
This commit is contained in:
Joshua Megnauth authored and GitHub committed 2026-08-04 16:50:22 +09:00
1 parent 331c3b14c8
commit 184db1191b
7 files changed
+91 -181

No files matched your search

Generated
+21 -101
View File
@@ -73,15 +73,6 @@ version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anes"
version = "0.1.6"
@@ -509,19 +500,6 @@ dependencies = [
"rand_core 0.10.1",
]
[[package]]
name = "chrono"
version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
dependencies = [
"iana-time-zone",
"js-sys",
"num-traits",
"wasm-bindgen",
"windows-link",
]
[[package]]
name = "ciborium"
version = "0.2.2"
@@ -1567,30 +1545,6 @@ dependencies = [
"typenum",
]
[[package]]
name = "iana-time-zone"
version = "0.1.65"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"log",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "icu_casemap"
version = "2.2.0"
@@ -1820,10 +1774,14 @@ checksum = "ccfe6121cbe750cf81efa362d85c0bde7ea298ec43092d3a193baca59cdbd634"
dependencies = [
"defmt",
"jiff-static",
"jiff-tzdb-platform",
"js-sys",
"log",
"portable-atomic",
"portable-atomic-util",
"serde_core",
"wasm-bindgen",
"windows-link",
]
[[package]]
@@ -1837,6 +1795,21 @@ dependencies = [
"syn 2.0.119",
]
[[package]]
name = "jiff-tzdb"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "142bd39932ad231f10513df9ab62661fead8719872150b7ad02a2df79f4e141e"
[[package]]
name = "jiff-tzdb-platform"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "875a5a69ac2bab1a891711cf5eccbec1ce0341ea805560dcd90b7a2e925132e8"
dependencies = [
"jiff-tzdb",
]
[[package]]
name = "jni"
version = "0.22.4"
@@ -3575,7 +3548,6 @@ dependencies = [
"base64",
"blake2",
"bzip2",
"chrono",
"constant_time_eq",
"crc32fast",
"crossbeam-utils",
@@ -3591,6 +3563,7 @@ dependencies = [
"indexmap",
"insta",
"itertools 0.15.0",
"jiff",
"libc",
"libsqlite3-sys",
"libz-rs-sys",
@@ -3669,7 +3642,6 @@ dependencies = [
"ascii",
"bitflags 2.13.1",
"bstr",
"chrono",
"constant_time_eq",
"crossbeam-utils",
"exitcode",
@@ -3682,6 +3654,7 @@ dependencies = [
"is-macro",
"itertools 0.15.0",
"itoa",
"jiff",
"libc",
"log",
"malachite-bigint",
@@ -4713,65 +4686,12 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement",
"windows-interface",
"windows-link",
"windows-result",
"windows-strings",
]
[[package]]
name = "windows-implement"
version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "windows-interface"
version = "0.59.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-strings"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link",
]
[[package]]
name = "windows-sys"
version = "0.52.0"
+1 -1
View File
@@ -200,7 +200,6 @@ bitflags = "2.11.0"
bitflagset = "0.0.3"
bstr = { version = "1", default-features = false, features = ["unicode"] }
bzip2 = "0.6"
chrono = { version = "0.4.44", default-features = false, features = ["clock", "std"] }
console_error_panic_hook = "0.1"
constant_time_eq = "0.5"
cranelift = "0.132.0"
@@ -231,6 +230,7 @@ insta = "1.47"
itertools = { version = "0.15.0", default-features = false, features = ["use_alloc"] }
itoa = "1"
is-macro = "0.3.7"
jiff = "0.2"
js-sys = "0.3"
junction = "2.0.0"
lexical-parse-float = "1.0.6"
+1 -1
View File
@@ -86,10 +86,10 @@ libz-rs-sys = { workspace = true }
bzip2 = { workspace = true }
# tkinter
jiff = { workspace = true }
tk-sys = { workspace = true, optional = true }
tcl-sys = { workspace = true, optional = true }
widestring = { workspace = true, optional = true }
chrono.workspace = true
# uuid
[target.'cfg(not(any(target_os = "ios", target_os = "android", target_os = "windows", target_arch = "wasm32", target_os = "redox")))'.dependencies]
+7 -7
View File
@@ -10,7 +10,7 @@
//! - Loading certificates from files, directories, and bytes
use alloc::sync::Arc;
use chrono::{DateTime, Utc};
use jiff::{Timestamp, Zoned, tz::TimeZone};
use parking_lot::RwLock as ParkingRwLock;
use rustls::{
DigitallySignedStruct, RootCertStore, SignatureScheme,
@@ -201,10 +201,10 @@ fn format_ip_address(ip: &[u8]) -> String {
/// Formats certificate validity dates in the format:
/// "Mon DD HH:MM:SS YYYY GMT"
fn format_asn1_time(time: &x509_parser::time::ASN1Time) -> String {
let timestamp = time.timestamp();
DateTime::<Utc>::from_timestamp(timestamp, 0)
.expect("ASN1Time must be valid timestamp")
.format("%b %e %H:%M:%S %Y GMT")
let timestamp =
Timestamp::from_second(time.timestamp()).expect("ASN1Time must be valid timestamp");
Zoned::new(timestamp, TimeZone::UTC)
.strftime("%b %e %H:%M:%S %Y GMT")
.to_string()
}
@@ -341,7 +341,7 @@ pub(super) fn cert_to_dict(
let serial = format_serial_number(&cert.serial);
dict.set_item("serialNumber", vm.ctx.new_str(serial).into(), vm)?;
// Validity dates - format with GMT using chrono
// Validity dates - format with GMT using jiff
dict.set_item(
"notBefore",
vm.ctx
@@ -414,7 +414,7 @@ pub(super) fn cert_der_to_dict_helper(
// CPython ordering: issuer, notAfter, notBefore, serialNumber, subject, version
dict.set_item("issuer", name_to_tuple(cert.issuer())?, vm)?;
// Validity - format with GMT using chrono
// Validity - format with GMT using jiff
dict.set_item(
"notAfter",
vm.ctx
+3 -3
View File
@@ -26,7 +26,7 @@ ast = ["ruff_python_ast", "ruff_text_size"]
codegen = ["rustpython-codegen", "ast"]
parser = ["ast"]
serde = ["dep:serde"]
wasmbind = ["rustpython-common/wasm_js", "chrono/wasmbind", "wasm-bindgen"]
wasmbind = ["rustpython-common/wasm_js", "jiff/js", "wasm-bindgen"]
[dependencies]
rustpython-compiler = { workspace = true, optional = true }
@@ -48,7 +48,6 @@ ascii = { workspace = true }
bitflags = { workspace = true }
bstr = { workspace = true }
crossbeam-utils = { workspace = true }
chrono = { workspace = true }
constant_time_eq = { workspace = true }
flame = { workspace = true, optional = true }
hex = { workspace = true }
@@ -56,6 +55,7 @@ indexmap = { workspace = true }
itertools = { workspace = true }
itoa = { workspace = true }
is-macro = { workspace = true }
jiff = { workspace = true }
libc = { workspace = true }
log = { workspace = true }
malachite-bigint = { workspace = true }
@@ -91,9 +91,9 @@ widestring = { workspace = true }
wasm-bindgen = { workspace = true, optional = true }
[build-dependencies]
chrono = { workspace = true }
glob = { workspace = true }
itertools = { workspace = true }
jiff = { workspace = true }
[lints]
workspace = true
+12 -10
View File
@@ -3,9 +3,8 @@
reason = "build scripts cannot use rustpython-host_env"
)]
use chrono::{Local, prelude::DateTime};
use core::time::Duration;
use itertools::Itertools;
use jiff::{Timestamp, Zoned, tz::TimeZone};
use std::{
env,
io::{self, prelude::*},
@@ -123,24 +122,27 @@ fn git_identifier() -> String {
}
}
fn get_git_timestamp_datetime() -> DateTime<Local> {
let timestamp = git_timestamp().parse::<u64>().unwrap_or_default();
let datetime = UNIX_EPOCH + Duration::from_secs(timestamp);
datetime.into()
fn get_git_timestamp_raw() -> Option<Timestamp> {
let git_timestamp = git_timestamp().parse::<i64>().ok()?;
Timestamp::from_second(git_timestamp).ok()
}
fn get_git_timestamp_datetime() -> Zoned {
get_git_timestamp_raw().map_or_else(Zoned::now, |timestamp| {
Zoned::new(timestamp, TimeZone::system())
})
}
#[must_use]
fn get_git_date() -> String {
let datetime = get_git_timestamp_datetime();
datetime.format("%b %e %Y").to_string()
datetime.strftime("%b %e %Y").to_string()
}
#[must_use]
fn get_git_time() -> String {
let datetime = get_git_timestamp_datetime();
datetime.format("%H:%M:%S").to_string()
datetime.strftime("%H:%M:%S").to_string()
}
fn rustc_version() -> String {
+46 -58
View File
@@ -25,12 +25,9 @@ mod decl {
common::wtf8::Wtf8Buf,
convert::{ToPyException, ToPyObject},
};
#[cfg(not(any(unix, windows)))]
use chrono::{
DateTime, Datelike, TimeZone, Timelike,
naive::{NaiveDate, NaiveDateTime, NaiveTime},
};
use core::time::Duration;
#[cfg(not(any(unix, windows)))]
use jiff::{Timestamp, Zoned, civil::DateTime, tz::TimeZone};
#[cfg(target_os = "wasi")]
use rustpython_host_env::time::ClockId;
#[cfg(any(unix, windows))]
@@ -289,10 +286,7 @@ mod decl {
}
#[cfg(not(any(unix, windows)))]
fn pyobj_to_date_time(
value: Either<f64, i64>,
vm: &VirtualMachine,
) -> PyResult<DateTime<chrono::offset::Utc>> {
fn pyobj_to_timestamp(value: Either<f64, i64>, vm: &VirtualMachine) -> PyResult<Timestamp> {
let secs = match value {
Either::A(float) => {
if !float.is_finite() {
@@ -302,19 +296,19 @@ mod decl {
}
Either::B(int) => int,
};
DateTime::<chrono::offset::Utc>::from_timestamp(secs, 0)
.ok_or_else(|| vm.new_overflow_error("timestamp out of range for platform time_t"))
Timestamp::from_second(secs)
.map_err(|_| vm.new_overflow_error("timestamp out of range for platform time_t"))
}
#[cfg(not(any(unix, windows)))]
impl OptionalArg<Option<Either<f64, i64>>> {
/// Construct a localtime from the optional seconds, or get the current local time.
fn naive_or_local(self, vm: &VirtualMachine) -> PyResult<NaiveDateTime> {
fn naive_or_local(self, vm: &VirtualMachine) -> PyResult<Zoned> {
Ok(match self {
Self::Present(Some(secs)) => pyobj_to_date_time(secs, vm)?
.with_timezone(&chrono::Local)
.naive_local(),
Self::Present(None) | Self::Missing => chrono::offset::Local::now().naive_local(),
Self::Present(Some(secs)) => {
pyobj_to_timestamp(secs, vm)?.to_zoned(TimeZone::system())
}
Self::Present(None) | Self::Missing => Zoned::now(),
})
}
}
@@ -432,10 +426,10 @@ mod decl {
#[cfg(not(any(unix, windows)))]
impl OptionalArg<StructTimeData> {
fn naive_or_local(self, vm: &VirtualMachine) -> PyResult<NaiveDateTime> {
fn naive_or_local(self, vm: &VirtualMachine) -> PyResult<DateTime> {
Ok(match self {
Self::Present(t) => t.to_date_time(vm)?,
Self::Missing => chrono::offset::Local::now().naive_local(),
Self::Missing => Zoned::now().datetime(),
})
}
}
@@ -456,9 +450,9 @@ mod decl {
}
_ => {
let instant = match secs {
OptionalArg::Present(Some(secs)) => pyobj_to_date_time(secs, vm)?.naive_utc(),
OptionalArg::Present(Some(secs)) => pyobj_to_timestamp(secs, vm)?.to_zoned(TimeZone::UTC),
OptionalArg::Present(None) | OptionalArg::Missing => {
chrono::offset::Utc::now().naive_utc()
Zoned::now().with_time_zone(TimeZone::UTC)
}
};
Ok(StructTimeData::new_utc(vm, instant))
@@ -481,7 +475,7 @@ mod decl {
}
_ => {
let instant = secs.naive_or_local(vm)?;
Ok(StructTimeData::new_local(vm, instant, 0))
StructTimeData::new_local(vm, instant.into(), 0)
}
}
}
@@ -502,11 +496,10 @@ mod decl {
{
let datetime = t.to_date_time(vm)?;
// mktime interprets struct_time as local time
let local_dt = chrono::Local
.from_local_datetime(&datetime)
.single()
.ok_or_else(|| vm.new_overflow_error("mktime argument out of range"))?;
let seconds_since_epoch = local_dt.timestamp() as f64;
let local_dt = datetime
.to_zoned(TimeZone::system())
.map_err(|_| vm.new_overflow_error("mktime argument out of range"))?;
let seconds_since_epoch = local_dt.timestamp().as_second() as f64;
Ok(seconds_since_epoch)
}
}
@@ -534,7 +527,7 @@ mod decl {
#[cfg(not(any(unix, windows)))]
{
let instant = t.naive_or_local(vm)?;
let formatted_time = instant.format(CFMT).to_string();
let formatted_time = instant.strftime(CFMT).to_string();
Ok(vm.ctx.new_str(formatted_time).into())
}
}
@@ -555,7 +548,7 @@ mod decl {
#[cfg(not(any(unix, windows)))]
{
let instant = secs.naive_or_local(vm)?;
Ok(instant.format(CFMT).to_string())
Ok(instant.strftime(CFMT).to_string())
}
}
@@ -645,7 +638,7 @@ mod decl {
};
let mut formatted_time = String::new();
write!(&mut formatted_time, "{}", instant.format(&fmt_lossy))
write!(&mut formatted_time, "{}", instant.strftime(&*fmt_lossy))
.unwrap_or_else(|_| formatted_time = format.to_string());
Ok(vm.ctx.new_str(formatted_time).into())
}
@@ -757,13 +750,7 @@ mod decl {
impl StructTimeData {
#[cfg(not(any(unix, windows)))]
fn new_inner(
vm: &VirtualMachine,
tm: NaiveDateTime,
isdst: i32,
gmtoff: i32,
zone: &str,
) -> Self {
fn new_inner(vm: &VirtualMachine, tm: Zoned, isdst: i32) -> Self {
Self {
tm_year: vm.ctx.new_int(tm.year()).into(),
tm_mon: vm.ctx.new_int(tm.month()).into(),
@@ -771,46 +758,47 @@ mod decl {
tm_hour: vm.ctx.new_int(tm.hour()).into(),
tm_min: vm.ctx.new_int(tm.minute()).into(),
tm_sec: vm.ctx.new_int(tm.second()).into(),
tm_wday: vm.ctx.new_int(tm.weekday().num_days_from_monday()).into(),
tm_yday: vm.ctx.new_int(tm.ordinal()).into(),
tm_wday: vm.ctx.new_int(tm.weekday().to_sunday_zero_offset()).into(),
tm_yday: vm.ctx.new_int(tm.day_of_year()).into(),
tm_isdst: vm.ctx.new_int(isdst).into(),
tm_zone: vm.ctx.new_str(zone).into(),
tm_gmtoff: vm.ctx.new_int(gmtoff).into(),
tm_zone: vm.ctx.new_str(tm.strftime("%Z").to_string()).into(),
tm_gmtoff: vm.ctx.new_int(tm.offset().seconds()).into(),
}
}
/// Create struct_time for UTC (gmtime)
#[cfg(not(any(unix, windows)))]
fn new_utc(vm: &VirtualMachine, tm: NaiveDateTime) -> Self {
Self::new_inner(vm, tm, 0, 0, "UTC")
fn new_utc(vm: &VirtualMachine, tm: Zoned) -> Self {
Self::new_inner(vm, tm, 0)
}
/// Create struct_time for local timezone (localtime)
#[cfg(not(any(unix, windows)))]
fn new_local(vm: &VirtualMachine, tm: NaiveDateTime, isdst: i32) -> Self {
let local_time = chrono::Local.from_local_datetime(&tm).unwrap();
let offset_seconds = local_time.offset().local_minus_utc();
let tz_abbr = local_time.format("%Z").to_string();
Self::new_inner(vm, tm, isdst, offset_seconds, &tz_abbr)
fn new_local(vm: &VirtualMachine, tm: DateTime, isdst: i32) -> PyResult<Self> {
tm.to_zoned(TimeZone::system())
.map(|tm| Self::new_inner(vm, tm, isdst))
.map_err(|_| {
vm.new_overflow_error("timestamp is ambiguous for the system timezone")
})
}
#[cfg(not(any(unix, windows)))]
fn to_date_time(&self, vm: &VirtualMachine) -> PyResult<NaiveDateTime> {
let invalid_overflow = || vm.new_overflow_error("mktime argument out of range");
let invalid_value = || vm.new_value_error("invalid struct_time parameter");
fn to_date_time(&self, vm: &VirtualMachine) -> PyResult<DateTime> {
macro_rules! field {
($field:ident) => {
self.$field.clone().try_into_value(vm)?
};
}
let dt = NaiveDateTime::new(
NaiveDate::from_ymd_opt(field!(tm_year), field!(tm_mon), field!(tm_mday))
.ok_or_else(invalid_value)?,
NaiveTime::from_hms_opt(field!(tm_hour), field!(tm_min), field!(tm_sec))
.ok_or_else(invalid_overflow)?,
);
Ok(dt)
DateTime::new(
field!(tm_year),
field!(tm_mon),
field!(tm_mday),
field!(tm_hour),
field!(tm_min),
field!(tm_sec),
0,
)
.map_err(|_| vm.new_overflow_error("mktime argument out of range"))
}
}