Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you add the current year to a Go template?

In a Go template, you can retrieve a field like this:

template.Parse("<html><body>{{ .Title }}</body></html>")
template.Execute(w, myObject)

How would you "inline" the current UTC year? I want to do something like this:

template.Parse("<html><body>The current year is {{time.Time.Now().UTC().Year()}}</body></html>")

But it returns the error:

panic: template: function "time" not defined

like image 863
BlueSky Avatar asked Mar 20 '17 04:03

BlueSky


2 Answers

you can add function to template, try this:

package main

import (
    "html/template"
    "log"
    "os"
    "time"
)

func main() {
    funcMap := template.FuncMap{
        "now": time.Now,
    }

    templateText := "<html><body>The current year is {{now.UTC.Year}}</body></html>"
    tmpl, err := template.New("titleTest").Funcs(funcMap).Parse(templateText)
    if err != nil {
        log.Fatalf("parsing: %s", err)
    }

    // Run the template to verify the output.
    err = tmpl.Execute(os.Stdout, nil)
    if err != nil {
        log.Fatalf("execution: %s", err)
    }
}
like image 138
zzn Avatar answered Sep 24 '22 03:09

zzn


You're already including a Title in your template. How does that end up in the template? You pass it as an argument to Template.Execute(). This (unsurprisingly) works for the current year too.

It's a better and easier solution than registering a function for this. This is how it could look like:

t := template.Must(template.New("").Parse(
    "<html><body>{{ .Title }}; Year: {{.Year}}</body></html>"))

myObject := struct {
    Title string
    Year  int
}{"Test Title", time.Now().UTC().Year()}

if err := t.Execute(os.Stdout, myObject); err != nil {
    fmt.Println(err)
}

Output (try it on the Go Playground):

<html><body>Test Title; Year: 2009</body></html>

(Note: the current date/time on the Go Playground is 2009-11-10 23:00:00, that's why you see 2009).

By design philosophy, templates should not contain complex logic. If something is (or looks) too complex in templates, you should consider calculating the result in Go code and either pass the result as data to the execution, or register a callback function in the templates and have a template action call that function and insert the return value.

Arguably getting the current year is not a complex logic. But Go is a statically linked language. You only have guarantee that the executable binary will only include packages and functions that your Go (source) code refers to explicitly. This applies to all packages of the standard library (except the runtime package). So a template text cannot just refer to and call functions from packages like the time package, because there is no guarantee that will be available at runtime.

like image 44
icza Avatar answered Sep 21 '22 03:09

icza