update human-date-parser conversion to use local timezone (#14266)

# Description

This PR tries to fix https://github.com/nushell/nushell/issues/14195 by
setting the local time and timezone after conversion without changing
the time.

### Before
```nushell
❯ 'in 10 minutes' | into datetime
Tue, 5 Nov 2024 12:59:58 -0600 (in 9 minutes)
❯ 'yesterday' | into datetime
Sun, 3 Nov 2024 18:00:00 -0600 (2 days ago)
❯ 'tomorrow' | into datetime
Tue, 5 Nov 2024 18:00:00 -0600 (in 5 hours)
❯ 'today' | into datetime
Mon, 4 Nov 2024 18:00:00 -0600 (18 hours ago)
```

### After (these are correct)
```nushell
❯ 'in 10 minutes' | into datetime
Tue, 5 Nov 2024 12:58:44 -0600 (in 9 minutes)
❯ 'yesterday' | into datetime
Mon, 4 Nov 2024 12:49:04 -0600 (a day ago)
❯ 'tomorrow' | into datetime
Wed, 6 Nov 2024 12:49:20 -0600 (in a day)
❯ 'today' | into datetime
Tue, 5 Nov 2024 12:52:06 -0600 (now)
```

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

# Tests + Formatting
<!--
Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to
check that you're using the standard code style
- `cargo test --workspace` to check that all tests pass (on Windows make
sure to [enable developer
mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging))
- `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the
tests for the standard library

> **Note**
> from `nushell` you can also use the `toolkit` as follows
> ```bash
> use toolkit.nu # or use an `env_change` hook to activate it
automatically
> toolkit check pr
> ```
-->

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->
This commit is contained in:
Darren Schroeder 2024-11-06 07:14:00 -06:00 committed by GitHub
parent b968376be9
commit d52ec65f18
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -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, FixedOffset, Local, NaiveDateTime, NaiveTime, TimeZone, Utc}; use chrono::{DateTime, FixedOffset, Local, NaiveDateTime, TimeZone, Utc};
use human_date_parser::{from_human_time, ParseResult}; use human_date_parser::{from_human_time, ParseResult};
use nu_cmd_base::input_handler::{operate, CmdArgument}; use nu_cmd_base::input_handler::{operate, CmdArgument};
use nu_engine::command_prelude::*; use nu_engine::command_prelude::*;
@ -275,12 +275,13 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
if let Ok(date) = from_human_time(&input_val) { if let Ok(date) = from_human_time(&input_val) {
match date { match date {
ParseResult::Date(date) => { ParseResult::Date(date) => {
let time = NaiveTime::from_hms_opt(0, 0, 0).expect("valid time"); let time = Local::now().time();
let combined = date.and_time(time); let combined = date.and_time(time);
let dt_fixed = DateTime::from_naive_utc_and_offset( let local_offset = *Local::now().offset();
combined, let dt_fixed =
*Local::now().offset(), TimeZone::from_local_datetime(&local_offset, &combined)
); .single()
.unwrap_or_default();
return Value::date(dt_fixed, span); return Value::date(dt_fixed, span);
} }
ParseResult::DateTime(date) => { ParseResult::DateTime(date) => {
@ -289,10 +290,11 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
ParseResult::Time(time) => { ParseResult::Time(time) => {
let date = Local::now().date_naive(); let date = Local::now().date_naive();
let combined = date.and_time(time); let combined = date.and_time(time);
let dt_fixed = DateTime::from_naive_utc_and_offset( let local_offset = *Local::now().offset();
combined, let dt_fixed =
*Local::now().offset(), TimeZone::from_local_datetime(&local_offset, &combined)
); .single()
.unwrap_or_default();
return Value::date(dt_fixed, span); return Value::date(dt_fixed, span);
} }
} }
@ -386,13 +388,15 @@ fn action(input: &Value, args: &Arguments, head: Span) -> Value {
Ok(d) => Value::date ( d, head ), Ok(d) => Value::date ( d, head ),
Err(reason) => { Err(reason) => {
match NaiveDateTime::parse_from_str(val, &dt.0) { match NaiveDateTime::parse_from_str(val, &dt.0) {
Ok(d) => Value::date ( Ok(d) => {
DateTime::from_naive_utc_and_offset( let local_offset = *Local::now().offset();
d, let dt_fixed =
*Local::now().offset(), TimeZone::from_local_datetime(&local_offset, &d)
), .single()
head, .unwrap_or_default();
),
Value::date (dt_fixed,head)
}
Err(_) => { Err(_) => {
Value::error ( Value::error (
ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) }, ShellError::CantConvert { to_type: format!("could not parse as datetime using format '{}'", dt.0), from_type: reason.to_string(), span: head, help: Some("you can use `into datetime` without a format string to enable flexible parsing".to_string()) },