Java Date混乱

时间:2016-12-13 12:28:04

标签: java date

我对日期非常困惑。

我有一个Web应用程序,它有一个Java后端。我有一个没有时间信息的日期字段。我使用 hibernate 将此信息写入DB。它的定义是

@Column
@Temporal(TemporalType.DATE)
private Date startDate;

实际上这些是基本的信息。这是我的问题。

我在UTC(GMT+0)时区运行java,但客户端时区为GMT+3

用户选择一天(让我们说 10.12.2016 (dd.MM.yyyy))。在客户端,这一天表示为10.12.2016 00:00 GMT+3。此用户想要保存此日期。

这个日期以09.12.2016 21:00 GMT+0的形式出现在我的后端。我想在没有timeinfo的情况下保存这个日期。所以java代码将数据保存为09.12.2016。 (对应于 09.12.2016 00:00 GMT+0

现在用户想看看他/她保存了什么。 Java将日期读为09.12.2016 00:00 GMT+0,客户端将此日期视为09.12.2016 03:00 GMT+3。最后,用户将日期视为09.12.2016,但他/她将此日期保存为10.12.2016

因此,用户可以在他/她实际保存前一天看到这一天。

我希望将数据保留为TemporalType.DATE,并希望向用户显示正确的日期。

我该如何解决这个问题?我一直在Google上挖掘2天,但我找不到合理的解释。

注意:**我的用户不仅可以在GMT+3上使用不同的时区。请考虑这种情况。

3 个答案:

答案 0 :(得分:0)

我认为,如果您的应用程序了解客户的GMT,您将从请求中获得GMT职位,因此我不会深入到这一点,因为需要有关您的申请的更多信息确实。

一旦您有要求的GMT信息,您只需要这样做:

Date databaseDate = database's date (you said you were working in GMT and it was also stored in GMT 0 so no further transformation is required)

//As you said you are working in GMT 0 this will be the GMT of your calendar.
Calendar calendar = new GregorianCalendar();

//As you know your GMT you only have to set it through this method
TimeZone clientTimezone = TimeZone.getTimeZone("GMT-1:00");

Date originalDate = inputCalendar.getTime();
calendar.setTimeZone(clientTimezone);

//This will return you the offset -positive or negative- of calendars time zone respect to UTC 0 - GMT 0 - in milliseconds
int offset = inputCalendar.getTimeZone().getOffset(originalDate.getTime());

//You get the database's date in milliseconds and add your offset to it. It can be positive or negative and the final result will the date transformed to your request's GMT
Date clientDate= (new Date(originalDate.getTime() + offset));

这足以满足您的要求。

答案 1 :(得分:0)

有几种选择。

  1. 如果您正在使用Java 8(或者可以切换到Java 8)那么新的 package java.time提供了更加灵活的日期模型和类 LocalDate会准确地为您提供所需的信息。
  2. 如果您使用的是java 7或更低版​​本,我会倾向于存储您的日期 在DB中作为String字段。即将Date格式化为String并保存 这种方式将DB转换为varchar字段。当你阅读它只是解析它 回到过去。这样你的" 10.12.2016"将保持如此 时区没有任何额外的诡计。
  3. 最后,如果您坚持将其保留为您可能想要的日​​期 无论如何,所有日期总是存储在GMT + 0中 临时位置。这样,位于同一位置的用户将始终可以看到 同一天。但是不同位置的两个用户仍然可以看到 与不同日期相同的字段
  4. 如果可能的话,我会提出第一个选项,如果不是那么2d。如果用户在不同时区使用您的应用,则第三种情况会变得越来越复杂。

    此外,您可能会发现这篇文章很有趣:它是关于将未知格式的字符串转换为日期:Parsing any string to Date

答案 2 :(得分:0)

有关日期时间问题的一般信息,而不是特定于Hibernate ...

服务器上当前默认值的时区应无关紧要。始终通过传递可选的时区参数,始终在代码中指定所需/预期的时区。在Stack Overflow上讨论了很多次,所以搜索更多信息。

LocalDate todayMontreal = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;

没有时区的仅限日期的值确实不精确。对于任何给定的时刻,日期因地区而异。巴黎午夜过后几分钟法国是一个新的一天,而在加拿大蒙特利尔仍然是'昨天'。在Stack Overflow上多次讨论,所以搜索更多信息。

如果要精确使用带时区的日期时间。在Stack Overflow上多次讨论,所以搜索更多信息。

ZonedDateTime todayMontrealStart = todayMontreal.atStartOfDay( ZoneId.of( "America/Montreal" ) ) ;

...或...

ZonedDateTime todayMontrealStart = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) );

要存储数据,请将该时区设为UTC。默认情况下,Instant类始终为UTC。

Instant instant = todayMontrealStart.toInstant();

您的JDBC驱动程序和/或数据库可能会为您执行此操作。使用JDBC 4.2及更高版本,通过getObjectsetObject传递java.time对象,否则返回java.sql类型以与数据库交换数据。在Stack Overflow上多次讨论,所以搜索更多信息。

避免使用麻烦的旧日期时间类,例如java.util.Date.Calendar。现在遗留下来,取而代之的是java.time类。在Stack Overflow上多次讨论,所以搜索更多信息。

具体来说,您应该搜索Stack Overflow以获取LocalDate,Instant,OffsetDateTime和ZonedDateTime类。

额外提示:在将日期时间值作为文本(例如客户端和服务器之间)交换时,请使用ISO 8601标准格式。在Stack Overflow上多次讨论,所以搜索更多信息。