Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/34.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java8LocalDate&;数据库中的LocalDateTime_Java_Hibernate_Utc_Java Time - Fatal编程技术网

使用Java8LocalDate&;数据库中的LocalDateTime

使用Java8LocalDate&;数据库中的LocalDateTime,java,hibernate,utc,java-time,Java,Hibernate,Utc,Java Time,我的要求是在数据库中存储UTC时区中的所有日期和日期时间。我在Hibernate实体中使用Java8的LocalDate&LocalDateTime 这是否正确,因为LocalDate和LocalDateTime没有与之关联的时区 如果不是,我是否应该退回到使用旧的(或旧的?Date&Timestamp 或者我应该使用Java8的Instant?如果使用Instant,是否可以只存储日期部分而不存储时间 数据库是MySQL和SQL Server,这是一个Spring Boot应用程序。作为新的日

我的要求是在数据库中存储UTC时区中的所有日期和日期时间。我在Hibernate实体中使用Java8的
LocalDate
&
LocalDateTime

这是否正确,因为
LocalDate
LocalDateTime
没有与之关联的时区

如果不是,我是否应该退回到使用旧的(或旧的?
Date
&
Timestamp

或者我应该使用Java8的
Instant
?如果使用
Instant
,是否可以只存储日期部分而不存储时间


数据库是MySQL和SQL Server,这是一个Spring Boot应用程序。

作为新的日期API的一部分,他们将日期类型拆分。包含时区的正确类是ZonedDateTime

// Get the current date and time
      ZonedDateTime date1 = ZonedDateTime.parse("2007-12-03T10:15:30+05:30[Asia/Karachi]");
      System.out.println("date1: " + date1);

      ZonedDateTime zonedDateTime = ZonedDateTime.now();
      System.out.println("Zoned Date Time: " + zonedDateTime);

      ZoneId id = ZoneId.of("Europe/Paris");
      System.out.println("ZoneId: " + id);

      ZoneId currentZone = ZoneId.systemDefault();
      System.out.println("CurrentZone: " + currentZone);
印刷品:

date1: 2007-12-03T10:15:30+05:00[Asia/Karachi]
Zoned Date Time: 2017-04-18T11:36:09.126-04:00[America/New_York]
ZoneId: Europe/Paris
CurrentZone: America/New_York

“本地…”类型故意没有时区的概念。因此,它们并不代表时间线上的某个时刻。
LocalDateTime
表示一个模糊的可能时刻范围,但在指定偏移量或时区之前没有实际意义。这意味着应用
ZoneId
来获取
zoneDateTime

例如,要说今年的圣诞节从12月25日的第一刻开始,我们说:

LocalDateTime ldt = LocalDateTime.of( 2017 , 12 , 25 , 0 , 0 , 0 , 0 );
但午夜钟声在东方比西方来得早

这就是为什么精灵后勤部门在UTC前14小时绘制出圣诞老人的路线图,从世界上最早的时区太平洋开始。在那里交货后,他们将圣诞老人向西运送到像新西兰这样的地方,在午夜过后再出发。之后,他们将前往亚洲参加午夜晚会。然后是印度,等等,几个小时后到达欧洲进入午夜,再过几个小时到达北美东海岸进入午夜。所有这些地方在不同的时刻都经历了相同的
LocalDateTime
,每个交付都由不同的
ZoneDateTime
对象表示

所以

  • 如果要记录25日午夜后开始的圣诞节概念,请使用
    LocalDateTime
    并将其写入不带时区的
    TIMESTAMP类型的数据库列中
    
  • 如果要记录圣诞老人每次递送的确切时间,请使用
    ZoneDateTime
    并将其写入带有时区的
    时间戳类型的数据库列中
关于第二个要点,请注意,几乎每个数据库系统都将使用区域信息将日期时间调整为UTC并存储该UTC值。有些人还保存了区域信息,但有些人(如Postgres)在使用区域信息调整到UTC后会丢弃区域信息。所以“有时区”有点用词不当,真正的意思是“尊重时区”。如果您想记住原始区域,可能需要将其名称存储在旁边的单独列中

使用
Local…
类型的另一个原因是为了将来的约会。政客们喜欢经常改变他们管辖的时区。他们喜欢采用夏令时(DST)。他们希望更改DST切换的日期。他们喜欢放弃采用DST。他们喜欢重新定义时区,改变边界。他们喜欢重新定义他们与UTC的偏移量,有时是15分钟。而且他们很少提前通知,只需一两个月的警告就可以做出这样的改变

因此,要预约明年或六个月的体检,时区定义无法预测。因此,如果您希望预约上午9点,您应该使用
LocalTime
LocalDateTime
记录在
TIMESTAMP类型的数据库列中,不带时区。否则,上午9点的约会,如果被划分为DST转换延迟的区域,则可能出现在上午8点或上午10点

生成计划时间表时,可以将时区(
ZoneId
)应用于那些“本地”(未分区)值,以创建
zoneDateTime
对象。但是,当政客们可能通过改变区域而破坏其意义时,不要过于依赖那些过时的东西

提示:这些对DST和时区的频繁更改意味着您必须使您的时区数据库保持最新。在您的主机操作系统、JVM中,或者在您的数据库系统(如Postgres)中,都有大量的数据。所有这三项都应该经常更新。有时,这些区域的变化速度快于这些产品的计划更新周期,例如土耳其去年决定在仅提前几周通知的情况下继续使用DST。因此,您可能偶尔需要手动更新这些数据文件。Oracle提供了一个工具来更新其Java实现的数据

处理精确时刻的一般最佳实践是在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.time类型:

  • PreparedStatement::setObject
  • ResultSet::getObject
奇怪的是,JDBC4.2规范不需要支持两种最常见的java.time类型:
Instant
&
ZonedDateTime
。该规范确实需要对
OffsetDateTime
的支持。因此,您可以轻松地来回转换

尽可能避免旧的遗留数据类型,如
java.util.Date
java.sql.Timestamp
。它们设计拙劣、令人困惑且存在缺陷

请理解,这四项都是UTC时间线上某一时刻的表示:

  • 现代
    • java.time.Instant
    • java.time.OffsetDateTime<dependency>
          <groupId>org.hibernate</groupId>
          <artifactId>hibernate-java8</artifactId>
          <version>${version.hibernate}</version>
      </dependency>
      
      @PostConstruct
      void setUTCTimezone() {
          TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
      }
      
      <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>
      
      @EntityScan(basePackageClasses = { Application.class,    Jsr310JpaConverters.class })
      SpringBootApplication
      public class Application { … }