Computing time/duration in Golang templates

huangapple go评论90阅读模式
英文:

Computing time/duration in Golang templates

问题

我有一个通过template渲染的结构体,例如:

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

我将这个值传递给一个模板,我希望它被渲染成这样:

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

显示时间戳(并格式化它)很容易,但我找不到计算时间间隔的方法。

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

在Go中,可以通过time.Since(foo.Created)来实现,它返回一个Duration,然后可以以不同的方式将持续时间转换为字符串。

但是在模板本身中进行计算似乎是不可能的:

function "time" not defined

或者说呢?
我找不到任何明确告诉我time(或其他任意函数)在模板中是绝对不允许的信息。所以我不知道我是不是调用方法不对。

(我知道我可以从Foo创建一个新的FooTemplateValue,添加该字段,这样模板就可以直接渲染持续时间。我只是想避免这样做,如果可能的话,直接使用实际的对象)。

英文:

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).

答案1

得分: 1

你可以使用template.FuncMap注册一个自定义模板函数,然后在模板中像调用内置函数一样调用该函数。

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


或者你可以声明一个自定义的时间类型,并使该类型实现一个生成所需值的方法,然后你可以在模板中直接在字段上调用该方法。

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-

英文:

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-

答案2

得分: -2

看起来你需要使用time.Now()来初始化Created字段。

package main

import (
	"fmt"
	"time"
)

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

func main() {
	x := Foo{Created: time.Now()}

	fmt.Println(time.Since(x.Created))
}

请注意,以上代码是使用Go语言编写的。它定义了一个名为Foo的结构体,其中包含一个Created字段,类型为time.Time。在main函数中,我们创建了一个Foo类型的变量x,并使用time.Now()函数将当前时间赋值给了x的Created字段。最后,我们打印了从Created字段到当前时间的时间间隔。

英文:

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))
}

huangapple
  • 本文由 发表于 2022年11月23日 02:00:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/74537174.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定