将Java不支持的UT时区替换为UTC是否安全?
邮件Date头中UT时区解析问题
我在解析邮件的Date头字段时,遇到了这样的格式:
Mon, 18 Jul 2011 05:05:53 UT
这个格式看起来符合Java文档的描述,但用SimpleDateFormat解析时却失败了。我写了如下测试代码:
public void testParser() throws ParseException { SimpleDateFormat FULL_FORMAT = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z", Locale.ENGLISH); try { String baddate = "Mon, 18 Jul 2011 05:05:53 UT"; System.out.println("NOW: " + FULL_FORMAT.format(new Date())); System.out.println("THEN: " + FULL_FORMAT.parse(baddate + "C")); System.out.println("---"); System.out.println(FULL_FORMAT.parse(baddate)); } catch (Exception e) { e.printStackTrace(System.out); } System.out.println("UTC: " + TimeZone.getTimeZone("UTC")); System.out.println("UT: " + TimeZone.getTimeZone("UT")); }
测试输出如下:
[INFO] Running de.e_nexus.web.rm.mail.TestDateParser NOW: Thu, 29 Feb 2024 11:50:52 +0100 THEN: Mon Jul 18 07:05:53 CEST 2011 --- java.text.ParseException: Unparseable date: "Mon, 18 Jul 2011 05:05:53 UT" at java.base/java.text.DateFormat.parse(DateFormat.java:399) at de.e_nexus.web.rm.mail/de.e_nexus.web.rm.mail.TestDateParser.testParser(TestDateParser.java:17) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at org.apache.maven.surefire.junit.PojoTestSetExecutor.executeTestMethod(PojoTestSetExecutor.java:104) at org.apache.maven.surefire.junit.PojoTestSetExecutor.execute(PojoTestSetExecutor.java:63) at org.apache.maven.surefire.junit.JUnit3Provider.executeTestSet(JUnit3Provider.java:131) at org.apache.maven.surefire.junit.JUnit3Provider.invoke(JUnit3Provider.java:93) at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:385) at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:162) at org.apache.maven.surefire.booter.ForkedBooter.run(ForkedBooter.java:507) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:495) UTC: sun.util.calendar.ZoneInfo[id="UTC",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null] UT: sun.util.calendar.ZoneInfo[id="GMT",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null] [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.044 s -- in de.e_nexus.web.rm.mail.TestDateParser
UT时区确实存在(和UTC功能等价),但Java的SimpleDateFormat不支持用它来解析日期。请问把Date头里的UT替换成UTC是否安全?
完全安全,理由如下:
- 时区等价性:UT(世界时)和UTC(协调世界时)在实际应用中几乎没有差异,对于邮件日期这类场景,两者表示的时间完全一致。从测试输出也能看到,
TimeZone.getTimeZone("UT")返回的是GMT时区实例,偏移量为0,和UTC的偏移量完全相同。 - 邮件标准兼容性:邮件的Date头遵循RFC规范,RFC 5322明确允许使用
UTC作为时区标识,同时也兼容UT的写法,但Java的旧日期API(SimpleDateFormat)对时区标识的支持有限,只识别UTC而不识别UT。 - 解决方案可行:在解析前将字符串中的
UT替换为UTC,不会改变原始时间的含义,同时能让SimpleDateFormat正常解析。如果使用Java 8及以上的新日期API(java.time包下的DateTimeFormatter),还可以直接配置解析器支持UT标识,示例代码如下:
DateTimeFormatter formatter = new DateTimeFormatterBuilder() .appendPattern("EEE, d MMM yyyy HH:mm:ss ") .appendZoneText(TextStyle.SHORT, Set.of(ZoneOffset.UTC)) .toFormatter(Locale.ENGLISH); ZonedDateTime.parse("Mon, 18 Jul 2011 05:05:53 UT", formatter);
不过如果只是兼容旧代码,直接替换UT为UTC是最简单可靠的方案。
内容的提问来源于stack exchange,提问作者Grim
相关产品推荐
相关产品推荐

