liquid_lib/extra/
date.rs

1use liquid_core::Expression;
2use liquid_core::Result;
3use liquid_core::Runtime;
4use liquid_core::{
5    Display_filter, Filter, FilterParameters, FilterReflection, FromFilterParameters, ParseFilter,
6};
7use liquid_core::{Value, ValueView};
8
9use crate::invalid_input;
10
11// liquid-rust proprietary
12
13#[derive(Debug, FilterParameters)]
14struct DateInTzArgs {
15    #[parameter(description = "The format to return the date in.", arg_type = "str")]
16    format: Expression,
17    #[parameter(
18        description = "The timezone to convert the date to.",
19        arg_type = "integer"
20    )]
21    timezone: Expression,
22}
23
24#[derive(Clone, ParseFilter, FilterReflection)]
25#[filter(
26    name = "date_in_tz",
27    description = "Converts a timestamp into another date format and timezone.",
28    parameters(DateInTzArgs),
29    parsed(DateInTzFilter)
30)]
31pub struct DateInTz;
32
33#[derive(Debug, FromFilterParameters, Display_filter)]
34#[name = "date_in_tz"]
35struct DateInTzFilter {
36    #[parameters]
37    args: DateInTzArgs,
38}
39
40impl Filter for DateInTzFilter {
41    fn evaluate(&self, input: &dyn ValueView, runtime: &dyn Runtime) -> Result<Value> {
42        let args = self.args.evaluate(runtime)?;
43
44        let date = input
45            .as_scalar()
46            .and_then(|s| s.to_date_time())
47            .ok_or_else(|| invalid_input("Invalid date format"))?;
48
49        let offset = time::UtcOffset::from_whole_seconds(args.timezone as i32 * 3600)
50            .map_err(|_err| invalid_input("Timezone was too large"))?;
51
52        let date_str = date
53            .with_offset(offset)
54            .format(args.format.as_str())
55            .map_err(|_err| invalid_input("Invalid format string"))?;
56        Ok(Value::scalar(date_str))
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn unit_date_in_tz_same_day() {
66        let unit_result = liquid_core::call_filter!(
67            DateInTz,
68            "13 Jun 2016 12:00:00 +0000",
69            "%Y-%m-%d %H:%M:%S %z",
70            3i64
71        )
72        .unwrap();
73        let desired_result = liquid_core::value!("2016-06-13 15:00:00 +0300");
74        assert_eq!(unit_result, desired_result);
75    }
76
77    #[test]
78    fn unit_date_in_tz_previous_day() {
79        let unit_result = liquid_core::call_filter!(
80            DateInTz,
81            "13 Jun 2016 12:00:00 +0000",
82            "%Y-%m-%d %H:%M:%S %z",
83            -13i64
84        )
85        .unwrap();
86        let desired_result = liquid_core::value!("2016-06-12 23:00:00 -1300");
87        assert_eq!(unit_result, desired_result);
88    }
89
90    #[test]
91    fn unit_date_in_tz_next_day() {
92        let unit_result = liquid_core::call_filter!(
93            DateInTz,
94            "13 Jun 2016 12:00:00 +0000",
95            "%Y-%m-%d %H:%M:%S %z",
96            13i64
97        )
98        .unwrap();
99        let desired_result = liquid_core::value!("2016-06-14 01:00:00 +1300");
100        assert_eq!(unit_result, desired_result);
101    }
102
103    #[test]
104    fn unit_date_in_tz_input_not_a_string() {
105        liquid_core::call_filter!(DateInTz, 0f64, "%Y-%m-%d %H:%M:%S %z", 0i64).unwrap_err();
106    }
107
108    #[test]
109    fn unit_date_in_tz_input_not_a_date_string() {
110        liquid_core::call_filter!(DateInTz, "blah blah blah", "%Y-%m-%d %H:%M:%S %z", 0i64)
111            .unwrap_err();
112    }
113
114    #[test]
115    fn unit_date_in_tz_offset_not_a_num() {
116        liquid_core::call_filter!(
117            DateInTz,
118            "13 Jun 2016 12:00:00 +0000",
119            "%Y-%m-%d %H:%M:%S %z",
120            "Hello"
121        )
122        .unwrap_err();
123    }
124
125    #[test]
126    fn unit_date_in_tz_zero_arguments() {
127        liquid_core::call_filter!(DateInTz, "13 Jun 2016 12:00:00 +0000").unwrap_err();
128    }
129
130    #[test]
131    fn unit_date_in_tz_one_argument() {
132        liquid_core::call_filter!(
133            DateInTz,
134            "13 Jun 2016 12:00:00 +0000",
135            "%Y-%m-%d %H:%M:%S %z"
136        )
137        .unwrap_err();
138    }
139
140    #[test]
141    fn unit_date_in_tz_three_arguments() {
142        liquid_core::call_filter!(
143            DateInTz,
144            "13 Jun 2016 12:00:00 +0000",
145            "%Y-%m-%d %H:%M:%S %z",
146            0f64,
147            1f64
148        )
149        .unwrap_err();
150    }
151}