我知道也有类似的问题,但是我无法找到与我类似的示例。我了解了LocalDateTimeZonedDateTime,但是我不知道如何告诉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_PauloEurope/Berlin)。
避免使用简短的缩写(例如CESTPST),因为它们是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)。

ZoneIdZonedDateTime类自动处理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,但是与其他任何预定义的内容一样,这些选择是任意的,不一定是您需要的那些。

10-06 16:02
查看更多