sebastienros/fluid

Tip - 'local_date' filter to always convert a datetime to configured TimeZone

Closed this issue · 1 comments

My use-case was to always convert a ISO8601+time-offset datetime string into the configured TemplateContext.TimeZone property.

So to do so, I created a 'local_date' filter that does exactly that:

internal static class FluidFilters
{
    public static ValueTask<FluidValue> LocalDateFilter(FluidValue input, FilterArguments arguments, TemplateContext context)
    {
        var value = TimeZoneConverter(input, context);
        return ReferenceEquals(value, NilValue.Instance) ? value : MiscFilters.Date(value, arguments, context);
    }

    private static FluidValue TimeZoneConverter(FluidValue input, TemplateContext context)
    {
        if (!input.TryGetDateTimeInput(context, out var value))
        {
            return NilValue.Instance;
        }

        var result = TimeZoneInfo.ConvertTime(value, context.TimeZone);
        return new DateTimeValue(result);        
    }
}

And code to use the above:

    [Theory]
    [InlineData("2022-12-07T22:22:18.1234-05:00")]
    [InlineData("2022-12-08T03:22:18.1234+00:00")]
    [InlineData("2022-12-08T05:22:18.1234+02:00")]
    [InlineData("2022-12-08T13:52:18.1234+10:30")]
    public void local_date_filter_should_convert_ISO8601_plus_offset_to_time_for_configured_TimeZone(
        string timestamp)
    {
        var templateOptions = new TemplateOptions
        {
            TimeZone = TimeZoneInfo.FindSystemTimeZoneById("Indian/Maldives"),
        };
        templateOptions.Filters.AddFilter("local_date", FluidFilters.LocalDateFilter);
        
        var parser = new FluidParser();
        var template = parser.Parse(@"Published at: {{ PublishedAt | local_date: ""%e %b %y %r"" }}");
        var result = template.Render(new TemplateContext(new {PublishedAt = timestamp}, templateOptions));

        Assert.Equal("Published at:  8 Dec 22 08:22:18 AM", result);
    }

Originally posted by @nicholas-brooks in #537 (comment)

I think that's a sensible request. I'd rather have this filter related to timezones though (instead of dates), and use the standard | date: ... filter for formatting. That isolates this Fluid specific feature in the same way as it does for timezones.

One option could be with a special timezone name, like {{ now | date | time_zone: 'local' }}
This would not require an extra filter.