stubr 0.6.2

Wiremock implemented in Rust
Documentation
use std::time::{SystemTime, UNIX_EPOCH};

use super::HelperExt;
use chrono::{prelude::*, Duration};
use chrono_tz::Tz;
use handlebars::{Context, Handlebars, Helper, HelperDef, RenderContext, RenderError, ScopedJson};
use humantime::parse_duration;
use serde_json::Value;

pub struct NowHelper;

impl NowHelper {
    pub const NAME: &'static str = "now";
    const FORMAT: &'static str = "format";
    const OFFSET: &'static str = "offset";
    const TIMEZONE: &'static str = "timezone";
    const EPOCH: &'static str = "epoch";
    const UNIX: &'static str = "unix";

    fn now() -> DateTime<Utc> {
        Utc::now()
    }

    fn fmt_with_custom_format(now: DateTime<Utc>, h: &Helper) -> Option<String> {
        if let Some(format) = h.get_str_hash(Self::FORMAT) {
            match format {
                Self::EPOCH => SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .map(|d| d.as_millis().to_string())
                    .ok(),
                Self::UNIX => SystemTime::now()
                    .duration_since(UNIX_EPOCH)
                    .map(|d| d.as_secs().to_string())
                    .ok(),
                _ => simpledateformat::fmt(format).map(|d| d.format(&now)).ok(),
            }
        } else {
            Some(now.to_rfc3339_opts(SecondsFormat::Secs, true))
        }
    }

    fn apply_offset(now: DateTime<Utc>, h: &Helper) -> DateTime<Utc> {
        h.get_str_hash(Self::OFFSET)
            .map(|it| it.replace(' ', ""))
            .and_then(|offset| Self::compute_offset(now, offset))
            .unwrap_or(now)
    }

    fn compute_offset(now: DateTime<Utc>, offset: String) -> Option<DateTime<Utc>> {
        let is_negative = offset.starts_with('-');
        let offset = if is_negative {
            offset.trim_start_matches('-')
        } else {
            offset.as_str()
        };
        parse_duration(offset)
            .ok()
            .and_then(|it| Duration::from_std(it).ok())
            .map(|rhs| if is_negative { now - rhs } else { now + rhs })
    }

    fn apply_timezone(now: DateTime<Utc>, h: &Helper) -> DateTime<Utc> {
        h.get_str_hash(Self::TIMEZONE)
            .and_then(|timezone| timezone.parse().ok())
            .map(|tz: Tz| tz.offset_from_utc_datetime(&now.naive_utc()).fix().local_minus_utc())
            .map(i64::from)
            .map(Duration::seconds)
            .map(|offset: Duration| now + offset)
            .unwrap_or(now)
    }
}

impl HelperDef for NowHelper {
    fn call_inner<'reg: 'rc, 'rc>(
        &self, h: &Helper<'reg, 'rc>, _: &'reg Handlebars<'reg>, _: &'rc Context, _: &mut RenderContext<'reg, 'rc>,
    ) -> Result<ScopedJson<'reg, 'rc>, RenderError> {
        let now = Self::now();
        let now = Self::apply_timezone(now, h);
        let now = Self::apply_offset(now, h);
        Self::fmt_with_custom_format(now, h)
            .map(Value::from)
            .map(ScopedJson::from)
            .ok_or_else(|| RenderError::new("Failed rendering now with custom format"))
    }
}