What's the idiomatic way to work with dates without time in golang?

huangapple go评论183阅读模式
英文:

What's the idiomatic way to work with dates without time in golang?

问题

我正在使用Go编写一个REST API,处理的日期不代表一个具体的时间点。

JSON数据以“2006-01-02”格式在服务器和客户端之间传输,该数据与使用DATE列的mysql数据库进行交互。

我尝试的一种方法是创建一个嵌入了Time的结构体,并实现JSON和SQL转换接口的实现,以便能够正确地与端点交互,同时仍然可以使用Time方法进行日期计算和格式化。例如:

  1. package localdate
  2. import (
  3. "time"
  4. "encoding/json"
  5. "database/sql/driver"
  6. )
  7. type LocalDate struct {
  8. time.Time
  9. }
  10. func NewLocalDate(year int, month time.Month, day int) LocalDate {
  11. time := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
  12. return LocalDate{Time: time}
  13. }
  14. const LocalDateFormat = "2006-01-02" // yyyy-mm-dd
  15. func (ld *LocalDate) UnmarshalJSON(data []byte) error {
  16. // 解析并设置ld.Time变量
  17. }
  18. func (ld *LocalDate) MarshalJSON() ([]byte, error) {
  19. return json.Marshal(ld.Format(LocalDateFormat))
  20. }
  21. // sql.Scanner implementation to convert a time.Time column to a LocalDate
  22. func (ld *LocalDate) Scan(value interface{}) error {}
  23. // sql/driver.Valuer implementation to go from LocalDate -> time.Time
  24. func (ld *LocalDate) Value() (driver.Value, error) {}
  25. // 用于将LocalDate转换为可以插入查询的内容
  26. // 我们可以直接使用ld.Time,但这将发送“2015-01-01 00:00:00 +0000 UTC”
  27. // 而不是DATE查询参数的“2015-01-01”。(这对于mysql有效,但官方上是无效的SQL)
  28. func (ld *LocalDate) SqlDate() string {
  29. return ld.Format(LocalDateFormat)
  30. }

然后其他结构体可以使用这种类型,并且在我的问题领域中可以实现日期类型的90%功能。

上述代码可以工作,但我觉得我在与Go的潮流作斗争。所以对于这门语言的老手,我有几个问题:

你认为这段代码会带来更多的痛苦吗?
如果是这样,你会推荐使用哪种风格?

英文:

I'm writing a REST API in Go, working with dates that don't represent a single point in time.

It's JSON data going to and from the server in "2006-01-02" format, with that data talking to a mysql database using DATE columns.

One thing I've tried is to create a struct that embeds a Time, and implements JSON and SQL conversion interface implementations to be able to correctly interact with the endpoints while still having Time methods available for date math and formatting. e.g.:

  1. package localdate
  2. import (
  3. "time"
  4. "encoding/json"
  5. "database/sql/driver"
  6. )
  7. type LocalDate struct {
  8. time.Time
  9. }
  10. func NewLocalDate(year int, month time.Month, day int) LocalDate {
  11. time := time.Date(year, month, day, 0, 0, 0, 0, time.UTC)
  12. return LocalDate{Time: time}
  13. }
  14. const LocalDateFormat = "2006-01-02" // yyyy-mm-dd
  15. func (ld *LocalDate) UnmarshalJSON(data []byte) error {
  16. // parse and set the ld.Time variable
  17. }
  18. func (ld *LocalDate) MarshalJSON() ([]byte, error) {
  19. return json.Marshal(ld.Format(LocalDateFormat))
  20. }
  21. // sql.Scanner implementation to convert a time.Time column to a LocalDate
  22. func (ld *LocalDate) Scan(value interface{}) error {}
  23. // sql/driver.Valuer implementation to go from LocalDate -> time.Time
  24. func (ld *LocalDate) Value() (driver.Value, error) {}
  25. // used to convert a LocalDate into something we can plug into a query
  26. // we could just use ld.Time, but that would send '2015-01-01 00:00:00 +0000 UTC'
  27. // instead of '2015-01-01' for the DATE query parameter. (Which works for mysql, but is officially invalid SQL)
  28. func (ld *LocalDate) SqlDate() string {
  29. return ld.Format(LocalDateFormat)
  30. }

And then other structs can be of this type, and get 90% there to representing the date type in my problem domain.

The above code works, but I feel like I'm fighting against the Go current. So a couple questions for the veterans of the language:

Do you think this code will cause more pain than it'll save?
If so, what style would you recommend?

答案1

得分: 11

我使用来自cloud.google.com/go/civil包的civil.Date

英文:

I use civil.Date from the package cloud.google.com/go/civil

答案2

得分: 3

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

  1. type LocalDate struct {
  2. t time.Time `json:",string"` // 甚至可以在这里匿名工作
  3. }

关于如何在SQL中使用这个方法,请参考:https://github.com/go-sql-driver/mysql#timetime-support

英文:

I think you can store your data as time.Time but convert it to a string for JSON purposes:

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

To see how to make this work with SQL: https://github.com/go-sql-driver/mysql#timetime-support

答案3

得分: 0

如果项目使用Gorm,我们可以自由地使用gorm.io/datatypes中的datatypes.Date

  1. import "gorm.io/datatypes"
  2. type UserWithDate struct {
  3. gorm.Model
  4. Name string
  5. Date datatypes.Date
  6. }
  7. user := UserWithDate{Name: "jinzhu", Date: datatypes.Date(time.Now())}
  8. DB.Create(&user)
  9. // INSERT INTO `user_with_dates` (`name`,`date`) VALUES ("jinzhu","2020-07-17 00:00:00")
  10. DB.First(&result, "name = ? AND date = ?", "jinzhu", datatypes.Date(curTime))
  11. // 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,但时间部分的值为零。
我使用的示例:

  1. // 将日期时间的时间部分设为零
  2. date, err := datatypes.Date(time.Now()).Value()
  3. if err != nil {
  4. return err
  5. }
  6. dateValue := date.(time.Time)
英文:

If the project uses Gorm then we can freely use datatypes.Date from gorm.io/datatypes

  1. import "gorm.io/datatypes"
  2. type UserWithDate struct {
  3. gorm.Model
  4. Name string
  5. Date datatypes.Date
  6. }
  7. user := UserWithDate{Name: "jinzhu", Date: datatypes.Date(time.Now())}
  8. DB.Create(&user)
  9. // INSERT INTO `user_with_dates` (`name`,`date`) VALUES ("jinzhu","2020-07-17 00:00:00")
  10. DB.First(&result, "name = ? AND date = ?", "jinzhu", datatypes.Date(curTime))
  11. // SELECT * FROM user_with_dates WHERE name = "jinzhu" AND date = "2020-07-17 00:00:00" ORDER BY `user_with_dates`.`id` LIMIT 1

Source: github.com/go-gorm/datatypes#date

Under the hood, it's still time.Time, but with zeroed values of the time part.
Example of my usage:

  1. // make the time part of datetime equal to zero
  2. date, err := datatypes.Date(time.Now()).Value()
  3. if err != nil {
  4. return err
  5. }
  6. dateValue := date.(time.Time)

huangapple
  • 本文由 发表于 2015年2月11日 12:49:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/28446796.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定