Files
nushell/crates/nu-command/src/date/utils.rs
WindSoilder 14bf25da14 rename from date format to format date (#9902)
# Description
Closes: #9891
I also think it's good to keep command name consistency.

And moving `date format` to deprecated.

# User-Facing Changes
Running `date format` will lead to deprecate message:
```nushell
❯ "2021-10-22 20:00:12 +01:00" | date format
Error: nu:🐚:deprecated_command

  × Deprecated command date format
   ╭─[entry #28:1:1]
 1 │ "2021-10-22 20:00:12 +01:00" | date format
   ·                                ─────┬─────
   ·                                     ╰── 'date format' is deprecated. Please use 'format date' instead.
   ╰────
```
2023-08-04 06:06:00 +12:00

304 lines
10 KiB
Rust

use chrono::{DateTime, FixedOffset, Local, LocalResult, TimeZone};
use nu_protocol::{ShellError, Span, Value};
pub(crate) fn parse_date_from_string(
input: &str,
span: Span,
) -> Result<DateTime<FixedOffset>, Value> {
match dtparse::parse(input) {
Ok((native_dt, fixed_offset)) => {
let offset = match fixed_offset {
Some(fo) => fo,
None => *(Local::now().offset()),
};
match offset.from_local_datetime(&native_dt) {
LocalResult::Single(d) => Ok(d),
LocalResult::Ambiguous(d, _) => Ok(d),
LocalResult::None => Err(Value::Error {
error: Box::new(ShellError::DatetimeParseError(input.to_string(), span)),
}),
}
}
Err(_) => Err(Value::Error {
error: Box::new(ShellError::DatetimeParseError(input.to_string(), span)),
}),
}
}
/// Generates a table containing available datetime format specifiers
///
/// # Arguments
/// * `head` - use the call's head
/// * `show_parse_only_formats` - whether parse-only format specifiers (that can't be outputted) should be shown. Should only be used for `into datetime`, not `format date`
pub(crate) fn generate_strftime_list(head: Span, show_parse_only_formats: bool) -> Value {
let column_names = vec![
"Specification".into(),
"Example".into(),
"Description".into(),
];
let now = Local::now();
struct FormatSpecification<'a> {
spec: &'a str,
description: &'a str,
}
let specifications = vec![
FormatSpecification {
spec: "%Y",
description: "The full proleptic Gregorian year, zero-padded to 4 digits.",
},
FormatSpecification {
spec: "%C",
description: "The proleptic Gregorian year divided by 100, zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%y",
description: "The proleptic Gregorian year modulo 100, zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%m",
description: "Month number (01--12), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%b",
description: "Abbreviated month name. Always 3 letters.",
},
FormatSpecification {
spec: "%B",
description: "Full month name. Also accepts corresponding abbreviation in parsing.",
},
FormatSpecification {
spec: "%h",
description: "Same as %b.",
},
FormatSpecification {
spec: "%d",
description: "Day number (01--31), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%e",
description: "Same as %d but space-padded. Same as %_d.",
},
FormatSpecification {
spec: "%a",
description: "Abbreviated weekday name. Always 3 letters.",
},
FormatSpecification {
spec: "%A",
description: "Full weekday name. Also accepts corresponding abbreviation in parsing.",
},
FormatSpecification {
spec: "%w",
description: "Sunday = 0, Monday = 1, ..., Saturday = 6.",
},
FormatSpecification {
spec: "%u",
description: "Monday = 1, Tuesday = 2, ..., Sunday = 7. (ISO 8601)",
},
FormatSpecification {
spec: "%U",
description: "Week number starting with Sunday (00--53), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%W",
description:
"Same as %U, but week 1 starts with the first Monday in that year instead.",
},
FormatSpecification {
spec: "%G",
description: "Same as %Y but uses the year number in ISO 8601 week date.",
},
FormatSpecification {
spec: "%g",
description: "Same as %y but uses the year number in ISO 8601 week date.",
},
FormatSpecification {
spec: "%V",
description: "Same as %U but uses the week number in ISO 8601 week date (01--53).",
},
FormatSpecification {
spec: "%j",
description: "Day of the year (001--366), zero-padded to 3 digits.",
},
FormatSpecification {
spec: "%D",
description: "Month-day-year format. Same as %m/%d/%y.",
},
FormatSpecification {
spec: "%x",
description: "Locale's date representation (e.g., 12/31/99).",
},
FormatSpecification {
spec: "%F",
description: "Year-month-day format (ISO 8601). Same as %Y-%m-%d.",
},
FormatSpecification {
spec: "%v",
description: "Day-month-year format. Same as %e-%b-%Y.",
},
FormatSpecification {
spec: "%H",
description: "Hour number (00--23), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%k",
description: "Same as %H but space-padded. Same as %_H.",
},
FormatSpecification {
spec: "%I",
description: "Hour number in 12-hour clocks (01--12), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%l",
description: "Same as %I but space-padded. Same as %_I.",
},
FormatSpecification {
spec: "%P",
description: "am or pm in 12-hour clocks.",
},
FormatSpecification {
spec: "%p",
description: "AM or PM in 12-hour clocks.",
},
FormatSpecification {
spec: "%M",
description: "Minute number (00--59), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%S",
description: "Second number (00--60), zero-padded to 2 digits.",
},
FormatSpecification {
spec: "%f",
description: "The fractional seconds (in nanoseconds) since last whole second.",
},
FormatSpecification {
spec: "%.f",
description: "Similar to .%f but left-aligned. These all consume the leading dot.",
},
FormatSpecification {
spec: "%.3f",
description: "Similar to .%f but left-aligned but fixed to a length of 3.",
},
FormatSpecification {
spec: "%.6f",
description: "Similar to .%f but left-aligned but fixed to a length of 6.",
},
FormatSpecification {
spec: "%.9f",
description: "Similar to .%f but left-aligned but fixed to a length of 9.",
},
FormatSpecification {
spec: "%3f",
description: "Similar to %.3f but without the leading dot.",
},
FormatSpecification {
spec: "%6f",
description: "Similar to %.6f but without the leading dot.",
},
FormatSpecification {
spec: "%9f",
description: "Similar to %.9f but without the leading dot.",
},
FormatSpecification {
spec: "%R",
description: "Hour-minute format. Same as %H:%M.",
},
FormatSpecification {
spec: "%T",
description: "Hour-minute-second format. Same as %H:%M:%S.",
},
FormatSpecification {
spec: "%X",
description: "Locale's time representation (e.g., 23:13:48).",
},
FormatSpecification {
spec: "%r",
description: "Hour-minute-second format in 12-hour clocks. Same as %I:%M:%S %p.",
},
FormatSpecification {
spec: "%Z",
description:
"Local time zone name. Skips all non-whitespace characters during parsing.",
},
FormatSpecification {
spec: "%z",
description: "Offset from the local time to UTC (with UTC being +0000).",
},
FormatSpecification {
spec: "%:z",
description: "Same as %z but with a colon.",
},
FormatSpecification {
spec: "%c",
description: "Locale's date and time (e.g., Thu Mar 3 23:05:25 2005).",
},
FormatSpecification {
spec: "%+",
description: "ISO 8601 / RFC 3339 date & time format.",
},
FormatSpecification {
spec: "%s",
description: "UNIX timestamp, the number of seconds since 1970-01-01",
},
FormatSpecification {
spec: "%t",
description: "Literal tab (\\t).",
},
FormatSpecification {
spec: "%n",
description: "Literal newline (\\n).",
},
FormatSpecification {
spec: "%%",
description: "Literal percent sign.",
},
];
let mut records = specifications
.iter()
.map(|s| Value::Record {
cols: column_names.clone(),
vals: vec![
Value::string(s.spec, head),
Value::string(now.format(s.spec).to_string(), head),
Value::string(s.description, head),
],
span: head,
})
.collect::<Vec<Value>>();
if show_parse_only_formats {
// now.format("%#z") will panic since it is parse-only
// so here we emulate how it will look:
let example = now
.format("%:z") // e.g. +09:30
.to_string()
.get(0..3) // +09:30 -> +09
.unwrap_or("")
.to_string();
records.push(Value::Record {
cols: column_names,
vals: vec![
Value::string("%#z", head),
Value::String {
val: example,
span: head,
},
Value::string(
"Parsing only: Same as %z but allows minutes to be missing or present.",
head,
),
],
span: head,
});
}
Value::List {
vals: records,
span: head,
}
}