Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use civil.Date for date fields #155

Open
jpmeijers opened this issue Sep 6, 2022 · 1 comment
Open

Use civil.Date for date fields #155

jpmeijers opened this issue Sep 6, 2022 · 1 comment
Assignees

Comments

@jpmeijers
Copy link

Describe the feature

Rather than using time.Time for sql date fields, shouldn't we rather use civil.Date from https://pkg.go.dev/cloud.google.com/go/civil. This latter type seems to be the standard way to handle dates in go.

Motivation

If one uses time.Time to represent dates, the time part is set to all 0's. If the end user isn't aware that the time part should be ignored, this can cause confusion, and even create errors if it's interpreted in a GMT+ve timezone.

Related Issues

Other

I tried defining a custom struct that uses civil.Date fields, and scanning the database result into this struct. This resulted in a date with value 0000-00-00.

@jpmeijers
Copy link
Author

I ended up writing a custom type based on gorm's Date.

package customtypes

import (
	"cloud.google.com/go/civil"
	"database/sql"
	"database/sql/driver"
	"time"
)

type Date civil.Date

func (date *Date) Scan(value interface{}) (err error) {
	nullTime := &sql.NullTime{}
	err = nullTime.Scan(value)
	*date = Date(civil.DateOf(nullTime.Time))
	return
}

func (date Date) Value() (driver.Value, error) {
	return time.Date(date.Year, date.Month, date.Day, 0, 0, 0, 0, time.UTC), nil
}

// GormDataType gorm common data type
func (date Date) GormDataType() string {
	return "date"
}

func (date Date) GobEncode() ([]byte, error) {
	return civil.Date(date).In(time.UTC).GobEncode()
}

func (date *Date) GobDecode(b []byte) error {
	var timeVal time.Time
	err := timeVal.GobDecode(b)
	if err != nil {
		return err
	}
	dateVal := Date(civil.DateOf(timeVal))
	*date = dateVal
	return nil
}

func (date Date) MarshalJSON() ([]byte, error) {
	marshalled := make([]byte, 0)
	text, err := civil.Date(date).MarshalText()
	marshalled = append(marshalled, byte('"'))
	marshalled = append(marshalled, text...)
	marshalled = append(marshalled, byte('"'))
	return marshalled, err
}

func (date *Date) UnmarshalJSON(b []byte) error {
	c := civil.Date{}
	err := c.UnmarshalText(b[1 : len(b)-1])
	*date = Date(c)
	return err
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants