我知道也有类似的问题,但是我无法找到与我类似的示例。我了解了LocalDateTime
和ZonedDateTime
,但是我不知道如何告诉ZonedDateTime
解析日期的假定时区。
我正在从Java 7迁移到Java8。在我的代码中,我有一个像这样的方法:
public String changeTZ(String tzFrom, String tzTo, String dateToChange) {
ZoneId zoneFrom = ZoneId.of(tzFrom);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dateFormat.toPattern());
LocalDateTime localtDateAndTime = LocalDateTime.parse(dateToChange, formatter);
ZonedDateTime dateAndTimeINeed = ZonedDateTime.of(localtDateAndTime, zoneFrom );
ZonedDateTime rezDate = dateAndTimeINeed.withZoneSameInstant(ZoneId.of(tzTo));
return formatter.format(rezDate);
}
用法示例是:
String rez = changeTZ("CEST", "UTC", "2017-08-10 14:23:58");
如您所见,它以字符串形式接收datetime,时区日期在
tzFrom
变量中,而我需要TZ(toTo
变量)。在Java 7中执行此操作的代码是荒谬且复杂的,因此在此不再赘述。您能否告诉我如何在Java 8中实现相同功能而不更改方法接口(参数和返回类型)? DST呢?在Java 8中会自动处理吗?
请注意,该方法还支持“ CEST”,“ CET”,“ UTC”以及诸如“欧洲/伦敦”之类的标准时区。
最佳答案
Java 8使用IANA timezones names(始终采用Region/City
格式,例如America/Sao_Paulo
或Europe/Berlin
)。
避免使用简短的缩写(例如CEST
或PST
),因为它们是ambiguous and not standard。
实际上,这些名称不能与ZoneId
一起使用,主要是因为存在歧义(例如,CST可以是“中央标准时间”,“古巴标准时间”或“中国标准时间”)。实际上,其中的某些功能可能会由于追溯兼容性原因而起作用,但不能保证与所有功能都兼容。
我假设CEST是Central European Summer Time。 CEST当前有许多不同的国家(和时区),因此,如果您只是将“ CEST”传递给它,则API无法决定选择哪个时区。
这是因为时区包含区域在其历史记录中的所有不同偏移量。今天可能有许多国家/地区使用CEST,但是它们的历史在过去有所不同(有些国家/地区可能在不同的年份使用DST,或者使用不同的偏移量然后进行了更改,等等),这就是为什么每个国家/地区都有一个时区。
但是,要使用这样的短名称(如CEST
),您可以为每个短名称定义一些默认值(这是一个任意选择),并将这些选择放在地图中:
// map of custom zone names
Map<String, String> map = new HashMap<>();
// setting my arbitrary choices for each name
map.put("CEST", "Europe/Berlin"); // Berlin during DST period
map.put("CET", "Europe/Berlin"); // Berlin during non-DST period
// ... and so on
然后,您可以使用此映射创建
ZoneId
:// use the custom map to create the ZoneId
ZoneId zoneFrom = ZoneId.of(tzFrom, map);
...
// use the custom map to create the ZoneId
ZonedDateTime rezDate = dateAndTimeINeed.withZoneSameInstant(ZoneId.of(tzTo, map));
我选择了
Europe/Berlin
,但是您当然可以将其更改为所需的任何时区。通过调用ZoneId.getAvailableZoneIds()
,可以获得可用时区的列表(并选择最适合您的系统的时区)。使用上面的地图:
System.out.println(changeTZ("CEST", "UTC", "2017-08-10 14:23:58"));
此代码输出:
2017-08-10 12:23:58
请注意,
CEST
中的14:23(我选择为Europe/Berlin
)在UTC中是12:23,这是正确的,因为在8月中,柏林处于DST(偏移量为+02:00
)。ZoneId
和ZonedDateTime
类自动处理DST效果。您可以通过选择1月的日期(柏林DST无效)来检查日期:// January is not DST, so use CET
System.out.println(changeTZ("CET", "UTC", "2017-01-10 14:23:58"));
输出为:
2017-01-10 13:23:58
一月份,柏林不在DST中,因此偏移量为
+01:00
,则柏林的14:23在UTC变为13:23。当然,理想的做法是始终使用全名(例如
Europe/Berlin
),但是如果您无法控制输入,则可以使用自定义映射。Java 8也有一个built-in predefined map,但是与其他任何预定义的内容一样,这些选择是任意的,不一定是您需要的那些。