“本地...”类型的故意没有时区的概念。所以他们做而不是代表时间轴上的一个时刻。 A LocalDateTime
表示可能时刻的模糊范围,但在分配偏移或时区之前没有真正意义。这意味着应用ZoneId
获得ZonedDateTime
。
例如,说今年圣诞节开始于12月25日的第一时刻,我们要说:
LocalDateTime ldt = LocalDateTime.of(2017 , 12 , 25 , 0 , 0 , 0 , 0);
但午夜的中风发生在更早的东部比西部。
这就是为什么精灵的物流部门在太平洋地区开始绘制圣诞老人的路线,起始地点是Kiribati,太平洋是世界最早的时区,比世界协调时早14小时。在那里交付后,他们将圣诞老人西向路线发往新西兰等地的午夜。然后在午夜之后回到亚洲。然后是印度等几个小时后到达欧洲的午夜,然后是北美东海岸,晚些时候再过几个小时。所有这些地方都经历过相同LocalDateTime
在不同的时刻,每个送货所代表的一个不同ZonedDateTime
对象。
所以......
- 如果你想要录制的概念的圣诞节午夜25日之后出发,使用
LocalDateTime
和写入TIMESTAMP WITHOUT TIME ZONE
类型的数据库列。
- 如果您想记录圣诞老人每次送货的确切时刻,请使用
ZonedDateTime
并写入类型为TIMESTAMP WITH TIME ZONE
的数据库列。
关于第二个项目符号,请注意,几乎每个数据库系统都将使用区域信息来调整UTC的日期时间并存储该UTC值。有些还保存区域信息,但某些(如Postgres)在使用它调整为UTC后丢弃区域信息。所以“带时区”是一个用词不当的地方,真的意思是“尊重时区”。如果您关心记住原始区域,您可能需要将其名称保存在一个单独的列中。
使用Local…
类型的另一个原因是未来约会。政治家喜欢经常改变他们辖区的时区。他们喜欢采用夏令时(DST)。喜欢改变他们DST切换的日期。他们喜欢放弃采用DST。他们喜欢重新定义他们的时区,改变边界。他们喜欢重新定义它们的UTC偏移量,有时候会像15分钟那样。他们很少提前发出通知,在短短一个月或两个小时内发出警告。
因此,要进行下一年或六个月的体检预约,无法预测时区定义。因此,如果您要预约上午9点,则应使用记录在TIMESTAMP WITHOUT TIME ZONE
类型的数据库列中的LocalTime
或LocalDateTime
。否则,上午9点的预约,如果在夏令时延期的区域划分,可能会显示为上午8点或上午10点。
生成投影计划时,可以将时区(ZoneId
)应用于这些“本地”(未分区)值以创建ZonedDateTime
对象。但是,当政客们通过改变区域可能毁掉他们的意义时,不要依赖那些时间太远的人。
提示:对DST和时区进行频繁更改意味着您必须保持您的时区tzdata数据库处于最新状态。在你的主机操作系统,你的JVM中,或者在你的数据库系统中,例如Postgres,都有一个tzdata。所有这三个应该经常更新。有时,这些区域的变化速度比计划的更新周期更快,例如土耳其去年决定在数周前通知DST。所以你可能偶尔需要手动更新这些tzdata文件。 Oracle提供了一个更新其Java实现的tzdata的工具。
处理精确时刻的一般最佳做法是使用UTC跟踪它们。仅在必要时才应用时区,例如向用户展示他们希望在自己的教区时区中看到值的用户。在java.time中,Instant
类表示时间轴中的某个时刻。 UTC的分辨率为纳秒。
Instant instant = Instant.now() ; // Current moment on the timeline in UTC.
ZonedDateTime zdt = instant.atZone(z) ; // Assign a time zone to view the same moment through the lens of a particular region’s wall-clock time.
Instant instant = zdt.toInstant(); // revert back to UTC, stripping away the time zone. But still the same moment in the timeline.
顺便说一句,符合JDBC 4.2及更高版本的驱动程序可以直接处理java。时间类型通过:
PreparedStatement::setObject
ResultSet::getObject
避免旧旧的数据类型,如java.util.Date
和java.sql.Timestamp
只要有可能。它们设计不佳,混乱和缺陷。
明白,所有这四个都在UTC时间线上的时刻表示:
- 现代
java.time.Instant
java.time.OffsetDateTime
与ZoneOffset.UTC
分配的偏移
- 传统
java.util.Date
java.sql.Timestamp
如果你想有一个日期,只值没有时间的天,没有时区,使用java.time.LocalDate
。这个类代替java.sql.Date
。
至于具体的数据库,要知道,SQL标准几乎没有触及到的日期时间类型及其处理的话题。此外,各种数据库有很大的不同,我真的是广泛,在他们的支持的日期时间的功能。有些几乎没有支持。有些将SQL标准类型与专有类型混合使用,这些类型要么早于标准类型,要么作为标准类型的替代品。另外,JDBC驱动程序的行为与将日期时间值封送到数据库或从数据库封装日期时间值不同。一定要研究文件和练习,练习,练习。
我非常同意这样的说法,即一段时间应该以UTC存储,并且只有在向用户显示时才划分区域。 –
我真的很希望我8岁的女儿(谁声称圣诞老人是不真实的)有一段时间读这个。不仅是一个很好的答案,但是当我得到“这就是为什么精灵......”的时候upvoted。:) – NealeU
TimeZone精美的解释。 Upvoted,谢谢:-) –