{"record":{"id":"b1280f24e456c281","repo":"pola-rs/polars","slug":"out-of-range-date","errorCode":null,"errorMessage":"out-of-range date","messagePattern":"out-of-range date","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/polars-arrow/src/temporal_conversions.rs","lineNumber":47,"sourceCode":"}\n\n/// converts a `i32` representing a `date32` to [`NaiveDateTime`]\n#[inline]\npub fn date32_to_datetime(v: i32) -> NaiveDateTime {\n    date32_to_datetime_opt(v).expect(\"invalid or out-of-range datetime\")\n}\n\n/// converts a `i32` representing a `date32` to [`NaiveDateTime`]\n#[inline]\npub fn date32_to_datetime_opt(v: i32) -> Option<NaiveDateTime> {\n    let delta = TimeDelta::try_days(v.into())?;\n    unix_epoch().checked_add_signed(delta)\n}\n\n/// converts a `i32` representing a `date32` to [`NaiveDate`]\n#[inline]\npub fn date32_to_date(days: i32) -> NaiveDate {\n    date32_to_date_opt(days).expect(\"out-of-range date\")\n}\n\n/// converts a `i32` representing a `date32` to [`NaiveDate`]\n#[inline]\npub fn date32_to_date_opt(days: i32) -> Option<NaiveDate> {\n    NaiveDate::from_num_days_from_ce_opt(EPOCH_DAYS_FROM_CE + days)\n}\n\n/// converts a `i64` representing a `date64` to [`NaiveDateTime`]\n#[inline]\npub fn date64_to_datetime(v: i64) -> NaiveDateTime {\n    TimeDelta::try_milliseconds(v)\n        .and_then(|delta| unix_epoch().checked_add_signed(delta))\n        .expect(\"invalid or out-of-range datetime\")\n}\n\n/// converts a `i64` representing a `date64` to [`NaiveDate`]\n#[inline]","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/crates/polars-arrow/src/temporal_conversions.rs#L29-L65","documentation":"Panics inside date32_to_date when NaiveDate::from_num_days_from_ce_opt(EPOCH_DAYS_FROM_CE + days) returns None, i.e. the i32 day count falls outside chrono NaiveDate's representable span (about years -262144..262143). The infallible wrapper uses .expect('out-of-range date') so out-of-range physical values abort rather than yield null.","triggerScenarios":"Converting a Date array to calendar dates when it holds sentinel or corrupt values (i32::MIN, i32::MAX) - common when a millisecond-epoch column was misdeclared as date32.","commonSituations":"Schema drift between writer and reader; corrupt parquet/IPC sources; uninitialized buffers read as dates; fuzzed inputs.","solutions":["Use date32_to_date_opt(days) and handle None (null/skip)","Validate day counts against chrono's range before conversion","Fix the upstream unit mismatch that put non-day values in the column","Use Polars-level casts with strict=False so bad values become null"],"exampleFix":"// before\nlet d = date32_to_date(days); // panics for out-of-range days\n\n// after\nlet d = date32_to_date_opt(days); // Option<NaiveDate>\nlet d = d.unwrap_or_default(); // or propagate as null","handlingStrategy":"validation","validationCode":"use polars_arrow::temporal_conversions::date32_to_date_opt;\n\nif date32_to_date_opt(days).is_none() {\n    // treat as null / corrupt value\n}","typeGuard":"fn date32_in_chrono_range(days: i32) -> bool {\n    polars_arrow::temporal_conversions::date32_to_date_opt(days).is_some()\n}","tryCatchPattern":null,"preventionTips":["Use date32_to_date_opt instead of the panicking wrapper on untrusted data","Scan Date columns for i32 extremes before calendar formatting","Pin down units in schemas at write time to avoid ms-in-days drift","Let invalid values become null via non-strict casts where semantics allow"],"tags":["rust","polars","arrow","temporal","date","panic"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}