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.
上下左右搜索 - 找不到此问题的简单答案:
我有 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.