知道是什么原因造成的……</p>
三个和四个字母的时区缩写是一个众所周知的问题。IST 的第三种解释是爱尔兰标准时间(欧洲/都柏林)。我不确切知道是什么导致一个 JVM 更喜欢一种解释而不是另一种解释。在至少一种情况下,我看到它比其他解释更喜欢它的默认时区设置。因此,如果您的开发机器具有亚洲/加尔各答时区设置而您的生产机器没有,这可能就是解释。但是,我不会将此作为确定的事实,并且我希望编写足够健壮的代码以在具有不同时区设置的计算机和 JVM 上运行。
......以及如何解决它。
理想的解决方案:避免获取包含三个或四个字母时区缩写的日期时间字符串。首选与 UTC 的区域偏移和/或大陆/城市形式的时区名称。我承认这并不总是可能的。
鉴于您的输入字符串,因为SimpleDateFormat
和TimeZone
已经过时,并且现代 Java 日期和时间 API 对程序员更加友好,并且您还使用ZonedDateTime
类(现代 API 的一部分)标记了您的问题,让我们首先采用现代解决方案:
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendPattern("EEE MMM dd HH:mm:ss ")
.appendZoneText(TextStyle.SHORT, Collections.singleton(ZoneId.of("Asia/Kolkata")))
.appendPattern(" uuuu")
.toFormatter(Locale.ROOT);
ZonedDateTime dateTime = ZonedDateTime.parse(input, dtf);
System.out.println(dateTime.getZone());
它打印:
Asia/Kolkata
我传递给的第二个参数appendZoneText()
是一组首选时区。在文档中它说“如果要解析的纹理区域名称不是唯一的,则将使用匹配的首选区域 ID。” 这就是我们在这里所追求的。
在我的计算机上,我还能够使用过时的类在您的代码中解决问题。我在解析之前插入了以下行。
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
但是,旧类的文档比较模糊,所以我不太确定这个解决方案总是有效的。
顺便说一句,无论您使用旧类还是现代类,我建议您始终为解析提供明确的语言环境。“Mon”和“Jun”是英文的,因此除非您指定了语言环境,否则解析将无法在具有非英语语言环境设置的计算机上进行。让我猜猜,您的日期字符串不是英语,因为它来自说英语的语言环境,而只是因为英语是计算中的通用语言。如果是这样,我认为Locale.ROOT
合适。我已经在我的代码中使用它。要在您的中使用它,请将其作为参数添加到构造函数:
SimpleDateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ROOT);
Locale.ENGLISH
像其他英语语言环境一样工作。