{"record":{"id":"1157f20e0b89ed17","repo":"PyO3/pyo3","slug":"ignored-leap-second-datetime-does-not-support-l","errorCode":null,"errorMessage":"ignored leap-second, `datetime` does not support leap-seconds","messagePattern":"ignored leap-second, `datetime` does not support leap-seconds","errorType":"console","errorClass":"PyUserWarning","httpStatus":null,"severity":"warning","filePath":"src/conversions/chrono.rs","lineNumber":623,"sourceCode":"impl From<&NaiveTime> for TimeArgs {\n    fn from(value: &NaiveTime) -> Self {\n        let ns = value.nanosecond();\n        let checked_sub = ns.checked_sub(1_000_000_000);\n        let truncated_leap_second = checked_sub.is_some();\n        let micro = checked_sub.unwrap_or(ns) / 1000;\n        Self {\n            hour: value.hour() as u8,\n            min: value.minute() as u8,\n            sec: value.second() as u8,\n            micro,\n            truncated_leap_second,\n        }\n    }\n}\n\nfn warn_truncated_leap_second(obj: &Bound<'_, PyAny>) {\n    let py = obj.py();\n    if let Err(e) = PyErr::warn(\n        py,\n        &py.get_type::<PyUserWarning>(),\n        c\"ignored leap-second, `datetime` does not support leap-seconds\",\n        0,\n    ) {\n        e.write_unraisable(py, Some(obj))\n    };\n}\n\n#[cfg(not(Py_LIMITED_API))]\nfn py_date_to_naive_date(\n    py_date: impl core::ops::Deref<Target = impl PyDateAccess>,\n) -> PyResult<NaiveDate> {\n    NaiveDate::from_ymd_opt(\n        py_date.get_year(),\n        py_date.get_month().into(),\n        py_date.get_day().into(),\n    )","sourceCodeStart":605,"sourceCodeEnd":641,"githubUrl":"https://github.com/PyO3/pyo3/blob/ac9b6899d348be4d54614d060dea53a645a12e36/src/conversions/chrono.rs#L605-L641","documentation":"This is not a panic but a warning emitted by pyo3's chrono integration: Python's `datetime` has no leap-second representation, so a `chrono::NaiveDateTime` whose nanosecond field encodes a leap second (nanoseconds >= 1_000_000_000) cannot be converted losslessly. pyo3 emits a `PyUserWarning` ('ignored leap-second') and truncates the leap second to a full second. If issuing the warning itself fails, the error is written as unraisable.","triggerScenarios":"Converting a chrono `NaiveDateTime`/`DateTime` with leap-second nanoseconds (e.g. from `chrono::DateTime::from_timestamp(…, 1_999_999_999)` or parsed leap-second data) to Python via `IntoPyObject`/`into_pyobject` for `PyDateTime`.","commonSituations":"Ingesting high-precision timestamps from scientific or GPS/time-source data (TAI/GPS offsets, leap-second tables) and passing them to Python datetime objects, which silently drops the extra nanoseconds.","solutions":["Normalize the chrono timestamp before conversion (e.g. truncate nanoseconds below 1_000_000_000 or round)","Check and handle the nanosecond field explicitly (`dt.nanosecond() >= 1_000_000_000`) and log/adjust in Rust instead of relying on the warning","Keep the data as a higher-precision type (e.g. integer nanoseconds since epoch) rather than Python datetime","Suppress/expect the UserWarning on the Python side if truncation is acceptable"],"exampleFix":"// before\nlet py_dt = chrono_dt.into_pyobject(py)?; // warns, truncates leap second\n// after\nlet dt = if chrono_dt.nanosecond() >= 1_000_000_000 {\n    chrono_dt - chrono::Duration::nanoseconds((chrono_dt.nanosecond() - 999_999_999) as i64)\n} else { chrono_dt };\nlet py_dt = dt.into_pyobject(py)?; // no leap second to truncate","handlingStrategy":"validation","validationCode":"fn has_leap_second(dt: &chrono::NaiveDateTime) -> bool {\n    dt.nanosecond() >= 1_000_000_000\n}\n// before conversion: assert/normalize if has_leap_second(&dt)","typeGuard":null,"tryCatchPattern":"// Python side: expect the UserWarning if truncation is acceptable\nimport warnings\nwith warnings.catch_warnings(record=True) as w:\n    warnings.simplefilter(\"always\")\n    py_dt = convert(dt)\n    if any('leap-second' in str(x.message) for x in w):\n        ...  # handle or log precision loss","preventionTips":["Normalize chrono timestamps (truncate/round nanoseconds >= 1_000_000_000) before crossing into Python","Model leap seconds with explicit TAI/UTC conversion instead of encoding them in nanoseconds","If nanosecond precision matters, keep data in integer-nanosecond form rather than Python datetime","Run conversion under a warnings filter during tests to detect silent truncation"],"tags":["rust","pyo3","chrono","datetime","precision-loss"],"backgroundTag":"leap-second-truncation","analyzedSha":"ac9b6899d348be4d54614d060dea53a645a12e36","analyzedAt":"2026-09-05T09:20:35.319Z","contentChangedAt":"2026-09-05T09:20:35.319Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}