Computing time/duration in Golang templates

Issue

I have a structure that gets rendered via template. e.g.:

type Foo struct {
  Created time.Time
  ...
}

I pass this value to a template, and I’d like to this rendered see:

  Created at 2022-11-22 9:50 (0d1h12m34s ago)

Displaying the timestamp (and formatting it) is easy enough, but I can’t find a way to calculate the interval.

Created at {{.Created}} ({{???}} ago)

In go, this would be accomplished by time.Since(foo.Created) which returns a Duration, and then I can convert duration to string in various ways.

But doing the calculation in the template itself does not seem possible:

function "time" not defined

Or is it?
Can’t find any information that explicitly tells me that time (or other arbitrary functions) are never ever allowed in templates. So I don’t know if I’m just calling it wrong.

(I know I could create a new FooTemplateValue from a Foo add that field, so the template can render the duration as-is. I was just trying to avoid it if I can and use the actual object as-is).

Solution

You can register a custom template function using template.FuncMap, then you can invoke that function inside the template just like you would invoke a builtin function.

template.New("").Funcs(template.FuncMap{
    "dur_until_now": func(t time.Time) time.Duration {
        return time.Now().Sub(t)
    },
}).Parse(`{{ dur_until_now .Created }}`)

https://go.dev/play/p/wM2f1oDFtDr


Or you can declare a custom time type and have that type implement a method that produces the desired value, then you can invoke that method inside the template directly on the field.

type MyTime struct{ time.Time }

func (t MyTime) DurUntilNow() time.Duration {
    return time.Now().Sub(t.Time)
}

// ...
.Parse(`{{ .Created.DurUntilNow }}`)

https://go.dev/play/p/3faW4nTzK3-

Answered By – mkopriva

Answer Checked By – Katrina (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.