V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
v2exblog
V2EX  ›  程序员

2021 年了,数据存时间是用 utc 还是本地时间?

  •  
  •   v2exblog · 100 天前 · 8262 次点击
    这是一个创建于 100 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本来自己打算用 UTC 存,结果手欠百度了一下,结果发现用什么存储的都有。 现在乱了,不知道怎么存了,求大佬帮忙打醒

    第 1 条附言  ·  99 天前
    谢谢各位!方案来了,全都存!存一个本地时间的存 datetime,bigint,string 各一个,
    UTC 存 datetime,bigint,string 各一个,一共存 6 种。希望做完这个项目不会被开除
    第 2 条附言  ·  99 天前
    哈哈哈哈哈不好意思各位,忘记说需求了,需求是有各个国家媒体的账单需要抓,然后每个账单的时间时区都不一样,最后需要按照某个维度汇总账单
    89 条回复    2021-07-22 13:01:14 +08:00
    ss098
        1
    ss098   100 天前   ❤️ 5
    UTC,客户端自行根据本地时间格式化。
    richangfan
        2
    richangfan   100 天前
    当然是服务器本地时间了,转换多麻烦,又没有国外用户
    Jirajine
        3
    Jirajine   100 天前 via Android   ❤️ 2
    当然是 UTC,要不然服务器时区一变(更换机房、新安装的系统没有修改等),全都乱套。
    dqzcwxb
        4
    dqzcwxb   100 天前   ❤️ 2
    偷懒的结果就是付出更多
    zjyl1994
        5
    zjyl1994   100 天前
    时间戳最没有歧义了,而且到处都可以格式化
    tabris17
        6
    tabris17   100 天前
    如果取值范围不大的话,时间戳最好了
    dynastysea
        7
    dynastysea   100 天前
    如果没有国外用户的话直接时间戳啊,搞 UTC 这些干啥。。时间戳有什么问题?
    ytmsdy
        8
    ytmsdy   100 天前
    后台存储 UTC,API 输出时输出时间戳。这样前端可以用用户的时区来显示具体时间
    CEBBCAT
        9
    CEBBCAT   100 天前
    时间戳,UNSIGNED BIGINT
    labulaka521
        10
    labulaka521   100 天前
    存时间戳 然后再把用户的时区存储起来
    wunonglin
        11
    wunonglin   100 天前
    干吗不用时间戳
    snail00
        12
    snail00   100 天前
    从数据库到后台服务全部统一 UTC+8
    hackersli
        13
    hackersli   100 天前
    时间戳吧,怎么转换都可以哇
    clf
        14
    clf   100 天前
    时间戳是最方便的。无论从数据库的查询效率来说,还是不同代码的通用性来说,时间戳都很好用。
    weizhen199
        15
    weizhen199   100 天前
    @dqzcwxb 付出更多可以弄更多的改造项目 /doge
    bthulu
        16
    bthulu   99 天前
    @lychs1998 时间戳是啥, mysql 的 datetime 类型是时间戳么
    clf
        17
    clf   99 天前
    @bthulu #17 bigint 类型,对应 Java 的 Long 类型。就是一串数字,从 UTC 1970 年 1 月 1 日 0 时 0 分 0 秒开始到现在的毫秒数。
    datetime 的查询效率是低于 bigint 的。
    Aruforce
        18
    Aruforce   99 天前
    @bthulu timestamp
    lfzyx
        19
    lfzyx   99 天前
    时间戳是 Epoch time
    rrfeng
        20
    rrfeng   99 天前
    当然存 timestamp

    每次遇到人时间 /时区搞不清楚的时候就很恼火。
    Cy1
        21
    Cy1   99 天前
    直接时间戳,各端根据时区自己格式化显示。
    cmdOptionKana
        22
    cmdOptionKana   99 天前   ❤️ 10
    看来关心时区问题的人不多呀,一大堆说时间戳……

    时间戳也分 “UTC” 时间戳和 “本地时间” 时间戳的好吗。
    BenX
        23
    BenX   99 天前
    UTC 秒数存下来,至于使用端的逻辑,看那一层处理了。 时间戳,跨时区不是自找麻烦
    libook
        24
    libook   99 天前
    看需求。

    如果你有个强大的数据库,那么可能怎么存时间无所谓。
    如果数据库不够强的话:

    如果你的服务只在一个时区开展的话,用本地时间记录可以方便数据的统计分析;

    如果希望跨时区的话就最好用 UTC ;

    用 ISODate 格式的话方便于根据日期查询;

    用时间戳格式便于进行数学计算;

    ……

    没有银弹。
    chenqh
        25
    chenqh   99 天前
    @CEBBCAT biginit 应该就够了吧, unsigned bigint?
    Yut
        26
    Yut   99 天前 via Android
    那肯定是 Unix 时间啊,存其他的都有可能要转两道
    tooya
        27
    tooya   99 天前
    @libook 直接都存,空间换时间(
    gtexpanse
        28
    gtexpanse   99 天前   ❤️ 1
    @cmdOptionKana #23 时间戳本身是没有时区概念的,只是他要基于 UTC1970 年这个基准而产生。
    使用时间戳来交互的方便之处在于,给出一个时间戳,不论你处于哪个时区,这个时间戳表示的时间点基准点的秒数都是相同的,也就是说时间的长度是固定的,但你拿时间戳想转换为“时间”的时候是必须要带入时区概念的——可以想象成尺子的长度是固定的,但是想看最终的读数必须要带入时区。
    qiayue
        29
    qiayue   99 天前   ❤️ 7
    @cmdOptionKana 时间戳是唯一的,不存在 UTC 时间戳还是本地时间时间戳。
    时间戳的定义式从 1970 年 1 月 1 日零点到现在经过的秒数。

    时间戳可以格式化为各地时间,如时间戳 0 值,你格式化为 UTC 时间,就是 1970 年 1 月 1 日 0 点,你格式化为北京时间,就是 1970 年 1 月 1 日 8 点。
    mxT52CRuqR6o5
        30
    mxT52CRuqR6o5   99 天前
    @cmdOptionKana 时间戳没有时区的,时间戳转为年月日是需要考虑时区
    SuperMild
        31
    SuperMild   99 天前   ❤️ 1
    @gtexpanse 我没说清楚,我本来想说就算用时间戳,也有 “直接用本地时间转时间戳” 与 “先转 UTC±00:00 再转时间戳” 两种做法。

    因为,如果每个客户端都先转 UTC±00:00, 按这个统一转时间戳,就能兼顾时区了。

    按我理解,楼主主要想问的是要不要处理时区,而回答 “用时间戳” 是回答不了 “要不要处理时区” 这个问题的,因为用时间戳既可以处理时区(方法是统一转 UTC±00:00 ),也可以不处理时区。
    crclz
        32
    crclz   99 天前
    首先,存到数据库里面的东西都要标准化,所以统一使用 UTC 时间。

    建议统一使用 int64 UTC milliseconds. 当然 int64 UTC seconds 也行,只不过都是 int64,不会省空间的。

    还有就是要注意,避免在 ORM 的实体上面使用语言自带的日期类型,例如 C#的 DateTime 、DateTimeOffset,例如 Java 的 Datetime 。虽然看起来方便,但是最终会付出额外的成本。

    keep it simple and stupid. 这虽然笨了点,但是却能够避免很多问题,并且别人也更加容易看懂你的代码。
    cmdOptionKana
        33
    cmdOptionKana   99 天前
    @gtexpanse
    @qiayue
    @mxT52CRuqR6o5 怪我没说清楚,具体请看 #32 (刚刚不小心用小号 SuperMild 回复了)
    tokyo2021
        34
    tokyo2021   99 天前   ❤️ 5
    1 看了前面很多,感觉有的也没理解啥是时间戳的概念呀, 我一直做海外游戏后端,稍微了解一点。
    时间戳 故名思义 表示戳记, 记录 1 个事件发生时的时间戳记
    举个例子: 当抵达上海的入境海关,给你护照上盖个时间戳,这是中国 cst 时间,时间格式是 ISO 那个 8644(好像是)格式, 抵达东京的海关入境时护照上面当然也会盖一个时间戳,这是东京时间,时间格式又是 1 种,他们的时间格式。
    你手机拍的照片, 同时也会存储拍照时的时间戳记,
    那计算机通常采用 unix timestamp 存储时间戳记。 一般是从 1970 年 1 月 1 日 0 时至今的秒数。 为啥 1970 年呢, 应该是 unix 系统就是 1970 年正式发布诞生,选择就从 1970 年开始记吧。UTC 世界协调时,啥原子能机构授时的机构发布,严谨的来说不要在 UTC 上面表示+- 时区,UTC 就是世界协调时。 一般+- 是 GMT +1, GMT -2,本地时间和 GMT 的偏差,PST,PDT,和 GMT 时间做转换,还有海洋时间等等

    2 觉得如果是 mysql 数据库,最好使用 datetime 格式, 做时区存储 (公元 0000 到 9999 年时间),SQL 查询(自带丰富的时间函数), 转换(天数加减)非常的方便。mysql 8.0.19 版本以来,支持插入的时间可以带上偏移的参数,支持多个时区的数据插入到同 1 个数据库,这样始终存储的是同 1 个时区的时间。

    3 觉得时间特别容易引起 bug, 当年 iPhone 就因为时间存储问题,变成砖了~
    lix7
        35
    lix7   99 天前
    永远都存毫秒级时间戳
    SingeeKing
        36
    SingeeKing   99 天前 via iPhone
    @SuperMild 先转 UTC0 的唯一「好处」是浪费了点时间…
    oooooooooooo
        37
    oooooooooooo   99 天前 via Android
    @cmdOptionKana
    @SuperMild

    顶级理解
    ngn999
        38
    ngn999   99 天前
    我理解是应该存下时刻, 展示时, 把时刻转到相应的时区就好了.
    akira
        39
    akira   99 天前
    看你的用户群体
    cmdOptionKana
        40
    cmdOptionKana   99 天前
    @SingeeKing
    @oooooooooooo 是我理解错了,感谢指正!
    paulw54jrn
        41
    paulw54jrn   99 天前 via Android
    Epoch 或者 UTC iso8601
    realradiolover
        42
    realradiolover   99 天前   ❤️ 8
    UNIX 时间戳是绝对的。其度量基准为:从伦敦时间 1970 年 1 月 1 日 0 时开始,到此刻的秒数。

    在某一时刻,全球不同地区时区不同,因此钟表时间也不相同(“时差”的来源),但 UNIX 时间戳是一致的。e.g.: 此刻,是北京时间 23:08:00,伦敦时间 15:08:00,美国东部时间 11:08:00,但此刻三个地方的 UNIX 时间戳都是 1626188880 。

    同样道理,你获得此刻的 UNIX 时间戳,在全球不同时区,翻译得到的时间也是不同的;几乎所有的操作系统都有“区域,语言”之类的配置项,就是为了根据你的设备所在的时区,来翻译出“合适”的时间。e.g.:手机的“时钟”APP 通过 ntp 授时服务获得此刻的 UNIX 时间戳 1626188880,然后检查手机系统配置的“区域”,如果此刻你在上海,那么时钟显示“23:08:00”;此刻,你在夏威夷的同学,他的手机时钟 APP 也得到了同样的 1626188880,但他的系统区域设置是夏威夷,那么时钟将显示太平洋时间“05:08:00”

    由此可见,各国日常生活所使用的时间是不过是表象,是相对的。这是为了照顾人们的生活习惯,午夜一定是 0 点,正午一定是 12 点。因此全球需要一个绝对的基准,一般用 UTC 来度量,计算机科学则使用 unix timestamp.


    PS:基于北京时间的时间戳,本身就是一个伪命题。时间戳只有一个全球的绝对的。早期照片文件 EXIF 信息就忽略了这一点,只存了文本而没有时区。造成时间转换的混乱
    smallthing
        43
    smallthing   99 天前
    @cmdOptionKana 所谓本地世界的时间戳 就是一个错误的时间戳罢了。
    cszchen
        44
    cszchen   99 天前 via iPhone   ❤️ 3
    mysql 用 timestamp pgsql 用 timestamptz,都带有时区,根据客户端时区转换
    acmore
        45
    acmore   99 天前
    把时区带进数据库中给人的感觉就像把前端样式存在数据库了一样。
    很多时候没啥不行,说不定还很好用,但是让人浑身不自在。
    jupiter157
        46
    jupiter157   99 天前 via iPhone
    时间戳是强制换算到 utc0 的,和楼主存 utc0 时间有差别吗?前者是毫秒,对机器友好,后者所见即所得,对人类友好。反正别存本地时间,如果实在必须,可以存成字符串后面永远带着时区的尾巴。
    jupiter157
        47
    jupiter157   99 天前   ❤️ 2
    楼主存 6 个,是下下策,原因有三。1 ) 5 个信息冗余,换来的优点是可以节省转换时间,调用可以没有格式要求; 2 )时间转换效率是会随着硬件和软件提升不断改善的,节省的时间会越来越少; 3 )冗余的数据会越来越多,如果有天想删了,发现不同的程序调用的格式都不一样。
    qfdk
        48
    qfdk   99 天前 via iPhone
    ISO8601 然后前端用 dayjs 这样的库来显示
    ericls
        49
    ericls   99 天前 via iPhone
    存未来的时间只能用 string
    sutra
        50
    sutra   99 天前
    当你使用本地时间存储时,需要考虑时区、夏令时。
    bxb100
        51
    bxb100   99 天前
    只要存储的信息里面包含(隐式 /显式)时区信息, 那么最终的展示应该根据 local zone 来计算, 不要预先考虑 DST/WT/ST, 最终转换使用工具类即可
    Mithril
        52
    Mithril   99 天前
    只要你不想知道这数据是从哪个时区生成的,那你可以直接存 UTC 或者时间戳。
    否则直接 ISO
    liuidetmks
        53
    liuidetmks   99 天前
    @cmdOptionKana 时间戳就是格林威治时间,各个时区都是一样的吧?
    cmdOptionKana
        54
    cmdOptionKana   99 天前
    @liuidetmks 是一样的,我理解错了。幸好参与了讨论,不然我都没发现自己错误(因为我的做法也不会导致结果出错,所以靠自己很难发现)。
    Cbdy
        55
    Cbdy   99 天前 via Android
    timestamptz 不好吗?
    p1gd0g
        56
    p1gd0g   99 天前
    看到有人说时间戳加时区的,忍不住说两句。
    我们做海外手游的,客户端曾经因为时间戳加了时区导致时间戳结果为负数,直接闪退。
    SilentDepth
        57
    SilentDepth   99 天前   ❤️ 1
    完全没想到楼主最终选择的方案是全都存,而且存 6 种……

    存 UTC 就得了,或者存带时区的 ISO8601 (取决于是否需要保留初始时区信息)。想不到有什么问题是解决不了的。
    egfegdfr
        58
    egfegdfr   99 天前
    存时间戳的 不考虑可读性吗? 每次查问题,或者是直接在数据库里面查数据的时候 都需要 format 一下,不累吗
    直接时间格式不香吗, 能后时区问题的话,可以存 utc 时间,能后根据时区转换
    falcon05
        59
    falcon05   99 天前 via iPhone   ❤️ 1
    WordPress 的 posts 表还真的是把 gmt 和本地时间都存了一份。
    Ariver
        60
    Ariver   99 天前
    建议对这个概念不太清楚的把楼上回复仔细看完。
    时区这个概念对于稍微有点经验的开发都是必须掌握的。
    ikas
        61
    ikas   99 天前
    用 utc..用 db 原生时间类型..db 默认时区也配置为 utc 时区...
    现在比如 elasticsearch 都是默认如此,并且完全不提供给你修改默认时区的机会..
    mcluyu
        62
    mcluyu   99 天前
    哈哈哈。。想不到啊想不到,V 站这么多人连时间戳都搞不清。。
    Torpedo
        63
    Torpedo   99 天前
    说到时间,想起和 php 后端对的时候,都是时间戳。和 java 后端就是各种时间格式化后的字符串。。。
    imnpc
        64
    imnpc   99 天前
    1.针对单一地区的 ,例如只有 国内 直接时间戳就可以 然后程序处理好 GMT +8 输出
    2.针对多个国家 /地区 /时区的 一律 UTC 存入 然后根据用户所在地区输出准确时间
    7v9TEc53
        65
    7v9TEc53   99 天前
    @egfegdfr from_unixtime()
    NoDocCat
        66
    NoDocCat   99 天前
    @p1gd0g 说明你们有和 Apple 一样的技术水平 U•ェ•*U
    Dragonphy
        67
    Dragonphy   99 天前   ❤️ 1
    存 UTC 还是 UTC+8 根本不是问题,问题是部署的容器时间都是 UTC 时间,每次看日志都要自动+8😂
    Lemeng
        68
    Lemeng   99 天前
    需求是什么
    v2exblog
        69
    v2exblog   99 天前
    @Lemeng 需求是有各个国家的账单需要抓,然后每个账单的时间时区都不一样
    winglight2016
        70
    winglight2016   99 天前
    有跨时区的需求那么必须两个都存,utc 统一核算,本地时间客户端使用,毕竟一个用户也许会有不同时区的账单呢?
    waterb
        71
    waterb   99 天前
    真希望时间戳能成为标准
    首先 UI 不会把所有用到时间的地方都统一格式
    其次我遇到的绝大部分后台也不会根据当前 UI 的格式给我字符串
    导致经常会有后台给我字符串 我要转成时间戳 再转成 UI 格式 是真的操蛋
    evilStart
        72
    evilStart   99 天前 via Android   ❤️ 3
    不是,这玩意儿从盘古开天开始就是存 UTC 时间的吧?

    楼上这么多说不存 UTC 时间而存时间戳的让我感觉进了北大青鸟培训班。你们说的时间戳是指 UNIX 时间戳吧?这本质上就是 UTC 时间的秒数。而且获得正确的时间戳的前提是代码里的 Date 对象时区要正确。所以为什么不直接存 UTC 时间?可读性还更高。
    julyclyde
        73
    julyclyde   99 天前
    @evilStart 你说的对
    GuuJiang
        74
    GuuJiang   99 天前 via iPhone
    @cmdOptionKana 居然还有另外 7 个人点赞,太可怕了,时间戳和时区没有任何关系!只有当把时间戳转换为人可读的时间时才涉及时区
    evilStart
        75
    evilStart   99 天前 via Android   ❤️ 2
    @evilStart UTC 时间不仅可读性更高,能够替代一切使用时间戳的场景,而且许多数据库都对 Date 类型有特殊的查询优化。比如你需要找到某年某月的所有记录,要是存时间戳你要怎么查?把月头月末的时间戳都算出来然后再查询?存 UTC 时间的话查询语句就很直观。

    数据库都提供给你日期类型不用,非要存时间戳那真是自找麻烦。
    muzuiget
        76
    muzuiget   99 天前
    我以为“时间”默认就是“Unix 时间戳”那个 32/64 的整数,想不到那么多人会带入时区的概念。

    程序内部各种储存通信计算一律“Unix 时间戳”,只有给用户交互那一层再转换成可读字符串格式。
    zxbutton
        77
    zxbutton   99 天前
    楼上很多太秀了,当然是存 UTC,根据客户端所在时区展示
    masterclock
        78
    masterclock   99 天前
    1 、时间戳,即 timestamp,只是个时间标签的概念,不涉及任何定义、实现、格式。
    2 、楼上一些人说的 “时间戳” 是 unix epoch ?这是个整数的秒数,扩展一下毫秒也行,也不涉及存储,也许有人要存成 36 进制数文本呢?
    3 、UTC 时间 是个时间的标准,不涉及表示、格式、存储。
    4 、有些数据库有 timestamp 、timestamptz 等格式,可以极度方便地存储、查询时间。
    5 、一般用 timestamptz,除非不是表示时间点。
    6 、pg 提供一堆函数来处理时间,比如 date_trunc 到日、周等。
    7 、有些数据库用 int64 、uint64 来存储时间,因为要精确到纳秒.
    egfegdfr
        79
    egfegdfr   99 天前   ❤️ 1
    @7v9TEc53 在查数据问题的时候,都是 习惯 select * from 的,如果是时间戳,需要手动 format, 还有,如果是客户端能直接连的话,都是直接打开的,sql 都不写
    szq8014
        80
    szq8014   99 天前
    直接 MySQL 存 timestamp 。
    什么,2038 年限制? 那不还剩下 16+年呢?
    但愿我做的项目能运行到那个时候。。
    TomatoYuyuko
        81
    TomatoYuyuko   99 天前
    数据这东西最终用途不就是用来展示的吗,对于前端来说当然是愿意拿时间戳了,最怕后端给一堆乱七八糟时间格式前端你还得转换一遍
    smallthing
        82
    smallthing   99 天前
    @egfegdfr 一看你就是那种自己爽的后端。应该是写 java 的
    ppphp
        83
    ppphp   98 天前
    打日志用本地时间,存数据库最好当然是用时间戳,正常人类存时间戳都是 unix epoch 的,没有任何歧义,数据库服务,服务数据库客户端(orm),宿主系统,客户端有一个地方处理时区处理不好,就很麻烦
    Digitalzz
        84
    Digitalzz   98 天前
    直接所有的服务器的时间都设置成 UTC 时间,存储自然是 UTC,然后根据需求在代码里加时区。
    jimmyismagic
        85
    jimmyismagic   98 天前
    @szq8014 2038,那是有符号整数
    egfegdfr
        86
    egfegdfr   98 天前
    @smallthing 前端 python java 都写过。刚开始工作的时候,团队中经常辩论用时间戳还是 Y M D 好,到现在公司各团队几乎是没人在讨论这个了 都是用的 年月日 时分秒 格式。
    julyclyde
        87
    julyclyde   98 天前
    即使“仅在”中国,也不是单一时区
    新中国成立的时候还继承了民国的五大时区制,90 年代还有过夏令时
    xuanbg
        88
    xuanbg   98 天前
    时间到底存什么?只要统一标准,存什么都行。
    smallthing
        89
    smallthing   91 天前
    @egfegdfr 那说明你们的 CTO 喜欢这个
    关于   ·   帮助文档   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3767 人在线   最高记录 5497   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 09:33 · PVG 17:33 · LAX 02:33 · JFK 05:33
    ♥ Do have faith in what you're doing.