mirror of
https://github.com/nushell/nushell.git
synced 2025-04-24 13:18:18 +02:00
Bugfix chrono panic + hotifx PR15544 (#15549)
Closes #13972 # Description First commit: a hotfix concerning my last PR #15544! I had a ``unwrap_or_default`` that resulted in all years before ~1800 being considered as "now", because the ``num_nanoseconds()`` overflowed. Cc @fdncred Second: about #13972 Negative years are not allowed with RFC 2822 formatting, so I fallback RTC 3339 in such cases. If you want you might Rebase and Merge, and not squash. # User-Facing Changes On master 🔴 : ```nu ~> {year: 1900} | into datetime Mon, 1 Jan 1900 00:00:00 +0200 (125 years ago) # OK ~> {year: 1000} | into datetime Wed, 1 Jan 1000 00:00:00 +0200 (now) # NOT OK: now? ~> {year: -1000} | into datetime -1000-01-01T00:00:00+02:00 (now) # NOT OK: now? ~> {year: -1000} | into datetime | format date Error: × Main thread panicked. ├─▶ at C:\Users\RIL1RT\.cargo\registry\src\index.crates.io-6f17d22bba15001f\chrono-0.4.39\src\datetime\mod.rs:626:14 ╰─▶ writing rfc2822 datetime to string should never fail: Error help: set the `RUST_BACKTRACE=1` environment variable to display a backtrace. # NOT OK: panics ``` On this branch 🟢 : ```nu ~> {year: 1900} | into datetime Mon, 1 Jan 1900 00:00:00 +0200 (in 125 years) ~> {year: 1000} | into datetime Wed, 1 Jan 1000 00:00:00 +0200 (1025 years ago) ~> {year: -1000} | into datetime -1000-01-01T00:00:00+02:00 (3025 years ago) ~> {year: -1000} | into datetime | format date -1000-01-01T00:00:00+02:00 ~> '3000 years ago' | date from-human | format date -0975-04-11T18:18:24.301641100+02:00 ``` # Tests + Formatting # After Submitting Nothing required IMO
This commit is contained in:
parent
1a0778d77e
commit
c8c018452f
@ -1,3 +1,4 @@
|
|||||||
|
use chrono::Datelike;
|
||||||
use chrono_humanize::HumanTime;
|
use chrono_humanize::HumanTime;
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
use nu_protocol::{format_duration, shell_error::io::IoError, ByteStream, PipelineMetadata};
|
use nu_protocol::{format_duration, shell_error::io::IoError, ByteStream, PipelineMetadata};
|
||||||
@ -167,7 +168,17 @@ fn local_into_string(
|
|||||||
Value::Filesize { val, .. } => val.to_string(),
|
Value::Filesize { val, .. } => val.to_string(),
|
||||||
Value::Duration { val, .. } => format_duration(val),
|
Value::Duration { val, .. } => format_duration(val),
|
||||||
Value::Date { val, .. } => {
|
Value::Date { val, .. } => {
|
||||||
format!("{} ({})", val.to_rfc2822(), HumanTime::from(val))
|
format!(
|
||||||
|
"{} ({})",
|
||||||
|
{
|
||||||
|
if val.year() >= 0 {
|
||||||
|
val.to_rfc2822()
|
||||||
|
} else {
|
||||||
|
val.to_rfc3339()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
HumanTime::from(val)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
Value::Range { val, .. } => val.to_string(),
|
Value::Range { val, .. } => val.to_string(),
|
||||||
Value::String { val, .. } => val,
|
Value::String { val, .. } => val,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{generate_strftime_list, parse_date_from_string};
|
use crate::{generate_strftime_list, parse_date_from_string};
|
||||||
use chrono::{DateTime, Locale, TimeZone};
|
use chrono::{DateTime, Datelike, Locale, TimeZone};
|
||||||
use nu_engine::command_prelude::*;
|
use nu_engine::command_prelude::*;
|
||||||
|
|
||||||
use nu_utils::locale::{get_system_locale_string, LOCALE_OVERRIDE_ENV_VAR};
|
use nu_utils::locale::{get_system_locale_string, LOCALE_OVERRIDE_ENV_VAR};
|
||||||
@ -228,11 +228,29 @@ fn format_helper(
|
|||||||
fn format_helper_rfc2822(value: Value, span: Span) -> Value {
|
fn format_helper_rfc2822(value: Value, span: Span) -> Value {
|
||||||
let val_span = value.span();
|
let val_span = value.span();
|
||||||
match value {
|
match value {
|
||||||
Value::Date { val, .. } => Value::string(val.to_rfc2822(), span),
|
Value::Date { val, .. } => Value::string(
|
||||||
|
{
|
||||||
|
if val.year() >= 0 {
|
||||||
|
val.to_rfc2822()
|
||||||
|
} else {
|
||||||
|
val.to_rfc3339()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
),
|
||||||
Value::String { val, .. } => {
|
Value::String { val, .. } => {
|
||||||
let dt = parse_date_from_string(&val, val_span);
|
let dt = parse_date_from_string(&val, val_span);
|
||||||
match dt {
|
match dt {
|
||||||
Ok(x) => Value::string(x.to_rfc2822(), span),
|
Ok(x) => Value::string(
|
||||||
|
{
|
||||||
|
if x.year() >= 0 {
|
||||||
|
x.to_rfc2822()
|
||||||
|
} else {
|
||||||
|
x.to_rfc3339()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
span,
|
||||||
|
),
|
||||||
Err(e) => e,
|
Err(e) => e,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,16 @@ fn into_datetime_from_record() {
|
|||||||
assert_eq!(expected.out, actual.out);
|
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]
|
#[test]
|
||||||
fn into_datetime_from_record_defaults() {
|
fn into_datetime_from_record_defaults() {
|
||||||
let actual = nu!(r#"{year: 2025, timezone: '+02:00'} | into datetime | into record"#);
|
let actual = nu!(r#"{year: 2025, timezone: '+02:00'} | into datetime | into record"#);
|
||||||
|
@ -4020,10 +4020,19 @@ fn operator_type_error(
|
|||||||
fn human_time_from_now(val: &DateTime<FixedOffset>) -> HumanTime {
|
fn human_time_from_now(val: &DateTime<FixedOffset>) -> HumanTime {
|
||||||
let now = Local::now().with_timezone(val.offset());
|
let now = Local::now().with_timezone(val.offset());
|
||||||
let delta = *val - now;
|
let delta = *val - now;
|
||||||
let delta_seconds = delta.num_nanoseconds().unwrap_or(0) as f64 / 1_000_000_000.0;
|
match delta.num_nanoseconds() {
|
||||||
let delta_seconds_rounded = delta_seconds.round() as i64;
|
Some(num_nanoseconds) => {
|
||||||
|
let delta_seconds = num_nanoseconds as f64 / 1_000_000_000.0;
|
||||||
HumanTime::from(Duration::seconds(delta_seconds_rounded))
|
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)]
|
#[cfg(test)]
|
||||||
|
Loading…
Reference in New Issue
Block a user