You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Gorilla Schema解析特定格式表单日期至结构体

Got it, let's tackle this problem! The gorilla/schema package doesn't automatically parse dd/mm/yyyy dates into time.Time fields out of the box—it defaults to using RFC3339 format for time parsing. Here are two solid, practical ways to fix this:


Create a custom type wrapping time.Time and implement the encoding.TextUnmarshaler interface. This tells gorilla/schema exactly how to parse your date format for this specific field.

package main

import (
	"encoding"
	"fmt"
	"net/url"
	"time"

	"github.com/gorilla/schema"
)

// CustomDate wraps time.Time to handle our dd/mm/yyyy format
type CustomDate time.Time

// UnmarshalText implements encoding.TextUnmarshaler
func (cd *CustomDate) UnmarshalText(b []byte) error {
	dateStr := string(b)
	// Go's layout uses a fixed reference time: "02/01/2006" maps to dd/mm/yyyy
	t, err := time.Parse("02/01/2006", dateStr)
	if err != nil {
		return fmt.Errorf("invalid date format (expected dd/mm/yyyy): %w", err)
	}
	*cd = CustomDate(t)
	return nil
}

// Optional: Add a String method to format dates when printing
func (cd CustomDate) String() string {
	return time.Time(cd).Format("02/01/2006")
}

// Your form struct using the custom date type
type EventForm struct {
	EventDate CustomDate `schema:"event_date"`
}

func main() {
	// Simulate form data submitted in dd/mm/yyyy format
	formData := url.Values{
		"event_date": []string{"15/08/2024"},
	}

	var parsedForm EventForm
	decoder := schema.NewDecoder()
	err := decoder.Decode(&parsedForm, formData)
	if err != nil {
		panic(err)
	}

	// Convert back to time.Time if you need standard time operations
	eventTime := time.Time(parsedForm.EventDate)
	fmt.Println("Parsed date (RFC3339):", eventTime.Format(time.RFC3339))
}

Why this works:

gorilla/schema checks if a field type implements TextUnmarshaler and uses that method instead of its default parsing logic. This keeps your date validation tied directly to the field type, making your code more maintainable.


Method 2: Register a Global Converter (For Multiple Structs)

If you have multiple structs that need to parse dd/mm/yyyy into time.Time fields, register a custom converter with your schema decoder. This applies to all time.Time fields using that decoder instance.

package main

import (
	"fmt"
	"net/url"
	"reflect"
	"time"

	"github.com/gorilla/schema"
)

type EventForm struct {
	EventDate time.Time `schema:"event_date"`
}

func main() {
	formData := url.Values{
		"event_date": []string{"15/08/2024"},
	}

	var parsedForm EventForm
	decoder := schema.NewDecoder()

	// Register custom converter for time.Time
	decoder.RegisterConverter(time.Time{}, func(value string) reflect.Value {
		t, err := time.Parse("02/01/2006", value)
		if err != nil {
			// Handle error as needed—here we return a zero time, but you could panic or log
			return reflect.ValueOf(time.Time{})
		}
		return reflect.ValueOf(t)
	})

	err := decoder.Decode(&parsedForm, formData)
	if err != nil {
		panic(err)
	}

	fmt.Println("Parsed date:", parsedForm.EventDate.Format(time.RFC1123))
}

Important Notes:

  • Double-check your Go layout string: "02/01/2006" is the correct mapping for dd/mm/yyyy (Go uses a fixed reference time to define layouts).
  • Error handling: Adjust the error logic in the converter or UnmarshalText method to match your application's needs (e.g., return a user-friendly error instead of panicking).
  • Empty dates: If your form allows empty date fields, add a check for empty strings in your parsing logic to avoid errors.

内容的提问来源于stack exchange,提问作者Oleh Sobchuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:06:09