pola-rs/polars · error
invalid or out-of-range datetime
Error message
invalid or out-of-range datetime
What it means
Panics inside date32_to_datetime when an i32 date32 value (days since 1970-01-01) cannot become a chrono NaiveDateTime: TimeDelta::try_days fails or unix_epoch().checked_add_signed(delta) overflows chrono's representable range (roughly years -262144..262143). i32 extremes span about +/-5.8 million days, far outside that window, so extreme or sentinel values panic instead of producing null.
Source
Thrown at crates/polars-arrow/src/temporal_conversions.rs:34
pub const NANOSECONDS: i64 = 1_000_000_000;
/// Number of milliseconds in a day
pub const MILLISECONDS_IN_DAY: i64 = SECONDS_IN_DAY * MILLISECONDS;
/// Number of microseconds in a day
pub const MICROSECONDS_IN_DAY: i64 = SECONDS_IN_DAY * MICROSECONDS;
/// Number of nanoseconds in a day
pub const NANOSECONDS_IN_DAY: i64 = SECONDS_IN_DAY * NANOSECONDS;
/// Number of days between 0001-01-01 and 1970-01-01
pub const EPOCH_DAYS_FROM_CE: i32 = 719_163;
#[inline]
fn unix_epoch() -> NaiveDateTime {
DateTime::UNIX_EPOCH.naive_utc()
}
/// converts a `i32` representing a `date32` to [`NaiveDateTime`]
#[inline]
pub fn date32_to_datetime(v: i32) -> NaiveDateTime {
date32_to_datetime_opt(v).expect("invalid or out-of-range datetime")
}
/// converts a `i32` representing a `date32` to [`NaiveDateTime`]
#[inline]
pub fn date32_to_datetime_opt(v: i32) -> Option<NaiveDateTime> {
let delta = TimeDelta::try_days(v.into())?;
unix_epoch().checked_add_signed(delta)
}
/// converts a `i32` representing a `date32` to [`NaiveDate`]
#[inline]
pub fn date32_to_date(days: i32) -> NaiveDate {
date32_to_date_opt(days).expect("out-of-range date")
}
/// converts a `i32` representing a `date32` to [`NaiveDate`]
#[inline]
pub fn date32_to_date_opt(days: i32) -> Option<NaiveDate> {View on GitHub (pinned to df599052da)
Solutions
- Use the fallible sibling date32_to_datetime_opt(v) and map None to null or skip the row
- Sanitize the column first: null out or clip values outside chrono's date range
- Fix the upstream unit/type mismatch before converting
- Prefer high-level Polars casts (strict=False) which produce nulls instead of panicking
Example fix
// before
let dt = date32_to_datetime(days); // panics on i32::MIN/MAX
// after
let dt = match date32_to_datetime_opt(days) {
Some(dt) => dt,
None => continue, // or insert a null
}; Defensive patterns
Strategy: validation
Validate before calling
use polars_arrow::temporal_conversions::date32_to_datetime_opt;
let valid: Vec<i32> = days.iter()
.copied()
.filter(|&d| date32_to_datetime_opt(d).is_some())
.collect(); Type guard
fn date32_representable(days: i32) -> bool {
polars_arrow::temporal_conversions::date32_to_datetime_opt(days).is_some()
} Prevention
- Prefer the _opt conversion variants in any code touching untrusted temporal data
- Null out sentinel values (i32::MIN/MAX) before Date -> Datetime conversions
- Verify producer/consumer agree on date32 units (days, not ms)
- Keep conversion panics out of request handlers by validating batches at ingestion
When it happens
Trigger: Calling date32_to_datetime (directly or via Date-to-Datetime temporal kernels) on data containing i32::MIN, i32::MAX, or garbage - e.g. millisecond epochs mistakenly stored in a date32 column.
Common situations: Unit mismatches between producer and consumer (epoch-ms written into a Date column); corrupt binary or misparsed CSVs interpreted as dates; arrow data from other systems with uninitialized values.
Related errors
- out-of-range date
- invalid time
- out-of-range duration
- out-of-range in duration conversion
- not implemented
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/040bb505d15f0329.
Report an issue: GitHub.