4

比较好奇大家时间都是怎么存数据库的

 1 year ago
source link: https://www.v2ex.com/t/882628
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.
neoserver,ios ssh client

V2EX  ›  Node.js

比较好奇大家时间都是怎么存数据库的

  humbass · 13 小时 1 分钟前 · 2675 次点击

目前我的项目都是直接使用 UTC 时间戳存,但是时间戳是 13 位的,所以除 1000 后,以 int(11) 的方式存

主要是担心数据库有时区问题,造成时间有差异

第 1 条附言  ·  7 小时 2 分钟前

时间处理一直是一个头大的问题,本人是前端入手后端,后端也需要一把梭,因此在对于 Mysql 的掌握,仅仅到增删改、联合查询、改表等常规操作,无法深入做进一步优化,所以时间问题等于丢到 nodejs 层面来处理了。

感谢各位回帖。

49 条回复    2022-09-25 02:17:51 +08:00
Livid

Livid      12 小时 59 分钟前   ❤️ 2

V2EX 的所有时间也是这么存的——Unix Timestamp

而且因为时间戳不会出现负数,所以用的是 unsigned int
JamesR

JamesR      12 小时 57 分钟前

直接存整型。
jybox

jybox      12 小时 54 分钟前

大多数据库的时间类型,都是收到带时区的时间后,内部转换为不带时区的时间存储(一般是 UTC 时间戳),在客户端查询时再根据客户端的要求转换到指定的时区显示,所谓「时区问题」只是读写时数据库或客户端 library 没有正确配置。当然如果业务需要关注每一行数据的时区的话,可以单独用一个字段来存时区。
dqzcwxb

dqzcwxb      12 小时 51 分钟前

问个问题,数据库为什么要设计出 date 和 dateTime 数据类型?
thinkershare

thinkershare      12 小时 43 分钟前

@dqzcwxb 很多场景不需要 Time, 只需要日期,例如生日这种, 这样日期的有效范围可用很小, 然后是要更小的字节长度来存储。 而且一些语言中也有 Date 类型和 Time 不同的类型, 还有合起来的 DataTime 类型。
wxf666

wxf666      12 小时 40 分钟前

肯定存时间戳啊

时区问题这么复杂,你确定数据库真的都能处理好了?

万一以后中国又实行夏令时,你数据库咋处理。。
go522000

go522000      12 小时 22 分钟前

以前用 unsigned int ,后来新项目我一般都是用 datetime 类型。就单纯觉得在数据库工具中直接查看比较方便而已。
Akitora

Akitora      12 小时 20 分钟前 via Android

datetime ,方便查看
zilongzixue

zilongzixue      11 小时 59 分钟前

存 long 类型的时间戳,要用的时候加上时区
iseki

iseki      11 小时 51 分钟前   ❤️ 1

按 PostgreSQL FAQ 里的最佳实践,用 timestamp with time zone ,如果需要时区信息就单独开个字段存 IANA 时区数据库里的时区 ID
Aloento

Aloento      11 小时 51 分钟前

PG 自带时间类型,所以直接用内置 UTC 时间类型就行了
dswyzx

dswyzx      11 小时 40 分钟前

mongodb 这样的不支持 datetime,mysql 之流则支持 datetime 类型存储字段.
如果一个项目考虑跨时区,那么考虑时区转换问题,如果一个项目等到删库都没变过 utc+8:00,还是在 mysql 这种有 datetime 类型的数据库里,天天对着一长串时间戳排查 db 数据的时候那就只能开着个网页专门转换时间戳了.毕竟人脑识别 datetime 比 long 强
leonshaw

leonshaw      10 小时 25 分钟前

以前用 Hibernate 时候吃过时区的亏(有两个 CST ),后面时区信息都是另外存。
waising

waising      10 小时 20 分钟前

@iseki #10 数据都是同一个时区下是不是用 timestamp 更好
moen

moen      8 小时 59 分钟前

@waising 不好,without timezone 的情况下需要保证客户端输入的是 UTC ,否则容易出错。显然还是让 dbms 自己处理时区更能减少问题
Cbdy

Cbdy      8 小时 56 分钟前

时间戳或者 ISO8601
myd

myd      8 小时 48 分钟前

性能的瓶颈通常不在于 int 和 datetime ,所以我选择可读性更好的 datetime 。如果涉及到时区,就用时间戳。
Jirajine

Jirajine      8 小时 44 分钟前   ❤️ 1

大部分应用不需要也不应该处理、存储时区信息,用户发表了一个 post ,你只需要知道该 post 发布的“绝对时间”,没必要去记录用户是用什么时区发布的。

“时区”只是作为时间信息输入 /输出 解析和格式化的时候的一项参数,与时间信息本身无关。就像存一个整数不需要关心它是 16 进制还是 10 进制、如何 padding 如何对齐,这些只是显示和解析时的参数。
reter

reter      8 小时 31 分钟前   ❤️ 1

#1 @Livid 说的并不正确,时间戳会出现负数,并且负数表示 1970 年 1 月 1 日之前的时间,所以不适合用无符号,应该用有符号。
CEBBCAT

CEBBCAT      8 小时 8 分钟前 via iPhone

20 层楼了,还没有人说 int(11) 的问题吗?
CEBBCAT

CEBBCAT      8 小时 3 分钟前 via iPhone

之前我也是像教科书上那样写的,存 datetime 。后来工作的公司在多个国家都有服务,所以学到了存 UNIX 时间戳的方式。MySQL 存的是 BUGINT ,无符号。

关于我楼上说的,int(11),是建表之后查建表结构然后显示的那个是吗?楼主可以 Google 一下,这个 11 不影响存储的
CEBBCAT

CEBBCAT      8 小时 3 分钟前 via iPhone

@CEBBCAT BIGINT 😄
twinsdestiny

twinsdestiny      7 小时 9 分钟前

@CEBBCAT 你确定 int(11)能存下 13 位时间戳?不然楼主除 1000 干嘛
humbass

humbass      7 小时 8 分钟前

@reter new 出来不会有负数,一般记录的时间肯定当前系统、用户生成的时间。
chenqh

chenqh      6 小时 53 分钟前

存 0 时区的 datetime,mysql 类型 datetime,用 biginit,太难运维了
triptipstop

triptipstop      6 小时 49 分钟前

小时候用 TP 存的都是时间戳,后来长大了用的 LV 存的就是 datetime ,这样看起来更优雅,用户面向全球,服务器设置成 0 时区,在客户端转换时区。
dcsuibian

dcsuibian      6 小时 35 分钟前

周经贴,unsigned long ,存毫秒级时间戳
JavaScript 里的数字都是 double ,但不超过 2^52 应该都是安全的
fuchish112

fuchish112      6 小时 6 分钟前

datetime,方便查看
timestamp,需要时区的话,用这种
CEBBCAT

CEBBCAT      6 小时 3 分钟前   ❤️ 1

@twinsdestiny 我既然发出来了,那自然说明有一定自信。但为了防止误人子弟,我又去确认了一遍。int(11)中的 int 决定了存储空间,11 则是和 ZEROFILL 配合的,只影响显示。

随附两个参考链接
1. https://stackoverflow.com/q/5634104
2. https://www.cnblogs.com/polk6/p/11595107.html

我觉得不应该这么自大和冷漠
ychost

ychost      5 小时 59 分钟前

最好存自己时区的数据到数据库,方便排查问题,其它时区只需要前端做一层转换就好了
ericls

ericls      5 小时 59 分钟前 via iPhone

存未来的时间还是 string 好
ladypxy

ladypxy      5 小时 51 分钟前

转换成 UTC Unix timestamp
baobao1270

baobao1270      5 小时 41 分钟前 via iPhone

@Livid 时间戳有可能出现负数:比如存用户的生日,而用户生日可能在 1970 年之前。这些在设计表的时候都是要考虑的。
james2013

james2013      5 小时 39 分钟前 via Android

那些说时区问题的,又不是国际软件?
在本地,测试,正式服设置一次 mysql 配置,使用 datetime 就可以了
Features

Features      5 小时 35 分钟前

我存俩,一个 datetime,一个 uint
就是读取的时候免得转来转去的
humbass

humbass      5 小时 24 分钟前

@CEBBCAT 多谢!

一直不知道扩符号里头的 11 代表啥,我按实际需求的 int 位数写;
那就是说:如果想存 unix time 在 int 里头,还是需要将 new Date().getTime() / 1000 , 是这个意思吗?
humbass

humbass      5 小时 20 分钟前

@baobao1270 说到生日这个使用点了,确实有这个需求,还是不能直接使用 unsigned int @Livid
codehz

codehz      5 小时 15 分钟前   ❤️ 1

关于 unix 时间戳的几个错误认知:
1. unix 时间戳表示从 UTC 1970 年 1 月 1 日 0 时 0 分到现在的秒数,错❌
2. 等待一秒后 unix 时间戳+1 ,错❌
3. 那么最起码,unix 时间戳不会递减,错❌
关于时间格式的几个错误认知:
1. 24:12:34 是一个非法的时间,错❌
2. 每一个整数都是一个可能的年份,错❌
3. 同一时间的年份在任何时间格式下都是一样的数字(如果有),错❌
4. 每月的日数在 28 到 31 之间,错❌
5. 星期六之前一定是星期五,错❌
6. 时区之间的差异最短是 15 分钟,错❌
7. 时区一定是到 UTC 到固定时间差异,错❌
8. 下一个星期的同一时间一定是当前时间+7*864000 秒,错❌
9. 你可以设计一个更好的时间系统,错❌
codehz

codehz      5 小时 6 分钟前

正经回答一下好了,存时间就别限制位数了,数据库也不差这么点,32 位时间戳很快就会撞到 2038 了(虽然数据库用十进制的倒是问题不大,但是这种莫名其妙的 11 的限制不会有啥好处)
不过其实如果不是性能非常要紧的话,存 iso8601 就足够用了(数据库自带时间类型,可以自动转换的就忽略这点),主要除了程序处理,有时候还需要人工检查问题的,看时间戳不如看可读性好的文本
CEBBCAT

CEBBCAT      4 小时 49 分钟前

@humbass 也许需要把时间戳获取和存储分开思考。说起来我现在才明白你说的除 1k 是什么意思,`Date().getTime()`获取的是毫秒时间戳,除以 1k 就变成了秒时间戳。

关于怎么存,一两句话有点难以讲清楚,我推荐你配合 Google 计算一下 4 字节的 INT 能支持存储什么样的时间范围。
2NUT

2NUT      4 小时 44 分钟前

@codehz #39 不能细想 坑很多
Jooooooooo

Jooooooooo      4 小时 41 分钟前

用 int 存 unixtime 基本没啥问题.
shiny

shiny      3 小时 42 分钟前 via iPhone

上次的润秒不知道有没有带来坑
colatin

colatin      2 小时 45 分钟前

i18n 是老大难问题,是考验是否合格程序员的最低标准。
iseki

iseki      2 小时 39 分钟前

@waising with time zone 并不是说数据库会存储输入的 timezone ,这是个比较迷惑的名字,存储的是一个绝对的时间点(实际上存的 UTC ),输入输出时按当前设定时区走
iseki

iseki      2 小时 35 分钟前

@CEBBCAT BUGINT 可太真实了
px920906

px920906      2 小时 25 分钟前

@codehz 除了最后一点,都不能理解... 求解释或者给些资料的链接,google 不过来😂
leonshaw

leonshaw      2 小时 1 分钟前

@px920906 大概看出来有润秒、公元前后、历法变更、夏令时这几点。时间戳本身就是绝对时空观的产物,是时候建立相对论时间系统了。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK