{"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/fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e/crates/polars-arrow/src/temporal_conversions.rs#L29-L65","documentation":"`date32_to_date` converts an i32 day count (days since Unix epoch) into a `NaiveDate` by adding `EPOCH_DAYS_FROM_CE`. The underlying `date32_to_date_opt` uses `NaiveDate::from_num_days_from_ce_opt`, which returns `None` when the total days-since-CE value is outside chrono's supported date range; the wrapper then panics with \"out-of-range date\".","triggerScenarios":"Calling `date32_to_date(days)` where `EPOCH_DAYS_FROM_CE + days` exceeds chrono's `NaiveDate` limits (~±262,000 years from year 1 CE), e.g. `days = i32::MAX` or heavily negative values.","commonSituations":"Sentinel/garbage values in a date32 column; display/formatting paths (`to_string`, `any_value_into_py_object`) encountering unvalidated data; tests using extreme values.","solutions":["Use `date32_to_date_opt(days)` and handle `None` instead of the panicking wrapper.","Range-check the day value before conversion (e.g. keep `EPOCH_DAYS_FROM_CE + days` within chrono's limits).","Scrub sentinel values from the source data before calling the converter."],"exampleFix":"// before\nlet d = date32_to_date(days); // panics on extreme input\n// after\nlet d = date32_to_date_opt(days)\n    .ok_or_else(|| anyhow!(\"date32 days {days} out of range\"))?;","handlingStrategy":"validation","validationCode":"fn date32_days_in_range(days: i32) -> bool {\n    NaiveDate::from_num_days_from_ce_opt(EPOCH_DAYS_FROM_CE + days).is_some()\n}","typeGuard":null,"tryCatchPattern":"match date32_to_date_opt(days) {\n    Some(d) => /* use d */,\n    None => /* treat as corrupt/null value */,\n}","preventionTips":["Prefer `date32_to_date_opt` everywhere, especially in display/format paths","Validate incoming date32 data before passing to string/PyObject converters","Keep test fixtures within chrono's supported calendar range"],"tags":["arrow","chrono","date","out-of-range"],"backgroundTag":"value-out-of-range","analyzedSha":"fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e","analyzedAt":"2026-09-18T22:14:11.667Z","contentChangedAt":"2026-09-18T22:14:11.667Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}