Java.util.date 获取客户时区的实际日期

Java.util.date get the actual date at client timezone

上下左右搜索 - 找不到此问题的简单答案:

我有 java.util.Date 个实例,它的值来自 mySQL。

我还有登录用户的时区代码。

我需要获取用户时区的实际时间。

例如:

我的服务器机器时区是GMT+2。

我在 DB 中的日期值为:2017-02-09 16:38:58.000

根据我的服务器机器时区,我将其放入 日期实例 为:2017-02-09T16:38:58.000+0200

现在我需要知道如果出现以下情况该怎么办:

例如,如果我的客户时区代码是 GMT+4,我想得到:

2017-02-09 20:38:58.000

纯日期,符合我的时区,不包含“+4”或"GMT"指示。

简而言之:将我的 java.util.date 转换为适合特定时区的纯日期。

听起来很简单?看了很多文档后,我已经不确定这是否真的很简单。

java.util.Date 不存储任何时区。它只存储自 'epoch' 以来的毫秒数,即 1970 年 1 月 1 日,00:00:00 UTC。

因此,你所要做的就是知道你的服务器机器的时区,找到这个时区和你想要转换到的时区之间的时间段,加上或减去时间段。

更新:

int clientGMT = 4; //GMT you want to convert to
int serverGMT = 2; //server's GMT
int delta = clientGMT - serverGMT; //delta between the dates

//assume this is the date in GMT + 2 received from the server
Date d1 = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss").parse("12.03.2019 13:00:00");

//... and you want to convert it to GMT + 4 (client side's time zone)
Date resultDate = new Date(d1.getTime() + delta * 3600000);

P.S. 是的,你必须手动操作时区,正如我上面所说,java.util.Date 不存储这些信息(每个日期都是假定为 UTC)。

时间戳(带时区)

据我所知,您的数据库中的日期时间为 UTC,但是当您检索它时,您(错误地)收到 2017-02-09T16:38:58.000+02:00。

首先,如果可以,请将 MySQL 数据库列的数据类型更改为 timestamp(在其他一些数据库中,它会被称为 timestamp with time zone)。这将确保 MySQL 知道时间是 UTC 时间,并且应该使您能够将它们检索为 正确的时间点 而不是错误的一天中的正确时间时区。这反过来将为您提供转换为客户端时区的最佳起点。

java.time

其次,从 java.time、现代 Java 日期和时间 API 中将您的值检索到适当的类型中。避免使用 java.util.Date,因为它设计不佳且无法处理不同的时区。例如,如果您的数据库数据类型是 datetime:

    LocalDateTime dateTime = yourResultSet.getObject("your_col", LocalDateTime.class);

LocalDateTime是没有时区的日期和时间,所以不会弄错时区。提供您知道正确的偏移量:

    OffsetDateTime odt = dateTime.atOffset(ZoneOffset.UTC);

转换为客户端时区:

    ZoneId clientTimeZone = ZoneId.of("Indian/Reunion");
    ZonedDateTime clientDateTime = odt.atZoneSameInstant(clientTimeZone);

    System.out.println(clientDateTime);

2017-02-09T20:38:58+04:00[Indian/Reunion]

请自己使用 region/city 格式的实时时区,而不是像 +04:00 这样的偏移量。它更容易理解,也更适合未来。 Indian/Reunion只是一个例子,当然,请为您的客户使用正确的那个。

上面的ZonedDateTime里面有偏移量和时区。建议保持这种状态,我认为它不会造成任何伤害。客户端始终可以选择不显示它。如果你还坚持,再转成LocalDateTime

    LocalDateTime clientDateTimeWithoutOffset = clientDateTime.toLocalDateTime();
    System.out.println(clientDateTimeWithoutOffset);

2017-02-09T20:38:58

如果数据库数据类型是timestamp:

    OffsetDateTime odt = yourResultSet.getObject("your_col", OffsetDateTime.class);

这样就省去了上面的第一步。余数相同

Link

Oracle tutorial: Date Time 解释如何使用 java.time.