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 · 2 天前 · 729 次点击

    众所周知: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 类型的能力。

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

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

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

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


    这点不如 pg 有个 timestamptz 啥问题都没有
    canteon
        4
    canteon  
       7 小时 47 分钟前
    @bbbblue 有,但是要自己写,go 那个转时区像个笑话。真的是只改时区,时间是一点都不给转,最终还不如自己写时间戳加秒数自己算
    javalaw2010
        5
    javalaw2010  
    OP
       6 小时 58 分钟前
    @canteon 是会变的呀,你是不是记错了,刚写了个 Demo: https://goplay.tools/snippet/02X21QFZ8h1
    javalaw2010
        6
    javalaw2010  
    OP
       6 小时 54 分钟前
    @bbbblue go 里面驱动解析的时区是根据 dsn 中的 loc 参数来的,也就是 session 的时区,golang 里面的 time.Time 对象是带时区的,所以不管 dsn 中的时区是啥,只需要应用层保证将 time.Time 转换为对应的时区就好了。
    Ketteiron
        7
    Ketteiron  
       35 分钟前
    @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 。

    >时区就会非常混乱
    时区的混乱是历史遗留问题,也是开发者对历史遗留问题选择了错误的解决办法。
    甚至还有各种屎山手动加减时区,也是服了。
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2666 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 20ms · UTC 08:35 · PVG 16:35 · LAX 01:35 · JFK 04:35
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.