3

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

 2 years ago
source link: https://www.v2ex.com/t/789255
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

V2EX  ›  程序员

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

  v2exblog · 1 天前 · 6205 次点击

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

第 1 条附言  ·  17 小时 16 分钟前

谢谢各位!方案来了,全都存!存一个本地时间的存 datetime,bigint,string 各一个,
UTC 存 datetime,bigint,string 各一个,一共存 6 种。希望做完这个项目不会被开除

第 2 条附言  ·  6 小时 10 分钟前

哈哈哈哈哈不好意思各位,忘记说需求了,需求是有各个国家媒体的账单需要抓,然后每个账单的时间时区都不一样,最后需要按照某个维度汇总账单
81 条回复    2021-07-14 14:24:42 +08:00

ss098

ss098   1 天前   ❤️ 5

UTC,客户端自行根据本地时间格式化。

richangfan

richangfan   1 天前

当然是服务器本地时间了,转换多麻烦,又没有国外用户

Jirajine

Jirajine   1 天前 via Android   ❤️ 1

当然是 UTC,要不然服务器时区一变(更换机房、新安装的系统没有修改等),全都乱套。

dqzcwxb

dqzcwxb   1 天前   ❤️ 2

偷懒的结果就是付出更多

zjyl1994

zjyl1994   1 天前

时间戳最没有歧义了,而且到处都可以格式化

tabris17

tabris17   1 天前

如果取值范围不大的话,时间戳最好了

dynastysea

dynastysea   1 天前

如果没有国外用户的话直接时间戳啊,搞 UTC 这些干啥。。时间戳有什么问题?

ytmsdy

ytmsdy   1 天前

后台存储 UTC,API 输出时输出时间戳。这样前端可以用用户的时区来显示具体时间

CEBBCAT

CEBBCAT   1 天前

时间戳,UNSIGNED BIGINT

labulaka521

labulaka521   1 天前

存时间戳 然后再把用户的时区存储起来

wunonglin

wunonglin   1 天前

干吗不用时间戳

snail00

snail00   1 天前

从数据库到后台服务全部统一 UTC+8

hackersli

hackersli   1 天前

时间戳吧,怎么转换都可以哇

lychs1998

lychs1998   1 天前

时间戳是最方便的。无论从数据库的查询效率来说,还是不同代码的通用性来说,时间戳都很好用。

weizhen199

weizhen199   1 天前

@dqzcwxb 付出更多可以弄更多的改造项目 /doge

bthulu

bthulu   23 小时 21 分钟前

@lychs1998 时间戳是啥, mysql 的 datetime 类型是时间戳么

lychs1998

lychs1998   23 小时 18 分钟前

@bthulu #17 bigint 类型,对应 Java 的 Long 类型。就是一串数字,从 UTC 1970 年 1 月 1 日 0 时 0 分 0 秒开始到现在的毫秒数。
datetime 的查询效率是低于 bigint 的。

Aruforce

Aruforce   23 小时 16 分钟前

@bthulu timestamp

lfzyx

lfzyx   23 小时 13 分钟前

时间戳是 Epoch time

rrfeng

rrfeng   23 小时 11 分钟前

当然存 timestamp

每次遇到人时间 /时区搞不清楚的时候就很恼火。

Cy1

Cy1   22 小时 52 分钟前

直接时间戳,各端根据时区自己格式化显示。

cmdOptionKana

cmdOptionKana   22 小时 29 分钟前   ❤️ 9

看来关心时区问题的人不多呀,一大堆说时间戳……

时间戳也分 “UTC” 时间戳和 “本地时间” 时间戳的好吗。

BenX

BenX   22 小时 22 分钟前

UTC 秒数存下来,至于使用端的逻辑,看那一层处理了。 时间戳,跨时区不是自找麻烦

libook

libook   22 小时 14 分钟前

看需求。

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

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

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

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

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

……

没有银弹。

chenqh

chenqh   22 小时 5 分钟前

@CEBBCAT biginit 应该就够了吧, unsigned bigint?

Yut

Yut   22 小时 0 分钟前 via Android

那肯定是 Unix 时间啊,存其他的都有可能要转两道

tooya

tooya   21 小时 58 分钟前

@libook 直接都存,空间换时间(

gtexpanse

gtexpanse   21 小时 52 分钟前   ❤️ 1

@cmdOptionKana #23 时间戳本身是没有时区概念的,只是他要基于 UTC1970 年这个基准而产生。
使用时间戳来交互的方便之处在于,给出一个时间戳,不论你处于哪个时区,这个时间戳表示的时间点基准点的秒数都是相同的,也就是说时间的长度是固定的,但你拿时间戳想转换为“时间”的时候是必须要带入时区概念的——可以想象成尺子的长度是固定的,但是想看最终的读数必须要带入时区。

qiayue

qiayue   21 小时 47 分钟前   ❤️ 4

@cmdOptionKana 时间戳是唯一的,不存在 UTC 时间戳还是本地时间时间戳。
时间戳的定义式从 1970 年 1 月 1 日零点到现在经过的秒数。

时间戳可以格式化为各地时间,如时间戳 0 值,你格式化为 UTC 时间,就是 1970 年 1 月 1 日 0 点,你格式化为北京时间,就是 1970 年 1 月 1 日 8 点。

mxT52CRuqR6o5

mxT52CRuqR6o5   21 小时 44 分钟前

@cmdOptionKana 时间戳没有时区的,时间戳转为年月日是需要考虑时区

SuperMild

SuperMild   21 小时 40 分钟前   ❤️ 1

@gtexpanse 我没说清楚,我本来想说就算用时间戳,也有 “直接用本地时间转时间戳” 与 “先转 UTC±00:00 再转时间戳” 两种做法。

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

按我理解,楼主主要想问的是要不要处理时区,而回答 “用时间戳” 是回答不了 “要不要处理时区” 这个问题的,因为用时间戳既可以处理时区(方法是统一转 UTC±00:00 ),也可以不处理时区。

crclz

crclz   21 小时 38 分钟前

首先,存到数据库里面的东西都要标准化,所以统一使用 UTC 时间。

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

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

keep it simple and stupid. 这虽然笨了点,但是却能够避免很多问题,并且别人也更加容易看懂你的代码。

cmdOptionKana

cmdOptionKana   21 小时 36 分钟前

@gtexpanse
@qiayue
@mxT52CRuqR6o5 怪我没说清楚,具体请看 #32 (刚刚不小心用小号 SuperMild 回复了)

tokyo2021

tokyo2021   21 小时 1 分钟前   ❤️ 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

lix7   20 小时 43 分钟前

永远都存毫秒级时间戳

SingeeKing

SingeeKing   20 小时 18 分钟前 via iPhone

@SuperMild 先转 UTC0 的唯一「好处」是浪费了点时间…

ngn999

ngn999   18 小时 50 分钟前

我理解是应该存下时刻, 展示时, 把时刻转到相应的时区就好了.

akira

akira   18 小时 45 分钟前

看你的用户群体

paulw54jrn

paulw54jrn   17 小时 54 分钟前 via Android

Epoch 或者 UTC iso8601

realradiolover

realradiolover   17 小时 21 分钟前   ❤️ 7

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

smallthing   17 小时 17 分钟前

@cmdOptionKana 所谓本地世界的时间戳 就是一个错误的时间戳罢了。

cszchen

cszchen   17 小时 8 分钟前 via iPhone   ❤️ 3

mysql 用 timestamp pgsql 用 timestamptz,都带有时区,根据客户端时区转换

acmore

acmore   16 小时 25 分钟前

把时区带进数据库中给人的感觉就像把前端样式存在数据库了一样。
很多时候没啥不行,说不定还很好用,但是让人浑身不自在。

jupiter157

jupiter157   13 小时 28 分钟前 via iPhone

时间戳是强制换算到 utc0 的,和楼主存 utc0 时间有差别吗?前者是毫秒,对机器友好,后者所见即所得,对人类友好。反正别存本地时间,如果实在必须,可以存成字符串后面永远带着时区的尾巴。

jupiter157

jupiter157   13 小时 14 分钟前   ❤️ 2

楼主存 6 个,是下下策,原因有三。1 ) 5 个信息冗余,换来的优点是可以节省转换时间,调用可以没有格式要求; 2 )时间转换效率是会随着硬件和软件提升不断改善的,节省的时间会越来越少; 3 )冗余的数据会越来越多,如果有天想删了,发现不同的程序调用的格式都不一样。

qfdk

qfdk   12 小时 36 分钟前 via iPhone

ISO8601 然后前端用 dayjs 这样的库来显示

ericls

ericls   12 小时 32 分钟前 via iPhone

存未来的时间只能用 string

sutra

sutra   8 小时 21 分钟前

当你使用本地时间存储时,需要考虑时区、夏令时。

bxb100

bxb100   8 小时 14 分钟前

只要存储的信息里面包含(隐式 /显式)时区信息, 那么最终的展示应该根据 local zone 来计算, 不要预先考虑 DST/WT/ST, 最终转换使用工具类即可

Mithril

Mithril   8 小时 9 分钟前

只要你不想知道这数据是从哪个时区生成的,那你可以直接存 UTC 或者时间戳。
否则直接 ISO

liuidetmks

liuidetmks   8 小时 6 分钟前

@cmdOptionKana 时间戳就是格林威治时间,各个时区都是一样的吧?

cmdOptionKana

cmdOptionKana   8 小时 0 分钟前

@liuidetmks 是一样的,我理解错了。幸好参与了讨论,不然我都没发现自己错误(因为我的做法也不会导致结果出错,所以靠自己很难发现)。

Cbdy

Cbdy   7 小时 57 分钟前 via Android

timestamptz 不好吗?

p1gd0g

p1gd0g   7 小时 52 分钟前

看到有人说时间戳加时区的,忍不住说两句。
我们做海外手游的,客户端曾经因为时间戳加了时区导致时间戳结果为负数,直接闪退。

SilentDepth

SilentDepth   7 小时 52 分钟前   ❤️ 1

完全没想到楼主最终选择的方案是全都存,而且存 6 种……

存 UTC 就得了,或者存带时区的 ISO8601 (取决于是否需要保留初始时区信息)。想不到有什么问题是解决不了的。

egfegdfr

egfegdfr   7 小时 47 分钟前

存时间戳的 不考虑可读性吗? 每次查问题,或者是直接在数据库里面查数据的时候 都需要 format 一下,不累吗
直接时间格式不香吗, 能后时区问题的话,可以存 utc 时间,能后根据时区转换

falcon05

falcon05   7 小时 44 分钟前 via iPhone   ❤️ 1

WordPress 的 posts 表还真的是把 gmt 和本地时间都存了一份。

Ariver

Ariver   7 小时 37 分钟前

建议对这个概念不太清楚的把楼上回复仔细看完。
时区这个概念对于稍微有点经验的开发都是必须掌握的。

ikas

ikas   7 小时 36 分钟前

用 utc..用 db 原生时间类型..db 默认时区也配置为 utc 时区...
现在比如 elasticsearch 都是默认如此,并且完全不提供给你修改默认时区的机会..

mcluyu

mcluyu   7 小时 28 分钟前

哈哈哈。。想不到啊想不到,V 站这么多人连时间戳都搞不清。。

Torpedo

Torpedo   6 小时 46 分钟前

说到时间,想起和 php 后端对的时候,都是时间戳。和 java 后端就是各种时间格式化后的字符串。。。

imnpc

imnpc   6 小时 39 分钟前

1.针对单一地区的 ,例如只有 国内 直接时间戳就可以 然后程序处理好 GMT +8 输出
2.针对多个国家 /地区 /时区的 一律 UTC 存入 然后根据用户所在地区输出准确时间

7v9TEc53

7v9TEc53   6 小时 36 分钟前

@egfegdfr from_unixtime()

NoDocCat

NoDocCat   6 小时 30 分钟前

@p1gd0g 说明你们有和 Apple 一样的技术水平 U•ェ•*U

Dragonphy

Dragonphy   6 小时 21 分钟前   ❤️ 1

存 UTC 还是 UTC+8 根本不是问题,问题是部署的容器时间都是 UTC 时间,每次看日志都要自动+8😂

Lemeng

Lemeng   6 小时 14 分钟前

需求是什么

v2exblog

v2exblog   6 小时 11 分钟前

@Lemeng 需求是有各个国家的账单需要抓,然后每个账单的时间时区都不一样

winglight2016

winglight2016   5 小时 15 分钟前

有跨时区的需求那么必须两个都存,utc 统一核算,本地时间客户端使用,毕竟一个用户也许会有不同时区的账单呢?

waterb

waterb   5 小时 7 分钟前

真希望时间戳能成为标准
首先 UI 不会把所有用到时间的地方都统一格式
其次我遇到的绝大部分后台也不会根据当前 UI 的格式给我字符串
导致经常会有后台给我字符串 我要转成时间戳 再转成 UI 格式 是真的操蛋

evilStart

evilStart   4 小时 55 分钟前 via Android   ❤️ 3

不是,这玩意儿从盘古开天开始就是存 UTC 时间的吧?

楼上这么多说不存 UTC 时间而存时间戳的让我感觉进了北大青鸟培训班。你们说的时间戳是指 UNIX 时间戳吧?这本质上就是 UTC 时间的秒数。而且获得正确的时间戳的前提是代码里的 Date 对象时区要正确。所以为什么不直接存 UTC 时间?可读性还更高。

GuuJiang

GuuJiang   4 小时 46 分钟前 via iPhone

@cmdOptionKana 居然还有另外 7 个人点赞,太可怕了,时间戳和时区没有任何关系!只有当把时间戳转换为人可读的时间时才涉及时区

evilStart

evilStart   4 小时 37 分钟前 via Android   ❤️ 1

@evilStart UTC 时间不仅可读性更高,能够替代一切使用时间戳的场景,而且许多数据库都对 Date 类型有特殊的查询优化。比如你需要找到某年某月的所有记录,要是存时间戳你要怎么查?把月头月末的时间戳都算出来然后再查询?存 UTC 时间的话查询语句就很直观。

数据库都提供给你日期类型不用,非要存时间戳那真是自找麻烦。

muzuiget

muzuiget   4 小时 6 分钟前

我以为“时间”默认就是“Unix 时间戳”那个 32/64 的整数,想不到那么多人会带入时区的概念。

程序内部各种储存通信计算一律“Unix 时间戳”,只有给用户交互那一层再转换成可读字符串格式。

zxbutton

zxbutton   3 小时 22 分钟前

楼上很多太秀了,当然是存 UTC,根据客户端所在时区展示

masterclock

masterclock   3 小时 19 分钟前

1 、时间戳,即 timestamp,只是个时间标签的概念,不涉及任何定义、实现、格式。
2 、楼上一些人说的 “时间戳” 是 unix epoch ?这是个整数的秒数,扩展一下毫秒也行,也不涉及存储,也许有人要存成 36 进制数文本呢?
3 、UTC 时间 是个时间的标准,不涉及表示、格式、存储。
4 、有些数据库有 timestamp 、timestamptz 等格式,可以极度方便地存储、查询时间。
5 、一般用 timestamptz,除非不是表示时间点。
6 、pg 提供一堆函数来处理时间,比如 date_trunc 到日、周等。
7 、有些数据库用 int64 、uint64 来存储时间,因为要精确到纳秒.

egfegdfr

egfegdfr   3 小时 9 分钟前   ❤️ 1

@7v9TEc53 在查数据问题的时候,都是 习惯 select * from 的,如果是时间戳,需要手动 format, 还有,如果是客户端能直接连的话,都是直接打开的,sql 都不写

szq8014

szq8014   3 小时 7 分钟前

直接 MySQL 存 timestamp 。
什么,2038 年限制? 那不还剩下 16+年呢?
但愿我做的项目能运行到那个时候。。

TomatoYuyuko

TomatoYuyuko   2 小时 34 分钟前

数据这东西最终用途不就是用来展示的吗,对于前端来说当然是愿意拿时间戳了,最怕后端给一堆乱七八糟时间格式前端你还得转换一遍

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK