use liquid_core::Expression;
use liquid_core::Result;
use liquid_core::Runtime;
use liquid_core::{
Display_filter, Filter, FilterParameters, FilterReflection, FromFilterParameters, ParseFilter,
};
use liquid_core::{Value, ValueView};
use crate::invalid_input;
#[derive(Debug, FilterParameters)]
struct DateInTzArgs {
#[parameter(description = "The format to return the date in.", arg_type = "str")]
format: Expression,
#[parameter(
description = "The timezone to convert the date to.",
arg_type = "integer"
)]
timezone: Expression,
}
#[derive(Clone, ParseFilter, FilterReflection)]
#[filter(
name = "date_in_tz",
description = "Converts a timestamp into another date format and timezone.",
parameters(DateInTzArgs),
parsed(DateInTzFilter)
)]
pub struct DateInTz;
#[derive(Debug, FromFilterParameters, Display_filter)]
#[name = "date_in_tz"]
struct DateInTzFilter {
#[parameters]
args: DateInTzArgs,
}
impl Filter for DateInTzFilter {
fn evaluate(&self, input: &dyn ValueView, runtime: &dyn Runtime) -> Result<Value> {
let args = self.args.evaluate(runtime)?;
let date = input
.as_scalar()
.and_then(|s| s.to_date_time())
.ok_or_else(|| invalid_input("Invalid date format"))?;
let offset = time::UtcOffset::from_whole_seconds(args.timezone as i32 * 3600)
.map_err(|_err| invalid_input("Timezone was too large"))?;
let date_str = date
.with_offset(offset)
.format(args.format.as_str())
.map_err(|_err| invalid_input("Invalid format string"))?;
Ok(Value::scalar(date_str))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unit_date_in_tz_same_day() {
let unit_result = liquid_core::call_filter!(
DateInTz,
"13 Jun 2016 12:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
3i64
)
.unwrap();
let desired_result = liquid_core::value!("2016-06-13 15:00:00 +0300");
assert_eq!(unit_result, desired_result);
}
#[test]
fn unit_date_in_tz_previous_day() {
let unit_result = liquid_core::call_filter!(
DateInTz,
"13 Jun 2016 12:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
-13i64
)
.unwrap();
let desired_result = liquid_core::value!("2016-06-12 23:00:00 -1300");
assert_eq!(unit_result, desired_result);
}
#[test]
fn unit_date_in_tz_next_day() {
let unit_result = liquid_core::call_filter!(
DateInTz,
"13 Jun 2016 12:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
13i64
)
.unwrap();
let desired_result = liquid_core::value!("2016-06-14 01:00:00 +1300");
assert_eq!(unit_result, desired_result);
}
#[test]
fn unit_date_in_tz_input_not_a_string() {
liquid_core::call_filter!(DateInTz, 0f64, "%Y-%m-%d %H:%M:%S %z", 0i64).unwrap_err();
}
#[test]
fn unit_date_in_tz_input_not_a_date_string() {
liquid_core::call_filter!(DateInTz, "blah blah blah", "%Y-%m-%d %H:%M:%S %z", 0i64)
.unwrap_err();
}
#[test]
fn unit_date_in_tz_offset_not_a_num() {
liquid_core::call_filter!(
DateInTz,
"13 Jun 2016 12:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
"Hello"
)
.unwrap_err();
}
#[test]
fn unit_date_in_tz_zero_arguments() {
liquid_core::call_filter!(DateInTz, "13 Jun 2016 12:00:00 +0000").unwrap_err();
}
#[test]
fn unit_date_in_tz_one_argument() {
liquid_core::call_filter!(
DateInTz,
"13 Jun 2016 12:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z"
)
.unwrap_err();
}
#[test]
fn unit_date_in_tz_three_arguments() {
liquid_core::call_filter!(
DateInTz,
"13 Jun 2016 12:00:00 +0000",
"%Y-%m-%d %H:%M:%S %z",
0f64,
1f64
)
.unwrap_err();
}
}