Java: 将带有时区缩写的日期字符串解析为日期对象

Java: Parse Date String with timezone abbreviations to Date object

我需要将带时区的日期字符串解析为 Date 对象。输入日期字符串模式为:

"MM/dd/yyyy hh:mm a z"  (eg: 04/30/2018 06:00 PM IST).

我使用了下面给出的代码。但它 returns 不正确的日期作为输出。

new SimpleDateFormat("MM/dd/yyyy hh:mm a z").parse("04/30/2018 06:00 PM IST")

当前输出:"Mon Apr 30 09:00:00 PDT 2018"。 预期输出:"Mon Apr 30 05:30:00 PDT 2018.

生成的 Date 对象将不包含任何时区信息。请参阅此

中的类似查询

您可能会得到正确的日期,但在您的 JVM 当前时区中。

如果您使用的是 Java 8,则会提供带时区的日期对象。看看ZonedDateTime, but for this you need a different kind of formatter while parsing (DateTimeFormatter)

那是因为timezone's abbreviations such as IST are ambiguous. IST is used in India, Israel and Ireland, and SimpleDateFormat assumes some of them as default, in obscure and undocumented ways (AFAIK). Actually, according to javadoc: "support of abbreviations is for JDK 1.1.x compatibility only and full names should be used".

让它工作的一种方法是任意选择一个时区并在格式化程序中设置它:

SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm a z");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
Date date = sdf.parse("04/30/2018 06:00 PM IST");

始终使用 Continent/Region 格式的名称,例如 Asia/Kolkata。这些名称是 IANA's timezones names,而且它们没有歧义,所以这使事情正常进行。

java.time API

如果您使用的是 Java 8 或更高版本,请切换到具有相同 类 和功能的 java.time API, which is much better. For Java 7 or lower, there's the Threeten Backport

在此 API 中,您必须设置所有首选时区的列表,以防名称不明确,例如 IST:

// prefered zones
Set<ZoneId> preferredZones = new HashSet<>();
preferredZones.add(ZoneId.of("Asia/Kolkata"));

DateTimeFormatter fmt = new DateTimeFormatterBuilder()
    // date and time
    .appendPattern("MM/dd/yyyy hh:mm a ")
    // zone (use set of prefered zones)
    .appendZoneText(TextStyle.SHORT, preferredZones)
    // use English, because different locales can affect timezones names
    .toFormatter(Locale.ENGLISH);

ZonedDateTime zdt = ZonedDateTime.parse("04/30/2018 06:00 PM IST", fmt);

如果还需要用java.util.Date,很容易转换:

// Java 8
Date d = Date.from(zdt.toInstant());

// Java 7 (Threenten Backport)
Date d = DateTimeUtils.toDate(zdt.toInstant());