nu_command/date/
humanize.rs

1use crate::date::utils::parse_date_from_string;
2use chrono::{DateTime, FixedOffset, Local};
3use nu_engine::command_prelude::*;
4
5#[derive(Clone)]
6pub struct DateHumanize;
7
8impl Command for DateHumanize {
9    fn name(&self) -> &str {
10        "date humanize"
11    }
12
13    fn signature(&self) -> Signature {
14        Signature::build("date humanize")
15            .input_output_types(vec![
16                (Type::Date, Type::String),
17                (Type::String, Type::String),
18            ])
19            .allow_variants_without_examples(true)
20            .category(Category::Date)
21    }
22
23    fn description(&self) -> &str {
24        "Print a 'humanized' format for the date, relative to now."
25    }
26
27    fn search_terms(&self) -> Vec<&str> {
28        vec![
29            "relative",
30            "now",
31            "today",
32            "tomorrow",
33            "yesterday",
34            "weekday",
35            "weekday_name",
36            "timezone",
37        ]
38    }
39
40    fn run(
41        &self,
42        engine_state: &EngineState,
43        _stack: &mut Stack,
44        call: &Call,
45        input: PipelineData,
46    ) -> Result<PipelineData, ShellError> {
47        let head = call.head;
48        // This doesn't match explicit nulls
49        if let PipelineData::Empty = input {
50            return Err(ShellError::PipelineEmpty { dst_span: head });
51        }
52        input.map(move |value| helper(value, head), engine_state.signals())
53    }
54
55    fn examples(&self) -> Vec<Example<'_>> {
56        vec![Example {
57            description: "Print a 'humanized' format for the date, relative to now.",
58            example: r#""2021-10-22 20:00:12 +01:00" | date humanize"#,
59            result: None,
60        }]
61    }
62}
63
64fn helper(value: Value, head: Span) -> Value {
65    let span = value.span();
66    match value {
67        Value::Nothing { .. } => {
68            let dt = Local::now();
69            Value::string(humanize_date(dt.with_timezone(dt.offset())), head)
70        }
71        Value::String { val, .. } => {
72            let dt = parse_date_from_string(&val, span);
73            match dt {
74                Ok(x) => Value::string(humanize_date(x), head),
75                Err(e) => e,
76            }
77        }
78        Value::Date { val, .. } => Value::string(humanize_date(val), head),
79        _ => Value::error(
80            ShellError::OnlySupportsThisInputType {
81                exp_input_type: "date, string (that represents datetime), or nothing".into(),
82                wrong_type: value.get_type().to_string(),
83                dst_span: head,
84                src_span: span,
85            },
86            head,
87        ),
88    }
89}
90
91fn humanize_date(dt: DateTime<FixedOffset>) -> String {
92    nu_protocol::human_time_from_now(&dt).to_string()
93}
94
95#[cfg(test)]
96mod test {
97    use super::*;
98
99    #[test]
100    fn test_examples() {
101        use crate::test_examples;
102
103        test_examples(DateHumanize {})
104    }
105}