mirror of
https://github.com/nushell/nushell.git
synced 2025-08-18 14:11:23 +02:00
Add custom datetime format through strftime
strings (#9500)
- improves usability of datetime's in displayed text - # Description Creates a config point for specifying long / short date time formats. Defaults to humanized as we have today. Provides for adding strftime formats into config.nu such as: ```nu datetime_format: { normal: "%Y-%m-%d %H:%M:%S" table: "%Y-%m-%d" } ``` Example: ```bash > $env.config.datetime_format ┏━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┓ ┃ normal ┃ %a, %d %b %Y %H:%M:%S %z ┃ ┃ table ┃ %m/%d/%y %I:%M:%S%p ┃ ┗━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━┛ > let a = (date now) > echo $a Thu, 22 Jun 2023 10:21:23 -0700 > echo [$a] ┏━━━┳━━━━━━━━━━━━━━━━━━━━━┓ ┃ 0 ┃ 06/22/23 10:21:23AM ┃ ┗━━━┻━━━━━━━━━━━━━━━━━━━━━┛ ``` # User-Facing Changes Any place converting a datetime to a user displayed value should be impacted. # Tests + Formatting - `cargo fmt --all -- --check` Done - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect -A clippy::result_large_err` Done - `cargo test --workspace` Done - `cargo run -- crates/nu-std/tests/run.nu` Not done - doesn't seem to work ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr ``` - Done --------- Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com> Co-authored-by: Antoine Stevan <44101798+amtoine@users.noreply.github.com>
This commit is contained in:
@@ -12,7 +12,7 @@ use crate::engine::EngineState;
|
||||
use crate::ShellError;
|
||||
use crate::{did_you_mean, BlockId, Config, Span, Spanned, Type, VarId};
|
||||
use byte_unit::ByteUnit;
|
||||
use chrono::{DateTime, Duration, FixedOffset};
|
||||
use chrono::{DateTime, Duration, FixedOffset, Locale, TimeZone};
|
||||
use chrono_humanize::HumanTime;
|
||||
pub use custom_value::CustomValue;
|
||||
use fancy_regex::Regex;
|
||||
@@ -20,10 +20,12 @@ pub use from_value::FromValue;
|
||||
use indexmap::map::IndexMap;
|
||||
pub use lazy_record::LazyRecord;
|
||||
use nu_utils::get_system_locale;
|
||||
use nu_utils::locale::get_system_locale_string;
|
||||
use num_format::ToFormattedString;
|
||||
pub use range::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt::Write;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fmt::{Display, Formatter, Result as FmtResult},
|
||||
@@ -534,7 +536,12 @@ impl Value {
|
||||
Value::Float { val, .. } => val.to_string(),
|
||||
Value::Filesize { val, .. } => format_filesize_from_conf(*val, config),
|
||||
Value::Duration { val, .. } => format_duration(*val),
|
||||
Value::Date { val, .. } => format!("{} ({})", val.to_rfc2822(), HumanTime::from(*val)),
|
||||
Value::Date { val, .. } => match &config.datetime_normal_format {
|
||||
Some(format) => self.format_datetime(val, format),
|
||||
None => {
|
||||
format!("{} ({})", val.to_rfc2822(), HumanTime::from(*val))
|
||||
}
|
||||
},
|
||||
Value::Range { val, .. } => {
|
||||
format!(
|
||||
"{}..{}",
|
||||
@@ -586,7 +593,10 @@ impl Value {
|
||||
Value::Float { val, .. } => val.to_string(),
|
||||
Value::Filesize { val, .. } => format_filesize_from_conf(*val, config),
|
||||
Value::Duration { val, .. } => format_duration(*val),
|
||||
Value::Date { val, .. } => HumanTime::from(*val).to_string(),
|
||||
Value::Date { val, .. } => match &config.datetime_table_format {
|
||||
Some(format) => self.format_datetime(val, format),
|
||||
None => HumanTime::from(*val).to_string(),
|
||||
},
|
||||
Value::Range { val, .. } => {
|
||||
format!(
|
||||
"{}..{}",
|
||||
@@ -630,6 +640,26 @@ impl Value {
|
||||
}
|
||||
}
|
||||
|
||||
fn format_datetime<Tz: TimeZone>(&self, date_time: &DateTime<Tz>, formatter: &str) -> String
|
||||
where
|
||||
Tz::Offset: Display,
|
||||
{
|
||||
let mut formatter_buf = String::new();
|
||||
let locale: Locale = get_system_locale_string()
|
||||
.map(|l| l.replace('-', "_")) // `chrono::Locale` needs something like `xx_xx`, rather than `xx-xx`
|
||||
.unwrap_or_else(|| String::from("en_US"))
|
||||
.as_str()
|
||||
.try_into()
|
||||
.unwrap_or(Locale::en_US);
|
||||
let format = date_time.format_localized(formatter, locale);
|
||||
|
||||
match formatter_buf.write_fmt(format_args!("{format}")) {
|
||||
Ok(_) => (),
|
||||
Err(_) => formatter_buf = format!("Invalid format string {}", formatter),
|
||||
}
|
||||
formatter_buf
|
||||
}
|
||||
|
||||
/// Convert Value into a debug string
|
||||
pub fn debug_value(&self) -> String {
|
||||
format!("{self:#?}")
|
||||
@@ -798,8 +828,8 @@ impl Value {
|
||||
return Ok(Value::nothing(*origin_span)); // short-circuit
|
||||
} else {
|
||||
return Err(ShellError::AccessBeyondEndOfStream {
|
||||
span: *origin_span
|
||||
});
|
||||
span: *origin_span
|
||||
});
|
||||
}
|
||||
}
|
||||
Value::CustomValue { val, .. } => {
|
||||
|
Reference in New Issue
Block a user