Java日期混淆
我对约会真的很困惑 我有一个web应用程序,它的后端是Java。我有一个没有时间信息的日期字段。我使用hibernate将此信息写入数据库。它的定义是Java日期混淆,java,date,Java,Date,我对约会真的很困惑 我有一个web应用程序,它的后端是Java。我有一个没有时间信息的日期字段。我使用hibernate将此信息写入数据库。它的定义是 @Column @Temporal(TemporalType.DATE) private Date startDate; 实际上,这些是基本信息。这是我的问题 我在UTC(GMT+0)时区运行java,但客户端时区是GMT+3 用户选择一天(比如说10.12.2016(dd.MM.yyyy))。在客户端,这一天表示为10.12.2016 00:
@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
的形式出现在我的后端。我想在没有时间信息的情况下保存此日期。因此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
,并希望向用户显示正确的日期
我怎样才能解决这个问题?我在谷歌上挖了两天,但找不到合理的解释
注意:**我的用户不仅可以在
GMT+3
上使用不同的时区。请考虑这个情况。 < P>我想,如果您的应用程序知道客户端的GMT,您将从请求接收GMT位置,所以我不会深入到这一点,因为它需要您的应用程序所做的进一步的信息。p>
获得请求的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));
这就足够满足您的需求了。您可以选择几个选项
java.time
提供了更灵活的日期模型和类
会给你你所需要的另外,您可能会发现这篇文章很有趣:它是关于将未知格式的字符串转换为日期的:关于日期时间问题的一些一般信息,而不是特定于Hibernate的 服务器上的当前默认时区应该与此无关。始终通过传递可选时区参数,在代码中指定所需/预期的时区。多次讨论堆栈溢出,请搜索更多信息
LocalDate todayMontreal = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ;
没有时区的仅日期值确实是不精确的。在任何特定的时刻,世界各地的日期都因地区而异。法国巴黎午夜过后几分钟是新的一天,而加拿大蒙特勒阿尔山仍然是“昨天”。多次讨论堆栈溢出,请搜索更多信息
ZonedDateTime todayMontrealStart = todayMontreal.atStartOfDay( ZoneId.of( "America/Montreal" ) ) ;
如果想要精确,请使用带时区的日期时间。多次讨论堆栈溢出,请搜索更多信息
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及更高版本中,通过getObject
和setObject
传递java.time对象,否则返回java.sql类型与数据库交换数据。多次讨论堆栈溢出,请搜索更多信息
ZonedDateTime todayMontrealStart = todayMontreal.atStartOfDay( ZoneId.of( "America/Montreal" ) ) ;
避免麻烦的旧日期时间类,如java.util.date
和日历
。现在是遗留类,被java.time类取代。多次讨论堆栈溢出,请搜索更多信息
ZonedDateTime todayMontrealStart = todayMontreal.atStartOfDay( ZoneId.of( "America/Montreal" ) ) ;
具体来说,您应该在堆栈溢出中搜索LocalDate、Instant、OffsetDateTime和ZonedDateTime类
额外提示:当在客户端和服务器之间以文本形式交换日期时间值时,请使用ISO 8601标准格式。多次讨论堆栈溢出,请搜索更多信息。您应该使用时间戳,并将UTC时间存储在实际数据库中。这是正确确定白天边界的唯一方法。实际上,许多数据库甚至不存储时区信息。这似乎是合乎逻辑的,但是考虑GMT + 2上的用户。此用户将日期视为2016年10月9日(因为日期将为2016年10月9日23:00)。这是正常情况还是我应该做一些安排:/没有时间的时区是否相关?日期代表什么。您的用户将输入一个日期,而您通过截断该时间将其有效地更改为另一个时间。客户端至少必须发送当前时区,以防在一个时区中输入日期,然后移动到另一个时区。然后将您的GMT时区转换为客户请求提供的时区。
ZonedDateTime todayMontrealStart = todayMontreal.atStartOfDay( ZoneId.of( "America/Montreal" ) ) ;