修复跨库迁移后数据库时区解释不一致
Some checks are pending
Security Checks / security (push) Waiting to run

This commit is contained in:
smail 2026-10-04 02:57:28 +08:00
parent 99b98c88fd
commit 2248190535
2 changed files with 57 additions and 6 deletions

View File

@ -35,12 +35,8 @@ func Init(version string) error {
}
switch cfg.DbType {
case "mysql":
Instance, err = xorm.NewEngine("mysql", dsn)
case "sqlite":
Instance, err = xorm.NewEngine("sqlite", dsn)
case "postgres":
Instance, err = xorm.NewEngine("postgres", dsn)
case "mysql", "sqlite", "postgres":
Instance, err = newDatabaseEngine(cfg.DbType, dsn)
default:
return errors.New("Database Type Error!")
}
@ -110,6 +106,17 @@ func Init(version string) error {
return nil
}
func newDatabaseEngine(driver, dsn string) (*xorm.Engine, error) {
engine, err := xorm.NewEngine(driver, dsn)
if err != nil {
return nil, err
}
// 数据库存储与跨库迁移统一使用 UTC,读取后仍按应用时区展示。
// 不得把驱动返回的 UTC 时间按本地时区重新解释。
engine.SetTZDatabase(time.UTC)
return engine, nil
}
func WithContext(ctx *requestcontext.Context, sql string) string {
if ctx != nil {
logId := ctx.GetValue(requestcontext.LogID)

View File

@ -4,11 +4,55 @@ import (
"context"
"path/filepath"
"testing"
"time"
"git.pcux.cn/xuans/Smail/config"
"git.pcux.cn/xuans/Smail/db/migration"
"xorm.io/xorm/convert"
)
func TestDatabaseEnginePreservesMigratedUTCTime(t *testing.T) {
previousLocal := time.Local
time.Local = time.FixedZone("CST", 8*3600)
t.Cleanup(func() { time.Local = previousLocal })
for _, tc := range []struct {
driver string
dsn string
}{
{"sqlite", ":memory:"},
{"mysql", "smail@tcp(127.0.0.1:3306)/smail?parseTime=true"},
{"postgres", "host=127.0.0.1 user=smail dbname=smail sslmode=require"},
} {
t.Run(tc.driver, func(t *testing.T) {
engine, err := newDatabaseEngine(tc.driver, tc.dsn)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = engine.Close() })
if engine.GetTZDatabase() != time.UTC {
t.Fatalf("database timezone = %v, want UTC", engine.GetTZDatabase())
}
if engine.GetTZLocation() != time.Local {
t.Fatalf("display timezone = %v, want CST", engine.GetTZLocation())
}
want := time.Date(2026, 10, 3, 16, 56, 0, 0, time.UTC)
for _, value := range []any{want, "2026-10-03 16:56:00"} {
got, err := convert.AsTime(value, engine.GetTZDatabase(), engine.GetTZLocation())
if err != nil {
t.Fatal(err)
}
if got == nil || !got.Equal(want) {
t.Fatalf("converted time = %v, want instant %v", got, want)
}
if display := got.Format("2006-01-02 15:04:05"); display != "2026-10-04 00:56:00" {
t.Fatalf("display time = %s, want 2026-10-04 00:56:00", display)
}
}
})
}
}
func TestInitAppliesSchemaMigration(t *testing.T) {
databasePath := filepath.Join(t.TempDir(), "init.db")
previousConfig := config.Instance