在golang中处理没有时间的日期的惯用方法是什么?

sqxo8psd  于 2023-04-03  发布在  Go
关注(0)|答案(3)|浏览(126)

我正在用Go编写一个REST API,使用不代表单个时间点的日期。
它是以“2006-01-02”格式进出服务器的JSON数据,该数据使用DATE列与mysql数据库通信。
我尝试过的一件事是创建一个嵌入Time的结构体,并实现JSON和SQL转换接口实现,以便能够正确地与端点交互,同时仍然有Time方法可用于日期数学和格式化。

package localdate

import (
    "time"
    "encoding/json"
    "database/sql/driver"
)

type LocalDate struct {
    time.Time
}

func NewLocalDate(year int, month time.Month, day int) LocalDate {
    time := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
    return LocalDate{Time: time}
}

const LocalDateFormat = "2006-01-02" // yyyy-mm-dd

func (ld *LocalDate) UnmarshalJSON(data []byte) error {
    // parse and set the ld.Time variable
}

func (ld *LocalDate) MarshalJSON() ([]byte, error) {
    return json.Marshal(ld.Format(LocalDateFormat))
}

// sql.Scanner implementation to convert a time.Time column to a LocalDate
func (ld *LocalDate) Scan(value interface{}) error {}

// sql/driver.Valuer implementation to go from LocalDate -> time.Time
func (ld *LocalDate) Value() (driver.Value, error)  {}

// used to convert a LocalDate into something we can plug into a query
// we could just use ld.Time, but that would send '2015-01-01 00:00:00 +0000 UTC'
// instead of '2015-01-01' for the DATE query parameter.  (Which works for mysql, but is officially invalid SQL)
func (ld *LocalDate) SqlDate() string  {
    return ld.Format(LocalDateFormat)
}

然后其他的结构体也可以是这种类型,并且在我的问题域中有90%的时间表示日期类型。
上面的代码可以工作,但是我感觉我在和Go语言的潮流作斗争,所以有几个问题要问这门语言的老手:
你认为这段代码会比它能保存的更痛苦吗?
如果是的话,你会推荐什么款式?

wwodge7n

wwodge7n2#

我认为你可以将数据存储为time.Time,但将其转换为JSON用途的字符串:

type LocalDate struct {
  t time.Time `json:",string"` // might even work anonymously here
}

要了解如何使用SQL实现此功能:https://github.com/go-sql-driver/mysql#timetime-support

xt0899hw

xt0899hw3#

如果项目使用Gorm,那么我们可以从gorm.io/datatypes自由使用datatypes.Date

import "gorm.io/datatypes"

type UserWithDate struct {
    gorm.Model
    Name string
    Date datatypes.Date
}

user := UserWithDate{Name: "jinzhu", Date: datatypes.Date(time.Now())}
DB.Create(&user)
// INSERT INTO `user_with_dates` (`name`,`date`) VALUES ("jinzhu","2020-07-17 00:00:00")

DB.First(&result, "name = ? AND date = ?", "jinzhu", datatypes.Date(curTime))
// SELECT * FROM user_with_dates WHERE name = "jinzhu" AND date = "2020-07-17 00:00:00" ORDER BY `user_with_dates`.`id` LIMIT 1

来源:github.com/go-gorm/datatypes#date
在引擎盖下,它仍然是time.Time,但时间部分的值为零。
我的用法示例:

// make the time part of datetime equal to zero
date, err := datatypes.Date(time.Now()).Value()
if err != nil {
    return err
}

dateValue := date.(time.Time)

相关问题