diff --git a/crates/nu-command/tests/commands/into_datetime.rs b/crates/nu-command/tests/commands/into_datetime.rs index 83f36a7c26..8ad096ef0a 100644 --- a/crates/nu-command/tests/commands/into_datetime.rs +++ b/crates/nu-command/tests/commands/into_datetime.rs @@ -14,6 +14,16 @@ fn into_datetime_from_record() { assert_eq!(expected.out, actual.out); } +#[test] +fn into_datetime_from_record_very_old() { + let actual = nu!(r#"{year: -100, timezone: '+02:00'} | into datetime | into record"#); + let expected = nu!( + r#"{year: -100, month: 1, day: 1, hour: 0, minute: 0, second: 0, millisecond: 0, microsecond: 0, nanosecond: 0, timezone: '+02:00'}"# + ); + + assert_eq!(expected.out, actual.out); +} + #[test] fn into_datetime_from_record_defaults() { let actual = nu!(r#"{year: 2025, timezone: '+02:00'} | into datetime | into record"#); diff --git a/crates/nu-protocol/src/value/mod.rs b/crates/nu-protocol/src/value/mod.rs index 2d820b044a..0aac797c8d 100644 --- a/crates/nu-protocol/src/value/mod.rs +++ b/crates/nu-protocol/src/value/mod.rs @@ -4020,10 +4020,19 @@ fn operator_type_error( fn human_time_from_now(val: &DateTime) -> HumanTime { let now = Local::now().with_timezone(val.offset()); let delta = *val - now; - let delta_seconds = delta.num_nanoseconds().unwrap_or(0) as f64 / 1_000_000_000.0; - let delta_seconds_rounded = delta_seconds.round() as i64; - - HumanTime::from(Duration::seconds(delta_seconds_rounded)) + match delta.num_nanoseconds() { + Some(num_nanoseconds) => { + let delta_seconds = num_nanoseconds as f64 / 1_000_000_000.0; + let delta_seconds_rounded = delta_seconds.round() as i64; + HumanTime::from(Duration::seconds(delta_seconds_rounded)) + } + None => { + // Happens if the total number of nanoseconds exceeds what fits in an i64 + // Note: not using delta.num_days() because it results is wrong for years before ~936: a extra year is added + let delta_years = val.year() - now.year(); + HumanTime::from(Duration::days(delta_years as i64 * 365)) + } + } } #[cfg(test)]