关于数据库时间字段的时区问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
MySQL 5.5 Community Server
MySQL 5.6 Community Server
Percona Configuration Wizard
XtraBackup 搭建主从复制
Great Sites on MySQL
Percona
MySQL Performance Blog
Severalnines
推荐管理工具
Sequel Pro
phpMyAdmin
推荐书目
MySQL Cookbook
MySQL 相关项目
MariaDB
Drizzle
参考文档
http://mysql-python.sourceforge.net/MySQLdb.html
simple2025
0D
V2EX    MySQL

关于数据库时间字段的时区问题

  •  
  •   simple2025 2020-01-30 21:20:07 +08:00 6963 次点击
    这是一个创建于 2146 天前的主题,其中的信息可能已经有所发展或是发生改变。

    大家数据库时区字段用的是 utc,还是本地,还是时间戳呢
    之前我都是用本地时间,但是曾经出过一次错,存了 utc 时间到数据库里面去了,导致我对本地时间有点怕怕的,而且存本地时间,好像需要更改服务器时区设置,好像是的
    但是使用 utc, 有点问题

    1. 渲染的时候需要加偏移(这只是麻烦点)
    2. 就是统计的问题了,如果是按天的统计表,那么这个统计表的day,那就是本地时间的了,这个样子有点郁闷呀 如果不使用统计表的方式,好像 sql 写起来会相当复杂呀!!
    28 条回复    2020-07-02 12:25:04 +08:00
    fuyufjh
        1
    fuyufjh  
       2020-01-30 21:36:01 +08:00   1
    大多数数据库都提供了两种列类型:自带时区和不带时区的时间戳,比如:
    MySQL:DATETIME (自带时区)和 TIMESTAMP (不带时区)
    PostgresQL:TIMESTAMP WITH TIME ZONE (自带时区)和 TIMESTAMP (不带时区)
    所谓自带时区,就是数据库不会帮你做额外的转换,你写入什么时间,读出来就是什么时间
    所谓不带时区,就是数据库实际上会保存 UTC 时间戳,写入的时候先按 Session 时区转成 UTC 时间,读出的时候再按 Session 时区转成当前时区的时间这些转换都是透明的
    总结一下,你的这个需求,应该用不带时区的时间戳作为列类型,然后一切就搞定了
    simple2025
        2
    simple2025  
    OP
       2020-01-30 21:37:46 +08:00
    @fuyufjh 使用 utc 的时候,统计的逻辑会复杂很多呀
    fuyufjh
        3
    fuyufjh  
       2020-01-30 21:38:30 +08:00
    @chenqh “这些转换都是透明的”
    simple2025
        4
    simple2025  
    OP
       2020-01-30 21:45:40 +08:00
    @fuyufjh 没有搞懂, 假如我想统计这个月每天的订单数目,这个天肯定是我本地时间的天呀
    noqwerty
        5
    noqwerty  
       2020-01-30 21:56:01 +08:00 via Android
    @chenqh UTC 转本地时间还嫌麻烦吗老哥…
    Hellert
        6
    Hellert  
       2020-01-30 22:02:11 +08:00 via Android
    @fuyufjh 说反了吧?
    Mithril
        7
    Mithril  
       2020-01-30 22:12:26 +08:00
    @chenqh 如果你觉得以后会支持前端跑在不同时区,比如从国外访问,那你数据库就存 UTC。
    查询的时候让前台给你传 UTC 时间。或者只存个 offset。
    一般这些 ORM 都可以给你做了,配置一下就好了。
    如果你这个产品从头到尾都不会有人在不同时区使用,那就直接本地时间也没问题。
    simple2025
        8
    simple2025  
    OP
       2020-01-30 22:12:35 +08:00
    @noqwerty 只是一点点麻烦而已,关键是统计的时候
    suotm
        9
    suotm  
       2020-01-30 22:23:09 +08:00
    存成 unix 时间戳
    simple2025
        10
    simple2025  
    OP
       2020-01-30 23:28:27 +08:00
    @suotm 那统计表的按天统计怎么办? 使用时间戳或者 utc,居然会导致数据库里面存在两种时区?
    simple2025
        11
    simple2025  
    OP
       2020-01-30 23:34:34 +08:00
    突然发现一个问题,v2ex 的东 8 区时间,好像差了几分钟
    simple2025
        12
    simple2025  
    OP
       2020-01-30 23:36:40 +08:00
    @chenqh 看错了
    DonaldY
        13
    DonaldY  
       2020-01-31 03:35:26 +08:00
    @fuyufjh 这里的数据库隐式转换,包括驱动吗?
    keepeye
        14
    keepeye  
       2020-01-31 09:18:32 +08:00   1
    客户端连接数据库之后,设置本次连接的时区,这样 timestamp 字段读写就能自动转换了
    SET time_zOne= timezone;
    optional
        15
    optional  
       2020-01-31 09:36:54 +08:00   1
    @chenqh 如果是 PG,设置客户端的连接时区, 所有 timestamp with time zone 都会自动按照设置的时区处理时间。
    bjking2014
        17
    bjking2014  
       2020-01-31 10:47:39 +08:00 via Android
    我们有澳洲,香港,英国的项目,都是用的 datetime 类型
    keepeye
        18
    keepeye  
       2020-01-31 11:03:34 +08:00
    @chenqh 不太明白你纠结的点在哪里,如果是不知道怎么聚合查询的话,可以这样写 where DATE(created_at) = 'xxxx-xx-xx'
    eason1874
        19
    eason1874  
       2020-01-31 11:11:19 +08:00
    我直接存 int 只由代码处理时区。
    ellermister
        20
    ellermister  
       2020-01-31 11:36:26 +08:00 via Android
    我也比较好奇这个问题,已经好久没有用时间类型了,一直是 int 存储。
    optional
        21
    optional  
       2020-01-31 11:47:02 +08:00
    @keepeye 他纠结的问题就在这里,如果 created_at 不带时区的话,不能按照 local date 的方式统计。
    keepeye
        22
    keepeye  
       2020-01-31 12:48:52 +08:00
    @optional 还是没明白,连接的时候指定下本地时区,查询的时候数据库会自动将 created_at 转换成本地时区
    keepeye
        23
    keepeye  
       2020-01-31 12:50:57 +08:00
    不信就做个试验吧,可能很多人还不理解 connection 可以设置时区

    mysql> select created_at from users limit 1;
    +---------------------+
    | created_at |
    +---------------------+
    | 2019-03-01 02:14:53 |
    +---------------------+
    1 row in set (0.00 sec)

    mysql> set time_zOne='-8:00';
    Query OK, 0 rows affected (0.00 sec)

    mysql> select created_at from users limit 1;
    +---------------------+
    | created_at |
    +---------------------+
    | 2019-02-28 10:14:53 |
    +---------------------+
    1 row in set (0.00 sec)

    mysql> select date(created_at) from users limit 1;
    +------------------+
    | date(created_at) |
    +------------------+
    | 2019-02-28 |
    +------------------+
    1 row in set (0.00 sec)
    optional
        24
    optional  
       2020-01-31 12:58:07 +08:00
    @keepeye 我也是这个意思。
    simple2025
        25
    simple2025  
    OP
       2020-01-31 13:15:00 +08:00
    @keepeye 之前都不知知道 connection 可以设置时区,但是我想了一下,有一个问题,使用了带时区的 connection,insert 或者 update 的时候, 时间必须是本地时间?
    keepeye
        26
    keepeye  
       2020-01-31 13:21:45 +08:00
    @chenqh 对,mysql 会根据 connection 时区,将你本地写的值转换为 utc 存储,你只要设置好你本地和连接的时区就行了,数据转换对你来说是透明的
    simple2025
        27
    simple2025  
    OP
       2020-01-31 14:15:56 +08:00
    @keepeye 这个样子好复杂呀,假如一步出错,估计要查好久,算了,以后我还是用 timestamp 吧
    lialzm
        28
    lialzm  
       2020-07-02 12:25:04 +08:00
    @optional 麻烦问下 postgre 怎么在连接上设置时区我查到的都是修改 jvm 的参数
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5663 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 45ms UTC 03:10 PVG 11:10 LAX 19:10 JFK 22:10
    Do have faith in what you're doing.
    ubao msn 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