使用Java在PostgreSQL中存储时间的最推荐方法是什么?java.time
我在PostgreSQL数据库中存储了两个日期。首先,是网页的访问数据,第二个日期是网页最后一次修改的日期(这是一个长)。
我有些怀疑存储这些价值观的最佳策略是什么。
我只需要日/月/年和小时:秒,这只适用于统计建议。
所以,一些疑问:
- 最好存储一样长,并在恢复信息时进行转换,还是以上述数据格式存储?
- 最好在软件上还是在数据库中插入时设置访问日期?
- 在Java中,如何处理日期的最佳类?
我在PostgreSQL数据库中存储了两个日期。首先,是网页的访问数据,第二个日期是网页最后一次修改的日期(这是一个长)。
我有些怀疑存储这些价值观的最佳策略是什么。
我只需要日/月/年和小时:秒,这只适用于统计建议。
所以,一些疑问:
IMO,任何在PostgreSQL中存储日期和时间数据的策略都应该依赖于以下两点:
即时
数据类型或LocalDateTime
数据类型之间做出决定。我的食谱如下。
如果要记录特定事件发生时的物理时刻(真正的“时间戳”,通常是一些创建/修改/删除事件),请使用:
(不要让PostgreSQL特殊的数据类型/混淆你:它们实际上都没有存储时区)WITH TIMEZONE
WITHOUT TIMEZONE
一些样板代码:以下假设是 一个 、 a 并且是对应于时区的静态对象。ps
PreparedStatement
rs
ResultSet
tzUTC
Calendar
UTC
public static final Calendar tzUTC = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
写入数据库 :Instant
TIMESTAMPTZ
Instant instant = ...;
Timestamp ts = instant != null ? Timestamp.from(instant) : null;
ps.setTimestamp(col, ts, tzUTC); // column is TIMESTAMPTZ!
从数据库读取 :Instant
TIMESTAMPTZ
Timestamp ts = rs.getTimestamp(col,tzUTC); // column is TIMESTAMPTZ
Instant inst = ts !=null ? ts.toInstant() : null;
如果您的PG类型是安全的(在这种情况下,在该代码中没有效果;但始终建议不依赖于默认值时区)。“安全”意味着结果将不依赖于服务器或数据库时区或时区信息:该操作是完全可逆的,无论时区设置发生什么,您都将始终获得与Java端相同的“时间瞬间”。TIMESTAMPTZ
calendarUTC
如果处理的不是时间戳(物理时间轴上的某个时刻),而是“民事”本地日期时间(即字段集),则可以使用:{year-month-day hour:min:sec(:msecs)}
LocalDateTime
(Java 8或Jodatime)。java.sql.Timestamp
不带时区的时间戳
(TIMESTAMP
)从数据库读取 :LocalDateTime
TIMESTAMP
Timestamp ts = rs.getTimestamp(col, tzUTC); //
LocalDateTime localDt = null;
if( ts != null )
localDt = LocalDateTime.ofInstant(Instant.ofEpochMilli(ts.getTime()), ZoneOffset.UTC);
写入数据库 :LocalDateTime
TIMESTAMP
Timestamp ts = null;
if( localDt != null)
ts = new Timestamp(localDt.toInstant(ZoneOffset.UTC).toEpochMilli()), tzUTC);
ps.setTimestamp(colNum,ts, tzUTC);
同样,这种策略是安全的,您可以安然入睡:如果您存储,您将始终检索这些精确字段(小时= 23,分钟= 59等),无论发生什么 - 即使明天您的Postgresql服务器(或客户端)的时区发生变化,或者您的JVM或操作系统时区,或者您的国家/地区修改其DST规则等。2011-10-30 23:59:30
添加:如果你想(这似乎是一个自然的要求)存储完整的日期时间规范(ZonedDatetime
:时间戳和时区,其中隐式还包括完整的民用日期时间信息 - 加上时区)...然后我有个坏消息要告诉你:PostgreSQL没有这个数据类型(据我所知,其他数据库也没有)。您必须设计自己的存储,也许在一对字段中:可能是上述两种类型(高度冗余,尽管对于检索和计算有效),或者其中一种加上时间偏移(您丢失了时区信息,一些计算变得困难,有些不可能),或者其中一种加上时区(作为字符串;某些计算可能非常昂贵)。
它并不漂亮,但这就是我使用Java 8及更高版本中的新java.time框架的ZonedDateTime
实例(教程)的工作原理:
ZonedDateTime receivedTimestamp = some_ts_value;
Timestamp ts = new Timestamp(receivedTimestamp.toInstant().toEpochMilli());
ps.setTimestamp(
1,
ts,
Calendar.getInstance(TimeZone.getTimeZone(receivedTimestamp.getZone()))
);