Add date and tz functions to templates (#3812)
* Add date and tz functions to templates This commit adds the date and tz functions to templates. This means users can now format time in a specified format and also change the timezone to their specific locale. An example of how these functions work, and can be composed together, can be seen here: {{ .StartsAt | tz "Europe/Paris" | date "15:04:05 MST" }} Signed-off-by: George Robinson <george.robinson@grafana.com> --------- Signed-off-by: George Robinson <george.robinson@grafana.com>
This commit is contained in:
parent
cb9724db47
commit
dc1e1a2b88
|
@ -95,3 +95,5 @@ templating.
|
||||||
| join | sep string, s []string | [strings.Join](http://golang.org/pkg/strings/#Join), concatenates the elements of s to create a single string. The separator string sep is placed between elements in the resulting string. (note: argument order inverted for easier pipelining in templates.) |
|
| join | sep string, s []string | [strings.Join](http://golang.org/pkg/strings/#Join), concatenates the elements of s to create a single string. The separator string sep is placed between elements in the resulting string. (note: argument order inverted for easier pipelining in templates.) |
|
||||||
| safeHtml | text string | [html/template.HTML](https://golang.org/pkg/html/template/#HTML), Marks string as HTML not requiring auto-escaping. |
|
| safeHtml | text string | [html/template.HTML](https://golang.org/pkg/html/template/#HTML), Marks string as HTML not requiring auto-escaping. |
|
||||||
| stringSlice | ...string | Returns the passed strings as a slice of strings. |
|
| stringSlice | ...string | Returns the passed strings as a slice of strings. |
|
||||||
|
| date | string, time.Time | Returns the text representation of the time in the specified format. For documentation on formats refer to [pkg.go.dev/time](https://pkg.go.dev/time#pkg-constants). |
|
||||||
|
| tz | string, time.Time | Returns the time in the timezone. For example, Europe/Paris. |
|
||||||
|
|
|
@ -192,6 +192,18 @@ var DefaultFuncs = FuncMap{
|
||||||
"stringSlice": func(s ...string) []string {
|
"stringSlice": func(s ...string) []string {
|
||||||
return s
|
return s
|
||||||
},
|
},
|
||||||
|
// date returns the text representation of the time in the specified format.
|
||||||
|
"date": func(fmt string, t time.Time) string {
|
||||||
|
return t.Format(fmt)
|
||||||
|
},
|
||||||
|
// tz returns the time in the timezone.
|
||||||
|
"tz": func(name string, t time.Time) (time.Time, error) {
|
||||||
|
loc, err := time.LoadLocation(name)
|
||||||
|
if err != nil {
|
||||||
|
return time.Time{}, err
|
||||||
|
}
|
||||||
|
return t.In(loc), nil
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pair is a key/value string pair.
|
// Pair is a key/value string pair.
|
||||||
|
|
|
@ -473,10 +473,11 @@ func TestTemplateFuncs(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
for _, tc := range []struct {
|
for _, tc := range []struct {
|
||||||
title string
|
title string
|
||||||
in string
|
in string
|
||||||
data interface{}
|
data interface{}
|
||||||
exp string
|
exp string
|
||||||
|
expErr string
|
||||||
}{{
|
}{{
|
||||||
title: "Template using toUpper",
|
title: "Template using toUpper",
|
||||||
in: `{{ "abc" | toUpper }}`,
|
in: `{{ "abc" | toUpper }}`,
|
||||||
|
@ -506,6 +507,21 @@ func TestTemplateFuncs(t *testing.T) {
|
||||||
title: "Template using reReplaceAll",
|
title: "Template using reReplaceAll",
|
||||||
in: `{{ reReplaceAll "ab" "AB" "abc" }}`,
|
in: `{{ reReplaceAll "ab" "AB" "abc" }}`,
|
||||||
exp: "ABc",
|
exp: "ABc",
|
||||||
|
}, {
|
||||||
|
title: "Template using date",
|
||||||
|
in: `{{ . | date "2006-01-02" }}`,
|
||||||
|
data: time.Date(2024, 1, 1, 8, 15, 30, 0, time.UTC),
|
||||||
|
exp: "2024-01-01",
|
||||||
|
}, {
|
||||||
|
title: "Template using tz",
|
||||||
|
in: `{{ . | tz "Europe/Paris" }}`,
|
||||||
|
data: time.Date(2024, 1, 1, 8, 15, 30, 0, time.UTC),
|
||||||
|
exp: "2024-01-01 09:15:30 +0100 CET",
|
||||||
|
}, {
|
||||||
|
title: "Template using invalid tz",
|
||||||
|
in: `{{ . | tz "Invalid/Timezone" }}`,
|
||||||
|
data: time.Date(2024, 1, 1, 8, 15, 30, 0, time.UTC),
|
||||||
|
expErr: "template: :1:7: executing \"\" at <tz \"Invalid/Timezone\">: error calling tz: unknown time zone Invalid/Timezone",
|
||||||
}} {
|
}} {
|
||||||
tc := tc
|
tc := tc
|
||||||
t.Run(tc.title, func(t *testing.T) {
|
t.Run(tc.title, func(t *testing.T) {
|
||||||
|
@ -515,8 +531,13 @@ func TestTemplateFuncs(t *testing.T) {
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
got, err := tmpl.ExecuteTextString(tc.in, tc.data)
|
got, err := tmpl.ExecuteTextString(tc.in, tc.data)
|
||||||
require.NoError(t, err)
|
if tc.expErr == "" {
|
||||||
require.Equal(t, tc.exp, got)
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tc.exp, got)
|
||||||
|
} else {
|
||||||
|
require.EqualError(t, err, tc.expErr)
|
||||||
|
require.Empty(t, got)
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
Loading…
Reference in New Issue