diff --git a/Cargo.lock b/Cargo.lock index 82fdab228..b45ccdd36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -481,9 +481,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.22" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1" +checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" dependencies = [ "iana-time-zone", "js-sys", diff --git a/Cargo.toml b/Cargo.toml index 6e5e377c0..afea76437 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ members = [ ] [dependencies] -chrono = { version = "0.4.21", features = ["serde"] } +chrono = { version = "0.4.23", features = ["serde"] } crossterm = "0.24.0" ctrlc = "3.2.1" log = "0.4" diff --git a/crates/nu-cli/Cargo.toml b/crates/nu-cli/Cargo.toml index 808b42a43..07f0e73bd 100644 --- a/crates/nu-cli/Cargo.toml +++ b/crates/nu-cli/Cargo.toml @@ -23,7 +23,7 @@ nu-color-config = { path = "../nu-color-config", version = "0.71.1" } reedline = { version = "0.14.0", features = ["bashisms", "sqlite"]} atty = "0.2.14" -chrono = { default-features = false, features = ["std"], version = "0.4.21" } +chrono = { default-features = false, features = ["std"], version = "0.4.23" } crossterm = "0.24.0" fancy-regex = "0.10.0" fuzzy-matcher = "0.3.7" diff --git a/crates/nu-command/Cargo.toml b/crates/nu-command/Cargo.toml index 1a82c93e5..ac3e38eee 100644 --- a/crates/nu-command/Cargo.toml +++ b/crates/nu-command/Cargo.toml @@ -32,7 +32,7 @@ base64 = "0.13.0" byteorder = "1.4.3" bytesize = "1.1.0" calamine = "0.18.0" -chrono = { version = "0.4.21", features = ["unstable-locales", "std"], default-features = false } +chrono = { version = "0.4.23", features = ["unstable-locales", "std"], default-features = false } chrono-humanize = "0.2.1" chrono-tz = "0.6.3" crossterm = "0.24.0" diff --git a/crates/nu-command/src/conversions/into/datetime.rs b/crates/nu-command/src/conversions/into/datetime.rs index 01e238f91..3c0289a15 100644 --- a/crates/nu-command/src/conversions/into/datetime.rs +++ b/crates/nu-command/src/conversions/into/datetime.rs @@ -1,6 +1,6 @@ use crate::input_handler::{operate, CmdArgument}; use crate::{generate_strftime_list, parse_date_from_string}; -use chrono::{DateTime, FixedOffset, Local, TimeZone, Utc}; +use chrono::{DateTime, FixedOffset, Local, LocalResult, TimeZone, Utc}; use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::ast::CellPath; @@ -147,38 +147,63 @@ impl Command for SubCommand { } fn examples(&self) -> Vec { + let example_result_1 = |secs: i64, nsecs: u32| { + let dt = match Utc.timestamp_opt(secs, nsecs) { + LocalResult::Single(dt) => Some(dt), + _ => None, + }; + match dt { + Some(dt) => Some(Value::Date { + val: dt.into(), + span: Span::test_data(), + }), + None => Some(Value::Error { + error: ShellError::UnsupportedInput( + "The given datetime representation is unsupported.".to_string(), + Span::test_data(), + ), + }), + } + }; + let example_result_2 = |millis: i64| { + let dt = match Utc.timestamp_millis_opt(millis) { + LocalResult::Single(dt) => Some(dt), + _ => None, + }; + match dt { + Some(dt) => Some(Value::Date { + val: dt.into(), + span: Span::test_data(), + }), + None => Some(Value::Error { + error: ShellError::UnsupportedInput( + "The given datetime representation is unsupported.".to_string(), + Span::test_data(), + ), + }), + } + }; vec![ Example { description: "Convert to datetime", example: "'27.02.2021 1:55 pm +0000' | into datetime", - result: Some(Value::Date { - val: Utc.timestamp(1614434100, 0).into(), - span: Span::test_data(), - }), + result: example_result_1(1614434100,0) }, Example { description: "Convert to datetime", example: "'2021-02-27T13:55:40+00:00' | into datetime", - result: Some(Value::Date { - val: Utc.timestamp(1614434140, 0).into(), - span: Span::test_data(), - }), + result: example_result_1(1614434140, 0) }, Example { description: "Convert to datetime using a custom format", example: "'20210227_135540+0000' | into datetime -f '%Y%m%d_%H%M%S%z'", - result: Some(Value::Date { - val: Utc.timestamp(1614434140, 0).into(), - span: Span::test_data(), - }), + result: example_result_1(1614434140, 0) + }, Example { description: "Convert timestamp (no larger than 8e+12) to a UTC datetime", example: "1614434140 | into datetime", - result: Some(Value::Date { - val: Utc.timestamp(1614434140, 0).into(), - span: Span::test_data(), - }), + result: example_result_1(1614434140, 0) }, Example { description: @@ -190,10 +215,7 @@ impl Command for SubCommand { description: "Convert timestamps like the sqlite history t", example: "1656165681720 | into datetime", - result: Some(Value::Date { - val: Utc.timestamp_millis(1656165681720).into(), - span: Span::test_data(), - }), + result: example_result_2(1656165681720) }, ] } @@ -239,8 +261,31 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value { // be able to convert chrono::Utc::now() let dt = match ts.to_string().len() { x if x > 13 => Utc.timestamp_nanos(ts).into(), - x if x > 10 => Utc.timestamp_millis(ts).into(), - _ => Utc.timestamp(ts, 0).into(), + x if x > 10 => match Utc.timestamp_millis_opt(ts) { + LocalResult::Single(dt) => dt.into(), + _ => { + return Value::Error { + // This error message is from chrono + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid." + .to_string(), + head, + ), + }; + } + }, + _ => match Utc.timestamp_opt(ts, 0) { + LocalResult::Single(dt) => dt.into(), + _ => { + return Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid." + .to_string(), + head, + ), + } + } + }, }; Value::Date { @@ -249,28 +294,64 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value { } } Some(Spanned { item, span }) => match item { - Zone::Utc => Value::Date { - val: Utc.timestamp(ts, 0).into(), - span: head, - }, - Zone::Local => Value::Date { - val: Local.timestamp(ts, 0).into(), - span: head, - }, - Zone::East(i) => { - let eastoffset = FixedOffset::east((*i as i32) * HOUR); - Value::Date { - val: eastoffset.timestamp(ts, 0), + Zone::Utc => match Utc.timestamp_opt(ts, 0) { + LocalResult::Single(val) => Value::Date { + val: val.into(), span: head, - } - } - Zone::West(i) => { - let westoffset = FixedOffset::west((*i as i32) * HOUR); - Value::Date { - val: westoffset.timestamp(ts, 0), + }, + _ => Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid.".to_string(), + *span, + ), + }, + }, + Zone::Local => match Local.timestamp_opt(ts, 0) { + LocalResult::Single(val) => Value::Date { + val: val.into(), span: head, - } - } + }, + _ => Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid.".to_string(), + *span, + ), + }, + }, + Zone::East(i) => match FixedOffset::east_opt((*i as i32) * HOUR) { + Some(eastoffset) => match eastoffset.timestamp_opt(ts, 0) { + LocalResult::Single(val) => Value::Date { val, span: head }, + _ => Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid.".to_string(), + *span, + ), + }, + }, + None => Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid.".to_string(), + *span, + ), + }, + }, + Zone::West(i) => match FixedOffset::west_opt((*i as i32) * HOUR) { + Some(westoffset) => match westoffset.timestamp_opt(ts, 0) { + LocalResult::Single(val) => Value::Date { val, span: head }, + _ => Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid.".to_string(), + *span, + ), + }, + }, + None => Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid.".to_string(), + *span, + ), + }, + }, Zone::Error => Value::Error { error: ShellError::UnsupportedInput( "Cannot convert given timezone or offset to timestamp".to_string(), @@ -425,7 +506,7 @@ mod tests { }; let actual = action(&date_str, &args, Span::test_data()); let expected = Value::Date { - val: Local.timestamp(1614434140, 0).into(), + val: Local.timestamp_opt(1614434140, 0).unwrap().into(), span: Span::test_data(), }; @@ -443,7 +524,7 @@ mod tests { let actual = action(&date_str, &args, Span::test_data()); let expected = Value::Date { - val: Utc.timestamp(1614434140, 0).into(), + val: Utc.timestamp_opt(1614434140, 0).unwrap().into(), span: Span::test_data(), }; diff --git a/crates/nu-command/src/dataframe/values/nu_dataframe/conversion.rs b/crates/nu-command/src/dataframe/values/nu_dataframe/conversion.rs index 0322d8b95..c4d448a1d 100644 --- a/crates/nu-command/src/dataframe/values/nu_dataframe/conversion.rs +++ b/crates/nu-command/src/dataframe/values/nu_dataframe/conversion.rs @@ -460,10 +460,31 @@ pub fn create_column( Some(a) => { // elapsed time in day since 1970-01-01 let seconds = a as i64 * SECS_PER_DAY; - let naive_datetime = NaiveDateTime::from_timestamp(seconds, 0); - + let naive_datetime = match NaiveDateTime::from_timestamp_opt(seconds, 0) { + Some(val) => val, + None => { + return Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid." + .to_string(), + span, + ), + } + } + }; // Zero length offset - let offset = FixedOffset::east(0); + let offset = match FixedOffset::east_opt(0) { + Some(val) => val, + None => { + return Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid." + .to_string(), + span, + ), + } + } + }; let datetime = DateTime::::from_utc(naive_datetime, offset); Value::Date { @@ -496,10 +517,31 @@ pub fn create_column( Some(a) => { // elapsed time in milliseconds since 1970-01-01 let seconds = a / 1000; - let naive_datetime = NaiveDateTime::from_timestamp(seconds, 0); - + let naive_datetime = match NaiveDateTime::from_timestamp_opt(seconds, 0) { + Some(val) => val, + None => { + return Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid." + .to_string(), + span, + ), + } + } + }; // Zero length offset - let offset = FixedOffset::east(0); + let offset = match FixedOffset::east_opt(0) { + Some(val) => val, + None => { + return Value::Error { + error: ShellError::UnsupportedInput( + "The given local datetime representation is invalid." + .to_string(), + span, + ), + } + } + }; let datetime = DateTime::::from_utc(naive_datetime, offset); Value::Date { diff --git a/crates/nu-command/src/date/to_timezone.rs b/crates/nu-command/src/date/to_timezone.rs index 7a33c301e..a32f6b380 100644 --- a/crates/nu-command/src/date/to_timezone.rs +++ b/crates/nu-command/src/date/to_timezone.rs @@ -1,6 +1,6 @@ use super::parser::datetime_in_timezone; use crate::date::utils::parse_date_from_string; -use chrono::{DateTime, Local}; +use chrono::{DateTime, Local, LocalResult}; use nu_engine::CallExt; use nu_protocol::ast::Call; use nu_protocol::engine::{Command, EngineState, Stack}; @@ -65,13 +65,25 @@ impl Command for SubCommand { fn examples(&self) -> Vec { let example_result_1 = || { - let dt = FixedOffset::east(5 * 3600) - .ymd(2020, 10, 10) - .and_hms(13, 00, 00); - Some(Value::Date { - val: dt, - span: Span::test_data(), - }) + let dt = match FixedOffset::east_opt(5 * 3600) { + Some(dt) => match dt.with_ymd_and_hms(2020, 10, 10, 13, 00, 00) { + LocalResult::Single(dt) => Some(dt), + _ => None, + }, + _ => None, + }; + match dt { + Some(dt) => Some(Value::Date { + val: dt, + span: Span::test_data(), + }), + None => Some(Value::Error { + error: ShellError::UnsupportedInput( + "The given datetime representation is unsupported.".to_string(), + Span::test_data(), + ), + }), + } }; vec![ diff --git a/crates/nu-command/src/formats/to/toml.rs b/crates/nu-command/src/formats/to/toml.rs index db8cb227f..0ba25709e 100644 --- a/crates/nu-command/src/formats/to/toml.rs +++ b/crates/nu-command/src/formats/to/toml.rs @@ -231,7 +231,7 @@ mod tests { [dependencies] rustyline = "4.1.0" sysinfo = "0.8.4" - chrono = { version = "0.4.21", features = ["serde"] } + chrono = { version = "0.4.23", features = ["serde"] } "#, ), Span::test_data(), diff --git a/crates/nu-command/src/generators/cal.rs b/crates/nu-command/src/generators/cal.rs index dad74beb1..114b05db8 100644 --- a/crates/nu-command/src/generators/cal.rs +++ b/crates/nu-command/src/generators/cal.rs @@ -184,12 +184,12 @@ impl MonthHelper { let next_month_naive_date = NaiveDate::from_ymd_opt(selected_year, selected_month, 1).ok_or(())?; - Ok(next_month_naive_date.pred().day()) + Ok(next_month_naive_date.pred_opt().unwrap_or_default().day()) } } fn get_current_date() -> (i32, u32, u32) { - let local_now_date = Local::now().date(); + let local_now_date = Local::now().date_naive(); let current_year: i32 = local_now_date.year(); let current_month: u32 = local_now_date.month(); diff --git a/crates/nu-command/src/generators/seq_date.rs b/crates/nu-command/src/generators/seq_date.rs index 109ed247c..1c080ffd7 100644 --- a/crates/nu-command/src/generators/seq_date.rs +++ b/crates/nu-command/src/generators/seq_date.rs @@ -195,10 +195,9 @@ pub fn run_seq_dates( day_count: Option, reverse: bool, ) -> Result { - let today = Local::today().naive_local(); - let mut step_size: i64 = increment - .as_i64() - .expect("unable to change increment to i64"); + let today = Local::now().date_naive(); + // if cannot convert , it will return error + let mut step_size: i64 = increment.as_i64()?; if step_size == 0 { return Err(ShellError::GenericError( diff --git a/crates/nu-command/tests/commands/touch.rs b/crates/nu-command/tests/commands/touch.rs index fc64f31fd..ea19ce8eb 100644 --- a/crates/nu-command/tests/commands/touch.rs +++ b/crates/nu-command/tests/commands/touch.rs @@ -1,4 +1,4 @@ -use chrono::{Date, DateTime, Local}; +use chrono::{DateTime, Local}; use nu_test_support::fs::Stub; use nu_test_support::nu; use nu_test_support::playground::Playground; @@ -45,9 +45,10 @@ fn change_modified_time_of_file_to_today() { let path = dirs.test().join("file.txt"); // Check only the date since the time may not match exactly - let date: Date = Local::now().date(); - let actual_date: Date = - DateTime::from(path.metadata().unwrap().modified().unwrap()).date(); + let date = Local::now().date_naive(); + let actual_date_time: DateTime = + DateTime::from(path.metadata().unwrap().modified().unwrap()); + let actual_date = actual_date_time.date_naive(); assert_eq!(date, actual_date); }) @@ -66,9 +67,10 @@ fn change_access_time_of_file_to_today() { let path = dirs.test().join("file.txt"); // Check only the date since the time may not match exactly - let date: Date = Local::now().date(); - let actual_date: Date = - DateTime::from(path.metadata().unwrap().accessed().unwrap()).date(); + let date = Local::now().date_naive(); + let actual_date_time: DateTime = + DateTime::from(path.metadata().unwrap().accessed().unwrap()); + let actual_date = actual_date_time.date_naive(); assert_eq!(date, actual_date); }) @@ -87,9 +89,11 @@ fn change_modified_and_access_time_of_file_to_today() { let metadata = dirs.test().join("file.txt").metadata().unwrap(); // Check only the date since the time may not match exactly - let date: Date = Local::now().date(); - let adate: Date = DateTime::from(metadata.accessed().unwrap()).date(); - let mdate: Date = DateTime::from(metadata.modified().unwrap()).date(); + let date = Local::now().date_naive(); + let adate_time: DateTime = DateTime::from(metadata.accessed().unwrap()); + let adate = adate_time.date_naive(); + let mdate_time: DateTime = DateTime::from(metadata.modified().unwrap()); + let mdate = mdate_time.date_naive(); assert_eq!(date, adate); assert_eq!(date, mdate); diff --git a/crates/nu-engine/Cargo.toml b/crates/nu-engine/Cargo.toml index 52974771a..417ed3448 100644 --- a/crates/nu-engine/Cargo.toml +++ b/crates/nu-engine/Cargo.toml @@ -13,7 +13,7 @@ nu-path = { path = "../nu-path", version = "0.71.1" } nu-glob = { path = "../nu-glob", version = "0.71.1" } nu-utils = { path = "../nu-utils", version = "0.71.1" } -chrono = { version="0.4.21", features = ["std"], default-features = false } +chrono = { version="0.4.23", features = ["std"], default-features = false } sysinfo ="0.26.2" [features] diff --git a/crates/nu-parser/Cargo.toml b/crates/nu-parser/Cargo.toml index 3c8d047c3..255023125 100644 --- a/crates/nu-parser/Cargo.toml +++ b/crates/nu-parser/Cargo.toml @@ -9,7 +9,7 @@ version = "0.71.1" [dependencies] bytesize = "1.1.0" -chrono = { default-features = false, features = ['std'], version = "0.4.21" } +chrono = { default-features = false, features = ['std'], version = "0.4.23" } itertools = "0.10" miette = {version = "5.1.0", features = ["fancy-no-backtrace"]} thiserror = "1.0.31" diff --git a/crates/nu-protocol/Cargo.toml b/crates/nu-protocol/Cargo.toml index 3c3dc1ba9..8365c30a6 100644 --- a/crates/nu-protocol/Cargo.toml +++ b/crates/nu-protocol/Cargo.toml @@ -14,7 +14,7 @@ nu-utils = { path = "../nu-utils", version = "0.71.1" } nu-json = { path = "../nu-json", version = "0.71.1" } byte-unit = "4.0.9" -chrono = { version="0.4.21", features= ["serde", "std"], default-features = false } +chrono = { version="0.4.23", features= ["serde", "std"], default-features = false } chrono-humanize = "0.2.1" fancy-regex = "0.10.0" indexmap = { version="1.7" } diff --git a/crates/nu-system/Cargo.toml b/crates/nu-system/Cargo.toml index 23e5d80c0..98c21b0a0 100644 --- a/crates/nu-system/Cargo.toml +++ b/crates/nu-system/Cargo.toml @@ -27,6 +27,6 @@ mach2 = "0.4" [target.'cfg(target_os = "windows")'.dependencies] winapi = { version = "0.3.9", features = ["tlhelp32", "fileapi", "handleapi", "ifdef", "ioapiset", "minwindef", "pdh", "psapi", "synchapi", "sysinfoapi", "winbase", "winerror", "winioctl", "winnt", "oleauto", "wbemcli", "rpcdce", "combaseapi", "objidl", "powerbase", "netioapi", "lmcons", "lmaccess", "lmapibuf", "memoryapi", "shellapi", "std", "securitybaseapi"] } -chrono = "0.4.21" +chrono = "0.4.23" ntapi = "0.4" once_cell = "1.0" diff --git a/crates/nu-system/src/windows.rs b/crates/nu-system/src/windows.rs index 763a046d1..c7ba79f0b 100644 --- a/crates/nu-system/src/windows.rs +++ b/crates/nu-system/src/windows.rs @@ -136,11 +136,22 @@ pub fn collect_proc(interval: Duration, _with_thread: bool) -> Vec let start_time = if let Some((start, _, _, _)) = times { let time = chrono::Duration::seconds(start as i64 / 10_000_000); - let base = NaiveDate::from_ymd(1600, 1, 1).and_hms(0, 0, 0); - let time = base + time; - Local.from_utc_datetime(&time) + let base = + NaiveDate::from_ymd_opt(1600, 1, 1).and_then(|nd| nd.and_hms_opt(0, 0, 0)); + if let Some(base) = base { + let time = base + time; + Local.from_utc_datetime(&time) + } else { + continue; + } } else { - Local.from_utc_datetime(&NaiveDate::from_ymd(1600, 1, 1).and_hms(0, 0, 0)) + let time = + NaiveDate::from_ymd_opt(1600, 1, 1).and_then(|nt| nt.and_hms_opt(0, 0, 0)); + if let Some(time) = time { + Local.from_utc_datetime(&time) + } else { + continue; + } }; let cpu_info = if let Some((_, _, curr_sys, curr_user)) = times { diff --git a/tests/fixtures/formats/cargo_sample.toml b/tests/fixtures/formats/cargo_sample.toml index 53311c7c3..87bd32b77 100644 --- a/tests/fixtures/formats/cargo_sample.toml +++ b/tests/fixtures/formats/cargo_sample.toml @@ -11,7 +11,7 @@ edition = "2018" [dependencies] rustyline = "4.1.0" sysinfo = "0.8.4" -chrono = { version = "0.4.21", features = ["serde"] } +chrono = { version = "0.4.23", features = ["serde"] } chrono-tz = "0.6.3" derive-new = "0.5.6" prettytable-rs = "0.8.0"