关于 golang mysql 驱动 parseTime 的设计感觉有点奇怪 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
javalaw2010
V2EX    Go 编程语言

关于 golang mysql 驱动 parseTime 的设计感觉有点奇怪

  •  
  •   javalaw2010 22 天前 1559 次点击

    众所周知:parseTime 参数为 true 时,驱动会将 date/datetime/timestamp 类型根据 loc 时区解析成 time.Time 类型之后再返回。

    timestamp 类型字段没什么疑议,本身底层是一个 unix 时间戳。

    但是 date/datetime 类型本身只是一种时间表达方式。假设我有两条数据,虽然可能存储的都是“2025-09-19 14:44:00”的时间,但是业务层面,有可能一条的时区是 Asia/Shanghai, 另一条的时区是 Asia/Tokoyo ,我认为这个地方更适合交由业务层自行处理啊,如果用上 time.Time ,时区就会非常混乱,这里面会涉及到存储时的时区/数据库时区/服务器时区/DSN 中的 LOC 时区,非常折磨人啊。驱动也不提供单独解析 timestamp 类型的能力。

    9 条回复    2025-09-21 21:56:45 +08:00
    Ketteiron
        1
    Ketteiron  
       22 天前   1
    别瞎搞这些有的没的。
    服务器和数据库统一使用 UTC ,时间戳展示交给客户端。
    datetime 没有时区,因此不建议用于有时区要求的场景。
    如果想用 datetime 处理,设计接口时要额外传输时区信息,然后服务端转换成 UTC 时间,请求数据时转换成 Unix 让客户端自行处理。
    当然这里存在一个问题,服务端完全丢失了该条数据的时区信息,如果业务有需要,再增加一个 timezone 字段。
    lysShub
        2
    lysShub  
       21 天前   1
    time.Time 带有时区的

    我司强制要求存 stamp, 非要存时区单独开个字段
    bbbblue
        3
    bbbblue  
       21 天前
    你想用的 timestamp 估计也会有问题。。。mysql 的 timestamp 是受到 session 的 timezone 影响的。。他虽然内部存时间戳 但是会根据 session 设置的 timezone 来处理它。。。

    go 不知道 js 和 java 都是 数据库驱动如果没正确设置时区 timestamp 就炸了
    java 侧是需要保证服务器时区和驱动时区能对上(可以把 session 改为服务器时区 或者 local+force)
    js 侧的 mysql2 是要填入 session 的时区

    直接存时间戳(我是指数字)得了


    这点不如 pg 有个 timestamptz 啥问题都没有
    canteon
        4
    canteon  
       20 天前
    @bbbblue 有,但是要自己写,go 那个转时区像个笑话。真的是只改时区,时间是一点都不给转,最终还不如自己写时间戳加秒数自己算
    javalaw2010
        5
    javalaw2010  
    OP
       20 天前   1
    @canteon 是会变的呀,你是不是记错了,刚写了个 Demo: https://goplay.tools/snippet/02X21QFZ8h1
    javalaw2010
        6
    javalaw2010  
    OP
       20 天前
    @bbbblue go 里面驱动解析的时区是根据 dsn 中的 loc 参数来的,也就是 session 的时区,golang 里面的 time.Time 对象是带时区的,所以不管 dsn 中的时区是啥,只需要应用层保证将 time.Time 转换为对应的时区就好了。
    Ketteiron
        7
    Ketteiron  
       20 天前   1
    @javalaw2010 #6
    "2025-09-19 14:44:00",有可能一条的时区是 Asia/Shanghai, 另一条的时区是 Asia/Tokoyo ,这是你的业务场景。
    驱动要将一个绝对时间转成有时区的相对时间,默认操作是以 ioc 参数进行转换。
    而你想的是在这里由业务层进行处理,第一条用 Asia/Shanghai ,第二条用 Asia/Tokoyo ,这样就能解析出正确的本地时间。

    但请思考这样一个场景:
    上海客户在下午 3 点创建订单,1 分钟后日本客户在下午 4 点 1 分创建订单,又 1 分钟后越南客户在下午 2 点 2 分创建订单。
    对服务器来说,如何能形成一个正确的时间线,3 点->4 点 1 分->2 点 2 分?
    在你这个场景下,已经无法区分了,因为所有时间被转换成当地时间,每个时区的订单都以自己为基准,失去了与其他区比较的中心坐标,如果要正确处理又得以一个标准(例如 UTC)统一转换,增加了复杂度。
    进一步,上海客户飞到了美国,此时你要用哪个时区给他解析呢?
    一旦驱动真的把解析时间的权利交给开发者,又要多出无数屎山。

    在这里我们要先统一共识,时区是什么?时区解决了什么问题?
    时区是绝对时间的相对偏移,与地理位置和政治有关,解决了如何将一个绝对时间在全球不同地方展示为当地时钟时间。
    服务器不应当关心时钟时间,或者只应当关心以一个时区作为始终标准的时钟时间,例如 UTC0 ,任何时间都要以此标准进行统一,丢弃原本时区信息。全世界任意一个地方要获得正确的时钟时间,应该依赖客户端,而非服务端,服务端要做的仅仅是统一标准。
    而原本时区信息在某些场景下是有意义的,Oracle 、PostgreSQL 等提供了 TIMESTAMP WITH TIME ZONE ,但是 MySQL 没有,只能自己存一个 zone 。

    >我认为这个地方更适合交由业务层自行处理啊
    因此可以回答这个问题,不同时区有不同的业务逻辑是合理的,但是自行处理时区时间是不合理的。

    服务器、数据库、驱动都会有这么一个时区配置,这是为了设定自身的基准,它们可以不一样并且是合理的,但是在分布式满天飞的当下,全部使用 UTC 是最简单最没有心智负担的做法,把各种转换问题全部扔掉。或者直接使用 BIGINT 。

    >时区就会非常混乱
    时区的混乱是历史遗留问题,也是开发者对历史遗留问题选择了错误的解决办法。
    甚至还有各种屎山手动加减时区,也是服了。
    javalaw2010
        8
    javalaw2010  
    OP
       20 天前
    @Ketteiron #7 你这样的场景下我们用的自然是 timestamp 类型了,我们的业务场景比较特殊,要记录用户的睡眠时间,这种场景下不管是记录 datetime 还是 timestamp ,都得配合时区才有意义。
    Ketteiron
        9
    Ketteiron  
       20 天前
    @javalaw2010 #8 这里不能用 datetime ,跨夏令时那天会少一小时,只能是两个 timestamp ,相减是正确的。不过 timestamp 的问题是用户去了别的时区记录会不正常,比如临时去日本旅游几天,那么所有不在日本的时间都会往后推一小时,必须要一个单独的 timezone 字段。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     839 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 22ms UTC 20:45 PVG 04:45 LAX 13:45 JFK 16:45
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86