询问一个关于 Java 日期在数据库存储的格式问题

2022-07-12 16:20:36 +08:00
 MuXia

java 新人目前只在一家公司工作过

想问下各位,一般 Java 写后端的话,对于日期字段的处理,一般数据库存储的是什么格式的?

时间戳? yyyy-MM-dd HH:mm:ss 格式字符串? 还是其他的?

3060 次点击
所在节点    Java
32 条回复
Jooooooooo
2022-07-12 16:23:49 +08:00
都行, 看现有的系统用啥, 跟着用一样的.

时间戳或者 string 或者 timestamp 都可以.
bxb100
2022-07-12 16:30:48 +08:00
UTC 时间戳
unco020511
2022-07-12 16:34:43 +08:00
有海外业务:时间戳,仅国内业务:存格式化后的字符串(GTM+8 本地时区)
gam2046
2022-07-12 16:36:28 +08:00
数据库都有日期类型,如果实在特殊原因不想、不能用。时间戳是唯一选择。所有语言都有简单的方法将时间戳转换成日期,并且也方便做本地化。
dqzcwxb
2022-07-12 16:37:56 +08:00
你猜猜数据库为什么要弄一个 datetime 类型出来
cheng6563
2022-07-12 16:42:44 +08:00
跨时区的国际系统可以用时间戳,其他的用 datetime 就行了
neptuno
2022-07-12 17:02:40 +08:00
新项目一律时间戳
nothingistrue
2022-07-12 17:53:26 +08:00
常规数据库有两种日期时间格式,一种是年、月、日、时、分、秒、毫秒组合存储,另一种是时间戳存储,即自 1970 年 0 点开始的毫秒数,内部是数值类型。第一种类型没有时区(查询出来的显示值,不随环境变量当中的时区而改变),Mysql 还细分为 Date 和 DateTime ,Oracle 则统一为 Date ,对应的 Java 类型是 java.time.LoacalDate 和 LocalDateTime 。第二种类型有时区(查询出来的显示值,随环境变量当中的时区的不同而不同),有的数据库单位直到毫秒,有得能到微秒,对应的 Java 类型是 java.sql.Date 或 java.sql.Timestamp (取决于要哪个单位)。

一般来说,如果是新项目,一律考虑使用 Date / DateTime - java.time.LocalDate / LocalDateTime ,即使要国际化(时区上你可以在程序层面再控制转换成 ZonedDateTime ,甚至还可以将时区国际化直接交给前端处理),在数据库上处理时区会是个灾难。
dcsuibian
2022-07-12 18:03:26 +08:00
用 long 存毫秒级时间戳,足够用到天荒地老。
MySQL 的 timestamp 不要用,只有 4 字节,除非你想在 2038 年引起下一个千年虫。

对于精准时间点,时间戳特别好用。没有时区、夏令时问题。闰秒操作系统会帮你吃掉。
连接数据库不用担心 serverTimezone=GMT%2B8 问题
时间不对,排查点就基本可以缩小到 Format
MuXia
2022-07-12 19:40:48 +08:00
@nothingistrue #8 回复的很详细,新知识 get
dorothyREN
2022-07-12 20:20:29 +08:00
pg 的话 用 timestamptz 是带时区的时间戳,java 用 Timestamp 类型
realpg
2022-07-13 01:53:10 +08:00
任何时候都存时间戳,不分语言
因为时间戳是绝对单位,且服务器设置好时区转换当地时间方便
nothingistrue
2022-07-13 10:05:04 +08:00
@MuXia 忽略我之前的回复,有错误。各数据库的日期时间保存格式,都不相同,我说得只在 Mysql 上是正确的。映射那里也写错了,与 JDBC 规范不符合。

正确的应该是:
java.time.LocalDateTime ,无时区日期时间(显示值即值,没有内部值,对应的现实时间随时区浮动),JDBC 类型是 TIMESTAMP ;
java.time.LocalDate ,无时区日期(显示值即值,没有内部值,与现实时间没有直接对应关系),JDBC 类型是 Date ;
java.time.LocalTime ,无时区当天时间(显示值即值,没有内部值,对应的现实时间随时区+天浮动),JDBC 类型是 Time ;
java.time.OffsetDateTime ,偏移量日期时间(对应现实完整时间,内部值固定,显示值随时区偏移),JDBC 类型是 TIMESTAMP ;
java.time.OffsetTime ,偏移量当天时间(对应现实当天时间,内部值固定,显示值随时区偏移),JDBC 类型是 TIMESTAMP ;
java.time.ZonedDateTime ,基本等同于 OffsetDateTime ,区别只是一个是 CST 时区,一个是+/-数字时区。

详细可见 : https://docs.jboss.org/hibernate/orm/5.6/userguide/html_single/Hibernate_User_Guide.html#basic-provided 表 2 。注意上面的 Date 、Time 、TIMESTAMP 都是 JDBC 类型,具体是什么类型取决于各数据库厂商提供的 JDBC 驱动。另外 TIMESTAMP 是时间戳 + 时区,不是只有时间戳。

这里面 Mysql 提供了个狗屎。它的 DateTime 只是歪打正着的跟 java.time.LocalDateTime 对应,但也只在 JVM 时区跟 数据库时区一致的情况下才这样,不一致的时候要出问题。而它的 Timestamp 则完全无法使用。
MuXia
2022-07-13 10:12:12 +08:00
@nothingistrue #13 总感觉这对应关系挺混乱的,我现在处理起来都是直接数据库字段用 varchar 或 int 来存时间戳,在代码里面去转化
nothingistrue
2022-07-13 10:14:09 +08:00
一般来说,不考虑国际化的时候,还是要用 java.time.LocalDateTime ,这个更贴近需求,而且就算狗屎 Mysql 也能正好提供实现。

考虑国际化的时候,应当用 java.time.OffsetDateTime/java.time.ZonedDateTime ,但是在数据库映射上要做特殊处理,不是所有的数据库都支持这种映射,比如 Mysql 。
MuXia
2022-07-13 10:20:23 +08:00
@nothingistrue #15 行,有空再去了解一下
nothingistrue
2022-07-13 10:20:28 +08:00
@MuXia 不要用单一的数值类型存时间戳,那实际上隐式存了一个 JDBC 时区,该时区依赖于 JVM 时区和 JDBC 驱动,当 JVM 时区、JDBC 驱动、或者只是 JDBC 连接配置( Mysql 就是个典型)发生变化的时候,会发生很难处理的时间偏移问题。要存时间戳,必须用数据库的带时区 Timestamp ,或者数字列+时区列两列存储时间。
MuXia
2022-07-13 10:28:04 +08:00
@nothingistrue #17 那#9 楼说的这个问题能否规避呢,如果纯国内应用的话,应该不用考虑时区变更的问题
nothingistrue
2022-07-13 10:32:49 +08:00
@MuXia #17 若不考虑国际化,就用 java.time.LocalDateTime 对应 Mysql DateTime ,只要保证 JVM 、Mysql 、JDBC 连接配置都是东八区,其他时候就都不用考虑时区问题。
MuXia
2022-07-13 10:48:02 +08:00
@nothingistrue #19
```
MySQL 的 timestamp 不要用,只有 4 字节,除非你想在 2038 年引起下一个千年虫。
```
九楼说的这个问题是不是无解?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/865700

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX