默认时间戳在不同的 mysql 表中具有不同的时区

Default timestamps are of different time zone in different mysql tables

服务器版本 & gorm 包:

❯ docker exec -it mysql mysqld --version
mysqld  Ver 5.7.29 for Linux on x86_64 (MySQL Community Server (GPL))

❯ docker exec -it mysql mysql --version
mysql  Ver 14.14 Distrib 5.7.29, for Linux (x86_64) using  EditLine wrapper
import "github.com/jinzhu/gorm"

两个table:

mysql> desc t1;
+------------+-------------------+------+-----+-------------------+----------------+
| Field      | Type              | Null | Key | Default           | Extra          |
+------------+-------------------+------+-----+-------------------+----------------+
| ...        |                   |      |     |                   |                |
| created_at | timestamp         | YES  |     | CURRENT_TIMESTAMP |                |
+------------+-------------------+------+-----+-------------------+----------------+

mysql> desc t2;
+----------------+------------------+------+-----+-------------------+----------------+
| Field          | Type             | Null | Key | Default           | Extra          |
+----------------+------------------+------+-----+-------------------+----------------+
| ...            | ...              | ...  | ... | ...               | ...            |
| initiated_at   | timestamp        | YES  |     | CURRENT_TIMESTAMP |                |
+----------------+------------------+------+-----+-------------------+----------------+

定义stuct{}时的gorm模型如下:

// t1
type T1 struct {
    ID uint `gorm:"primary_key"`
    // others are here
    // ...

    CreatedAt  time.Time `gorm:"timestamp;default:CURRENT_TIMESTAMP" json:"created_at" form:"created_at" query:"created_at" sql:"DEFAULT:current_timestamp"`
}

// t2 ...
type T2 struct {
    ID uint `gorm:"primary_key"`
    // others are here
    // ...
    InitiatedAt  time.Time `gorm:"timestamp;default:CURRENT_TIMESTAMP" json:"initiated_at" form:"initiated_at" query:"initiated_at" sql:"DEFAULT:current_timestamp"`
}

插入未初始化的时间戳

dbSource := fmt.Sprintf(
    "%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local",
    cnf.Username,
    cnf.Password,
    cnf.Host,
    cnf.Port,
    cnf.DBName,
)

db, err := gorm.Open("mysql", dbSource)
if err != nil {
    logrus.Warn("Got error when connect database:", err)
    return err
}

t1 := T1{} // created_at is not set
t2 := T2{} // initiated_at is not set

tx := db.Begin()
defer func() {
    if r := recover(); r != nil {
        logrus.Error("Rolling back")
        tx.Rollback()
    }
}()
// If failed to begin transaction
if err := tx.Error; err != nil {
    return err
}

if err := db.Create(&t1).Error; err != nil {
    logrus.Warn(err)
    // rollback the transaction in case of error
    tx.Rollback()
    return derror.ErrorBadRequest
}
if err := db.Create(&t2).Error; err != nil {
    logrus.Warn(err)
    // rollback the transaction in case of error
    tx.Rollback()
    return derror.ErrorBadRequest
}

// Or commit the transaction
if err := tx.Commit().Error; err != nil {
    logrus.Warn(err)
    // rollback the transaction in case of error
    tx.Rollback()
    return derror.ErrorBadRequest
}

我看到的,什么时候select查询

mysql> select * from t1;
+-----+---------------------+
| ... | created_at          |
+-----+---------------------+
| ... | 2020-03-24 02:38:26 |
+-----+---------------------+

mysql> select * from t2;
+-----+---------------------+
| ... | initiated_at        |
+-----+---------------------+
| ... | 2020-03-23 20:38:26 |
+-----+---------------------+

期望:

请注意,我在 asia/dhaka(+06:00) 区域。而t1table的created_at时间就是我所在地区的BST当前时间。另一方面,t2table的initiated_at时间是UTC当前时间。

但我希望这两个时间相同(我指的是 UTC 或 BST)。

想知道:

在 Table t1 中,CreatedAtGorm 在本地时区设置,因为您使用 loc=Local.

参考:https://github.com/jinzhu/gorm/blob/master/callback_create.go#L32

并且在 Table t2 中,initiated_at 不是由 Gorm 设置的,它是由 Mysql 设置的,因为您使用默认值 CURRENT_TIMESTAMPMySql.

解法:

您可以在连接中使用 loc=UTCGorm 时区更改为 UTC。

您可以将本地时区设置为 Mysql 时区。 请注意,设置 time.Time 值的位置但不会更改 MySQL 的 time_zone setting.For 看到 time_zone 系统变量,也可以设置为DSN 参数。

参考:https://github.com/go-sql-driver/mysql#loc