在Go模板中验证日期

I am trying to ensure I have a valid date in my template file and if so populate a div, otherwise leave it blank. The data type is mysql.NullTime.

Here is what I am trying to do:

{{ if .StartDate ne nil }}
   <div class="box date-row" id="startdate-{{ .DepartureTimeID }}">{{ .StartDate.Format "2006-01-02" }}</div>
{{ else }}
   <div class="box date-row" id="startdate-{{ .DepartureTimeID }}"></div>
{{ end }}

That does seem to work, how can I test for a non-null date?

If it is a mandatory value, you should validate it before you render the template.

However, if it is optional and/or you are writing a template driven application, you have at least two options to achieve what you want.

Using zero values only

Put zero values to good use: for time.Time that is epoch. So, assuming you can not have a StartDate in the past, you can compare wether your StartDate is after epoch.

package main

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

// Note the call to the `After` function of the date.
const templateText = `
{{ if .Data.StartDate.After .Epoch }}
   <div class="box date-row" id="startdate-{{ .Data.DepartureTimeID }}">{{ .Data.StartDate.Format "2006-01-02" }}</div>
{{ else }}
   <div class="box date-row" id="startdate-{{ .Data.DepartureTimeID }}">No date</div>
{{ end }}
`

func main() {

     // shortcut for the sake of brevity.
    tmpl := template.Must(template.New("titleTest").Parse(templateText))

    // Create an anonymous wrapper struct for your data and the additional
    // time value you need to compare against
    tcx := struct {

        // This of course may be of the type you actually use.
        Data struct {
            StartDate       time.Time
            DepartureTimeID int
        }
        Epoch time.Time
    }{
        Data: struct {
            StartDate       time.Time
            DepartureTimeID int
        }{time.Now(), 1},
        Epoch: time.Time{},
    }

    tmpl.Execute(os.Stdout, tcx)
}

Run on playground

Using a custom function

This is pretty much self explanatory: simply define a custom function that validates your date. In this example, I have checked against the zero value again. However, you can get as granular as you wish, of course:

package main

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

const templateText = `
{{ if afterEpoch .StartDate }}
   <div class="box date-row" id="startdate-{{ .DepartureTimeID }}">{{ .StartDate.Format "2006-01-02" }}</div>
{{ else }}
   <div class="box date-row" id="startdate-{{ .DepartureTimeID }}"></div>
{{ end }}
`

func AfterEpoch(t time.Time) bool {
    return t.After(time.Time{})
}

type yourData struct {
    DepartureTimeID int
    StartDate       time.Time
}

func main() {
    funcMap := template.FuncMap{
        "afterEpoch": AfterEpoch,
    }

    tmpl := template.Must(template.New("fmap").Funcs(funcMap).Parse(templateText))

    log.Println("First run")
    tmpl.Execute(os.Stdout, yourData{1, time.Now()})


    log.Println("Second run")
    tmpl.Execute(os.Stdout, yourData{DepartureTimeID:1})
}

Edit:

Of course, you can also use the pipe notation for the second solution, which is by for more readable, imho: {{ if .StartDate | afterEpoch }}

Run on playground