From 9beecff736a92b255be9868eba8465240d3cb86e Mon Sep 17 00:00:00 2001 From: JT <547158+jntrnr@users.noreply.github.com> Date: Fri, 1 Apr 2022 21:09:30 +1300 Subject: [PATCH] Add 'date to-record' (#5058) --- crates/nu-command/src/date/mod.rs | 2 + crates/nu-command/src/date/to_record.rs | 164 +++++++++++++++++++++++ crates/nu-command/src/date/to_table.rs | 8 +- crates/nu-command/src/default_context.rs | 1 + 4 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 crates/nu-command/src/date/to_record.rs diff --git a/crates/nu-command/src/date/mod.rs b/crates/nu-command/src/date/mod.rs index 1b7b8880cc..b964c59a60 100644 --- a/crates/nu-command/src/date/mod.rs +++ b/crates/nu-command/src/date/mod.rs @@ -4,6 +4,7 @@ mod humanize; mod list_timezone; mod now; mod parser; +mod to_record; mod to_table; mod to_timezone; mod utils; @@ -14,6 +15,7 @@ pub use format::SubCommand as DateFormat; pub use humanize::SubCommand as DateHumanize; pub use list_timezone::SubCommand as DateListTimezones; pub use now::SubCommand as DateNow; +pub use to_record::SubCommand as DateToRecord; pub use to_table::SubCommand as DateToTable; pub use to_timezone::SubCommand as DateToTimezone; pub(crate) use utils::parse_date_from_string; diff --git a/crates/nu-command/src/date/to_record.rs b/crates/nu-command/src/date/to_record.rs new file mode 100644 index 0000000000..3d1a637d89 --- /dev/null +++ b/crates/nu-command/src/date/to_record.rs @@ -0,0 +1,164 @@ +use crate::date::utils::parse_date_from_string; +use chrono::{DateTime, Datelike, FixedOffset, Local, Timelike}; +use nu_protocol::ast::Call; +use nu_protocol::engine::{Command, EngineState, Stack}; +use nu_protocol::{ + Category, Example, PipelineData, ShellError::DatetimeParseError, Signature, Span, Value, +}; + +#[derive(Clone)] +pub struct SubCommand; + +impl Command for SubCommand { + fn name(&self) -> &str { + "date to-record" + } + + fn signature(&self) -> Signature { + Signature::build("date to-record").category(Category::Date) + } + + fn usage(&self) -> &str { + "Convert the date into a structured table." + } + + fn run( + &self, + engine_state: &EngineState, + _stack: &mut Stack, + call: &Call, + input: PipelineData, + ) -> Result { + let head = call.head; + input.map(move |value| helper(value, head), engine_state.ctrlc.clone()) + } + + fn examples(&self) -> Vec { + vec![ + Example { + description: "Convert the current date into a structured table.", + example: "date to-table", + result: None, + }, + Example { + description: "Convert the current date into a structured table.", + example: "date now | date to-record", + result: None, + }, + Example { + description: "Convert a given date into a structured table.", + example: " '2020-04-12 22:10:57 +0200' | date to-record", + result: { + let span = Span::test_data(); + let cols = vec![ + "year".into(), + "month".into(), + "day".into(), + "hour".into(), + "minute".into(), + "second".into(), + "timezone".into(), + ]; + let vals = vec![ + Value::Int { val: 2020, span }, + Value::Int { val: 4, span }, + Value::Int { val: 12, span }, + Value::Int { val: 22, span }, + Value::Int { val: 10, span }, + Value::Int { val: 57, span }, + Value::String { + val: "+02:00".to_string(), + span, + }, + ]; + Some(Value::Record { cols, vals, span }) + }, + }, + ] + } +} + +fn parse_date_into_table(date: Result, Value>, head: Span) -> Value { + let cols = vec![ + "year".into(), + "month".into(), + "day".into(), + "hour".into(), + "minute".into(), + "second".into(), + "timezone".into(), + ]; + match date { + Ok(x) => { + let vals = vec![ + Value::Int { + val: x.year() as i64, + span: head, + }, + Value::Int { + val: x.month() as i64, + span: head, + }, + Value::Int { + val: x.day() as i64, + span: head, + }, + Value::Int { + val: x.hour() as i64, + span: head, + }, + Value::Int { + val: x.minute() as i64, + span: head, + }, + Value::Int { + val: x.second() as i64, + span: head, + }, + Value::String { + val: x.offset().to_string(), + span: head, + }, + ]; + Value::Record { + cols, + vals, + span: head, + } + } + Err(e) => e, + } +} + +fn helper(val: Value, head: Span) -> Value { + match val { + Value::String { + val, + span: val_span, + } => { + let date = parse_date_from_string(&val, val_span); + parse_date_into_table(date, head) + } + Value::Nothing { span: _ } => { + let now = Local::now(); + let n = now.with_timezone(now.offset()); + parse_date_into_table(Ok(n), head) + } + Value::Date { val, span: _ } => parse_date_into_table(Ok(val), head), + _ => Value::Error { + error: DatetimeParseError(head), + }, + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_examples() { + use crate::test_examples; + + test_examples(SubCommand {}) + } +} diff --git a/crates/nu-command/src/date/to_table.rs b/crates/nu-command/src/date/to_table.rs index 9f5215f32b..54a0236835 100644 --- a/crates/nu-command/src/date/to_table.rs +++ b/crates/nu-command/src/date/to_table.rs @@ -19,7 +19,7 @@ impl Command for SubCommand { } fn usage(&self) -> &str { - "Print the date in a structured table." + "Convert the date into a structured table." } fn run( @@ -36,17 +36,17 @@ impl Command for SubCommand { fn examples(&self) -> Vec { vec![ Example { - description: "Print the date in a structured table.", + description: "Convert the date into a structured table.", example: "date to-table", result: None, }, Example { - description: "Print the date in a structured table.", + description: "Convert the date into a structured table.", example: "date now | date to-table", result: None, }, Example { - description: "Print the date in a structured table.", + description: "Convert a given date into a structured table.", example: " '2020-04-12 22:10:57 +0200' | date to-table", result: { let span = Span::test_data(); diff --git a/crates/nu-command/src/default_context.rs b/crates/nu-command/src/default_context.rs index 9566305760..294cac4ee6 100644 --- a/crates/nu-command/src/default_context.rs +++ b/crates/nu-command/src/default_context.rs @@ -218,6 +218,7 @@ pub fn create_default_context(cwd: impl AsRef) -> EngineState { DateHumanize, DateListTimezones, DateNow, + DateToRecord, DateToTable, DateToTimezone, };