Go 将时间从DB转换为自定义时间失败

Go 将时间从DB转换为自定义时间失败,go,go-gorm,Go,Go Gorm,我需要从数据库中读取日期,将其转换为特定的时间戳并将其转换为JSON 我有以下代码: package usages import ( "fmt" "time" ) type SpecialOffer struct { PublishedDate jsonTime `gorm:"column:publishing_date" json:"published_date"` ExpirationDate jsonTime `gorm:"column

我需要从数据库中读取日期,将其转换为特定的时间戳并将其转换为JSON

我有以下代码:

package usages

import (
    "fmt"
    "time"
)

type SpecialOffer struct {
    PublishedDate   jsonTime    `gorm:"column:publishing_date" json:"published_date"`
    ExpirationDate  jsonTime    `gorm:"column:expiration_date" json:"expiration_date"`
}

type jsonTime struct {
    time.Time
}

func (tt jsonTime) MarshalJSON() ([]byte, error) {
    jsonTime := fmt.Sprintf("\"%s\"", tt.Format("20060102"))
    return []byte(jsonTime), nil
}
当我这样运行它时,会出现以下错误:

sql: Scan error on column index 8, name "publishing_date": unsupported Scan, storing driver.Value type time.Time into type *usages.trvTime 
数据是错误的:

{"published_date":"00010101","expiration_date":"00010101"}
{"published_date":"2020-03-12T00:00:00Z","expiration_date":"2020-06-12T00:00:00Z"}
如果我将
SpecialOffer
结构更改为使用
time.time
,它将返回正确的,但格式显然是错误的:

{"published_date":"00010101","expiration_date":"00010101"}
{"published_date":"2020-03-12T00:00:00Z","expiration_date":"2020-06-12T00:00:00Z"}
我做错了什么?

您应该实现和接口

大概是这样的:

func (j *jsonTime) Scan(src interface{}) error {
    if t, ok := src.(time.Time); ok {
        j.Time = t
    }
    return nil
}

func (j jsonTime) Value() (driver.Value, error) {
    return j.Time, nil
}

这是必要的,因为
gorm
和其他一些go-ORMs(如果不是全部的话)使用的
database/sql
包只为少数类型提供现成的支持

大多数支持的类型都是该语言的基本内置类型,如
string
int
bool
,等等。通过扩展,它还支持任何自定义的用户定义类型,其基础类型是上述基本类型之一,然后支持
[]字节
类型和相关的
sql.RawBytes
类型,最后还支持
time.time
类型

您可能希望向数据库写入或从数据库读取的任何其他类型都需要实现上述两个接口。
sql.Scanner
Scan
方法在将列的值解码为支持的类型之一后自动调用(这就是为什么需要针对
time.time
而不是针对
[]byte
键入assert)。
driver.Valuer
Value
方法会在驱动程序将其编码为对目标列有效的格式之前自动调用(这就是为什么您可以直接返回
time.time
,而不是让用户自己进行编码)

记住

type jsonTime struct {
    time.Time
}
甚至

type jsonTime time.Time

声明一个不等于
time.time的新类型,这就是为什么
数据库/sql
包没有提取它的原因。

非常感谢。你能解释一下为什么需要这样做吗?它是有效的,但对于Golang来说是非常新的,我想了解原因。@Albert我添加了一些上下文,希望能帮助您更好地理解原因。谢谢。非常感谢你的努力@mkopriva是否可以像基本内置类型一样支持底层类型为
time.time
的所有自定义类型?@Eklavya不可能。基本内置类型是“特殊”的,因为它们在
reflect
包(由
database/sql
使用)中有一个等价的表示,它是
reflect.Kind
类型的各种常量,可用于计算底层类型。例如,
string
具有种类
reflect.string
,而
type MyString string
也具有种类
reflect.string
等。