Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.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
Java日期混淆_Java_Date - Fatal编程技术网

Java日期混淆

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:

我对约会真的很困惑

我有一个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: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));

这就足够满足您的需求了。

您可以选择几个选项

  • 如果您正在使用Java8(或者可以切换到Java8),那么新的 包
    java.time
    提供了更灵活的日期模型和类 会给你你所需要的
  • 如果您使用java 7或更低版本,我会尝试存储您的日期 在DB中作为字符串字段。例如,将日期格式化为字符串并保存 这样就可以将DB转换为varchar字段。当你读它的时候,只需要解析它 回到现在。这样,您的“2016年12月10日”将在任何情况下保持不变 时区没有任何额外的诡计
  • 最后,如果你坚持按日期保存,你可能会想要 请注意,您的所有日期始终存储在GMT+0中,而不考虑 活动位置。这样,同一位置的用户将始终看到 同一天。但不同位置的两个用户仍可能看到 同一字段作为不同的日期
  • 如果可能的话,我会建议第一个方案,如果不可能的话,我会建议第二个方案。第三,如果你的应用程序被不同时区的用户使用,它将变得越来越复杂


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

    关于日期时间问题的一些一般信息,而不是特定于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" ) ) ;