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).
CodePudding user response:
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-
CodePudding user response:
Looks like you need to initialize the Created field with time.Now()
package main
import (
"fmt"
"time"
)
type Foo struct {
Created time.Time
// ...
}
func main() {
x := Foo{Created: time.Now()}
fmt.Println(time.Since(x.Created))
}