parse method expects a String in a specific format,如2007-12-03T10:15:30+01:00[Europe/Paris]。由于您的输入格式不同,您需要DateTimeFormatter。
需要注意的一个细节是 API 使用 IANA timezones names(始终采用 Continent/City 格式,例如 America/Sao_Paulo 或 Europe/Berlin)。
避免使用三个字母的缩写(如CST 或PST),因为它们是ambiguous and not standard。
API 使用特定 ID 进行一些例外处理,并为它们提供一些默认值。对于PDT,默认为America/Los_Angeles。
另一个细节是,在下面的例子中,我在模式中使用了小写的hh:格式有AM/PM指示,所以我认为hh是正确的模式,因为its value is from 1 to 12(常见的值是有 AM/PM 指示灯)。
如果你使用大写的HH,它允许从0到23的值(在上午/下午使用这个值并不常见),并且如果输入包含像@987654339这样的小时,它会抛出异常@。
所以代码会是这样的:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("MM/dd/yyyy hh:mm a (zzz)");
ZonedDateTime z = ZonedDateTime.parse("06/24/2017 07:00 AM (PDT)", fmt);
System.out.println(z);
输出是:
2017-06-24T07:00-07:00[美国/洛杉矶]
但并非所有 3 个字母的时区名称都能被 API 识别并引发异常。
无论如何,PDT 中还有其他时区(例如 America/Vancouver) - 您可以通过调用 ZoneId.getAvailableZoneIds() 获取所有时区的列表。如果您想使用不同的时区作为默认时区,您可以创建一组首选时区并使用该组构建格式化程序:
Set<ZoneId> preferredZones = new HashSet<>();
// set America/Vancouver as preferred zone
preferredZones.add(ZoneId.of("America/Vancouver"));
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// pattern
.appendPattern("MM/dd/yyyy hh:mm a (")
// append timezone with set of prefered zones
.appendZoneText(TextStyle.SHORT, preferredZones)
// finish the pattern
.appendPattern(")")
// create formatter
.toFormatter();
System.out.println(ZonedDateTime.parse("06/24/2017 07:00 AM (PDT)", fmt));
API 将使用首选区域集(在本例中为 America/Vancouver)而不是默认区域集(America/Los_Angeles)。输出将是:
2017-06-24T07:00-07:00[美国/温哥华]
目前尚不清楚输入 String 的来源。如果您无法控制它们的格式,那么您别无选择:它们需要以这种方式解析。然后您可以使用withZoneSameInstant 方法将其转换为另一个时区:
// parse the input string
ZonedDateTime z = ZonedDateTime.parse("06/24/2017 07:00 AM (PDT)", fmt);
// convert to another timezone
ZonedDateTime other = z.withZoneSameInstant(ZoneId.of("America/Sao_Paulo")); // 2017-06-24T11:00-03:00[America/Sao_Paulo]
other 的值将是 2017-06-24T11:00-03:00[America/Sao_Paulo]。
但如果您可以控制输出,最好 (IMO) 在内部使用 UTC (java.time.Instant),并且仅在向用户显示时转换为某个时区:
// convert ZonedDateTime to instant
ZonedDateTime z = // parse input
// convert to UTC (Instant is always in UTC)
Instant instant = z.toInstant();
// internally work with instant (as it's always in UTC)
// convert instant to some timezone only when necessary (like displaying to users)
ZonedDateTime converted = instant.atZone(ZoneId.of("Europe/London"));