【发布时间】:2014-05-12 15:58:34
【问题描述】:
我正在使用 Java 8 中的新 java.time 包。我有一个旧数据库,它给了我java.util.Date,我将其转换为Instant。
我想要做的是添加一个基于另一个数据库标志的时间段。我可以添加几天、几周、几个月或几年。我不想关心我要添加什么,我希望将来能够添加更多选项。
我的第一个想法是Instant.plus(),但对于大于一天的值,我会使用UnsupportedTemporalTypeException。 Instant 显然不支持大时间单位的操作。好吧,无论如何,LocalDateTime 可以。
所以这给了我这个代码:
private Date adjustDate(Date myDate, TemporalUnit unit){
Instant instant = myDate.toInstant();
LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
dateTime = dateTime.plus(1, unit);
Instant updatedInstant = dateTime.atZone(ZoneId.systemDefault()).toInstant();
return new Date(dueInstant.toEpochMilli());
}
现在,这是我第一次使用新的时间 API,所以我可能在这里遗漏了一些东西。但对我来说,我必须去似乎很笨拙:
Date --> Instant --> LocalDateTime --> do stuff--> Instant --> Date.
即使我不必使用 Date 部分,我仍然会觉得它有点尴尬。所以我的问题是,我这样做是否完全错误,最好的方法是什么?
编辑:扩展 cmets 中的讨论。
我想我现在对 LocalDateTime 和 Instant 如何使用 java.util.Date 和 java.sql.Timestamp 有了更好的了解。谢谢大家。
现在,一个更实际的考虑。假设用户向我发送了他们在世界任何地方的日期,任意时区。他们发给我2014-04-16T13:00:00,我可以将其解析为 LocalDateTime。然后我将其直接转换为 java.sql.Timestamp 并保存在我的数据库中。
现在,我不做任何其他事情,从我的数据库中提取我的 java.sql.timestamp,使用timestamp.toLocalDateTime() 转换为LocalDateTime。都好。然后我使用 ISO_DATE_TIME 格式将此值返回给我的用户。结果是2014-04-16T09:00:00。
我认为这种差异是由于某种类型的与 UTC 的隐式转换。我认为我的默认时区可能会应用于值 (EDT, UTC-4),这可以解释为什么该数字会延迟 4 小时。
新问题。从本地时间到 UTC 的隐式转换在哪里发生?保留时区的更好方法是什么。我不应该直接从当地时间作为字符串 (2014-04-16T13:00:00) 转到LocalDateTime 吗?我应该期待用户输入的时区吗?
【问题讨论】:
-
你想在这里代表什么价值?
Instant不逻辑上了解日历系统 - 它只是一个时间点 - 所以添加一个月没有任何意义。您还应该仔细考虑您是否真的想要使用系统时区 - 您是否希望根据运行的位置为相同的值获得不同的结果? -
如果数据库中的所有内容都以 UTC 存储,您可以认为 Timestamp 是 UTC 时区中的一个瞬间,并使用 UTC 将其转换为 LocalDateTime。您可以将此转换封装在您的实体中,或者使用 jadira(AFAIK)允许您直接映射 LocalDateTime。
-
如果您将 UTC 指定为时区,这对我来说是正确的。我会使用 Date.from(Instant) 而不是毫秒。 Hibernat 的未来版本可能会直接支持新的时间类型。
-
JDBC 要求驱动程序将没有时区的时间和时间戳解释为在本地时区中,因此除非您的时区是 UTC,或者您的驱动程序不兼容 jdbc,否则该假设是错误的。
-
@jacobhyphenated 一个
java.sql.Timestamp有一个toLocalDateTime()方法和一个静态valueOf(LocalDateTime)。应该没有必要使用Instant作为中介。