From 0e08c916df51c753dcdabc11dbb3721c38cd2a12 Mon Sep 17 00:00:00 2001 From: Jusabe Guedes Date: Mon, 14 Sep 2026 12:13:56 +0000 Subject: [PATCH] Add MarshalText to types.Date Date defines UnmarshalText, which parses the "2006-01-02" DateFormat, but has no MarshalText, so it inherits time.Time's RFC 3339 one. Every codec that pairs encoding.TextMarshaler with encoding.TextUnmarshaler therefore writes a Date it cannot read back: xml.Marshal -> 2019-04-01T00:00:00Z xml.Unmarshal -> parsing time "2019-04-01T00:00:00Z": extra text: "T00:00:00Z" Format with DateFormat instead, matching MarshalJSON, String and UnmarshalText, and matching the method set types.Duration already carries. This also resolves the XML round trip that #58 addressed with MarshalXML and UnmarshalXML, without needing the encoding/xml import. Co-Authored-By: Claude Opus 5 (1M context) --- types/date.go | 4 ++++ types/date_test.go | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/types/date.go b/types/date.go index 155751ac..393dbdab 100644 --- a/types/date.go +++ b/types/date.go @@ -33,6 +33,10 @@ func (d Date) String() string { return d.Format(DateFormat) } +func (d Date) MarshalText() ([]byte, error) { + return []byte(d.Format(DateFormat)), nil +} + func (d *Date) UnmarshalText(data []byte) error { parsed, err := time.Parse(DateFormat, string(data)) if err != nil { diff --git a/types/date_test.go b/types/date_test.go index 21177652..2f927f06 100644 --- a/types/date_test.go +++ b/types/date_test.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "encoding/xml" "fmt" "testing" "time" @@ -53,6 +54,46 @@ func TestDate_Stringer(t *testing.T) { }) } +func TestDate_MarshalText(t *testing.T) { + date := Date{Time: time.Date(2022, 6, 14, 0, 0, 0, 0, time.UTC)} + + value, err := date.MarshalText() + + assert.NoError(t, err) + assert.Equal(t, "2022-06-14", string(value)) +} + +func TestDate_TextRoundTrip(t *testing.T) { + testDate := time.Date(2022, 6, 14, 0, 0, 0, 0, time.UTC) + + value, err := Date{Time: testDate}.MarshalText() + assert.NoError(t, err) + + date := Date{} + err = date.UnmarshalText(value) + + assert.NoError(t, err) + assert.Equal(t, testDate, date.Time) +} + +func TestDate_XMLRoundTrip(t *testing.T) { + testDate := time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC) + type body struct { + XMLName xml.Name `xml:"body"` + DateField Date `xml:"date"` + } + + xmlBytes, err := xml.Marshal(body{DateField: Date{testDate}}) + assert.NoError(t, err) + assert.Equal(t, `2019-04-01`, string(xmlBytes)) + + var b body + err = xml.Unmarshal(xmlBytes, &b) + + assert.NoError(t, err) + assert.Equal(t, testDate, b.DateField.Time) +} + func TestDate_UnmarshalText(t *testing.T) { testDate := time.Date(2022, 6, 14, 0, 0, 0, 0, time.UTC) value := []byte("2022-06-14")