diff --git a/crates/nu-command/src/date/format.rs b/crates/nu-command/src/date/format.rs index 833eae133b..8a9e47c6a1 100644 --- a/crates/nu-command/src/date/format.rs +++ b/crates/nu-command/src/date/format.rs @@ -1,10 +1,13 @@ use chrono::Local; +use chrono::{DateTime, TimeZone}; + use nu_engine::CallExt; use nu_protocol::{ ast::Call, engine::{Command, EngineState, Stack}, - Category, Example, PipelineData, ShellError, Signature, Span, SyntaxShape, Value, + Category, Example, PipelineData, ShellError, Signature, Span, Spanned, SyntaxShape, Value, }; +use std::fmt::{Display, Write}; use super::utils::parse_date_from_string; @@ -50,11 +53,11 @@ impl Command for SubCommand { )); } - let format = call.opt::(engine_state, stack, 0)?; + let format = call.opt::>(engine_state, stack, 0)?; input.map( move |value| match &format { - Some(format) => format_helper(value, format.as_str(), head), + Some(format) => format_helper(value, format.item.as_str(), format.span, head), None => format_helper_rfc2822(value, head), }, engine_state.ctrlc.clone(), @@ -90,34 +93,41 @@ impl Command for SubCommand { } } -fn format_helper(value: Value, formatter: &str, span: Span) -> Value { - match value { - Value::Date { val, span: _ } => Value::String { - val: val.format(formatter).to_string(), +fn format_from(date_time: DateTime, formatter: &str, span: Span) -> Value +where + Tz::Offset: Display, +{ + let mut formatter_buf = String::new(); + let format = date_time.format(formatter); + + match formatter_buf.write_fmt(format_args!("{}", format)) { + Ok(_) => Value::String { + val: formatter_buf, span, }, - Value::String { - val, - span: val_span, - } => { - let dt = parse_date_from_string(&val, val_span); + Err(_) => Value::Error { + error: ShellError::UnsupportedInput("invalid format".to_string(), span), + }, + } +} + +fn format_helper(value: Value, formatter: &str, formatter_span: Span, head_span: Span) -> Value { + match value { + Value::Date { val, .. } => format_from(val, formatter, formatter_span), + Value::String { val, .. } => { + let dt = parse_date_from_string(&val, formatter_span); + match dt { - Ok(x) => Value::String { - val: x.format(formatter).to_string(), - span, - }, + Ok(x) => format_from(x, formatter, formatter_span), Err(e) => e, } } - Value::Nothing { span: _ } => { + Value::Nothing { .. } => { let dt = Local::now(); - Value::String { - val: dt.with_timezone(dt.offset()).format(formatter).to_string(), - span, - } + format_from(dt, formatter, formatter_span) } _ => Value::Error { - error: ShellError::DatetimeParseError(span), + error: ShellError::DatetimeParseError(head_span), }, } } diff --git a/crates/nu-command/tests/commands/date/format.rs b/crates/nu-command/tests/commands/date/format.rs new file mode 100644 index 0000000000..be3f254240 --- /dev/null +++ b/crates/nu-command/tests/commands/date/format.rs @@ -0,0 +1,14 @@ +use nu_test_support::{nu, pipeline}; + +#[test] +fn formatter_not_valid() { + let actual = nu!( + cwd: ".", pipeline( + r#" + date format '%N' + "# + ) + ); + + assert!(actual.err.contains("invalid format")); +} diff --git a/crates/nu-command/tests/commands/date/mod.rs b/crates/nu-command/tests/commands/date/mod.rs new file mode 100644 index 0000000000..863126853c --- /dev/null +++ b/crates/nu-command/tests/commands/date/mod.rs @@ -0,0 +1 @@ +mod format; diff --git a/crates/nu-command/tests/commands/mod.rs b/crates/nu-command/tests/commands/mod.rs index 9d625154f6..f006f29050 100644 --- a/crates/nu-command/tests/commands/mod.rs +++ b/crates/nu-command/tests/commands/mod.rs @@ -6,6 +6,7 @@ mod cal; mod cd; mod compact; mod cp; +mod date; mod def; mod default; mod drop;