Repository: nushell/nushell
File: crates/nu-command/src/conversions/into/datetime.rs (Rust)

Code before:
                example: "'In 5 minutes and 30 seconds' | into datetime",
                result: None,
            },
        ]
    }
}

#[derive(Clone)]
struct DatetimeFormat(String);

fn action(input: &Value, args: &Arguments, head: Span) -> Value {
    let timezone = &args.zone_options;
    let dateformat = &args.format_options;

    // Let's try dtparse first
    if matches!(input, Value::String { .. }) && dateformat.is_none() {
        let span = input.span();
        if let Ok(input_val) = input.coerce_str() {
            match parse_date_from_string(&input_val, span) {
                Ok(date) => return Value::date(date, span),
                Err(_) => {
                    if let Ok(date) = from_human_time(&input_val) {
                        match date {
                            ParseResult::Date(date) => {
                                let time = Local::now().time();
                                let combined = date.and_time(time);
                                let local_offset = *Local::now().offset();
                                let dt_fixed =
                                    TimeZone::from_local_datetime(&local_offset, &combined)
                                        .single()
                                        .unwrap_or_default();
                                return Value::date(dt_fixed, span);
                            }
                            ParseResult::DateTime(date) => {
                                return Value::date(date.fixed_offset(), span)
                            }
                            ParseResult::Time(time) => {
                                let date = Local::now().date_naive();
                                let combined = date.and_time(time);
                                let local_offset = *Local::now().offset();
                                let dt_fixed =
                                    TimeZone::from_local_datetime(&local_offset, &combined)
                                        .single()
                                        .unwrap_or_default();
                                return Value::date(dt_fixed, span);
                            }
                        }
                    }
                }
            };
        }

Review comment (refactor):
It might be slightly cleaner to move this to a new arm in the main `match input`, right below `dtparse` check.

Code after:
            Example {
                description: "Parsing human readable datetimes",
                example: "'Last Friday at 19:45' | into datetime",
                result: None,
            },
            Example {
                description: "Parsing human readable datetimes",
                example: "'In 5 minutes and 30 seconds' | into datetime",
                result: None,
            },
        ]
    }
}

#[derive(Clone)]
struct DatetimeFormat(String);

fn action(input: &Value, args: &Arguments, head: Span) -> Value {
    let timezone = &args.zone_options;
    let dateformat = &args.format_options;

    // noop if the input is already a datetime
    if matches!(input, Value::Date { .. }) {
        return input.clone();
    }

    // Let's try dtparse first
    if matches!(input, Value::String { .. }) && dateformat.is_none() {
        let span = input.span();
        if let Ok(input_val) = input.coerce_str() {
            match parse_date_from_string(&input_val, span) {
                Ok(date) => return Value::date(date, span),
                Err(_) => {
                    if let Ok(date) = from_human_time(&input_val) {
                        match date {
                            ParseResult::Date(date) => {
                                let time = Local::now().time();
                                let combined = date.and_time(time);
                                let local_offset = *Local::now().offset();
                                let dt_fixed =
                                    TimeZone::from_local_datetime(&local_offset, &combined)
                                        .single()
                                        .unwrap_or_default();
                                return Value::date(dt_fixed, span);
                            }
                            ParseResult::DateTime(date) => {
                                return Value::date(date.fixed_offset(), span)
                            }
                            ParseResult::Time(time) => {
                                let date = Local::now().date_naive();
                                let combined = date.and_time(time);