当我使用 yyyy-MM-dd'T'HH:mm:ss 解析时,它工作正常,但是当我
解析yyyy-MM-dd'T'HH:mm:ssXXX ParseException 被抛出。
什么是解析日期的正确格式以及究竟是什么
这两种格式有什么区别?
我们先来看看yyyy-MM-dd'T'HH:mm:ss:
检查documentation 中的以下行(重点是我的):
从给定字符串的开头解析文本以生成日期。
该方法可能不会使用给定字符串的整个文本。
所以,基本上,yyyy-MM-dd'T'HH:mm:ss 格式只考虑到 2014-12-03T10:05:59 并忽略秒和时区偏移信息的分数。
yyyy-MM-dd'T'HH:mm:ssXXX 有什么问题?
在这种格式中,您已正确放置时区偏移的符号,但错过了几分之一秒的符号。
使用SimpleDateFormat 解析它的正确格式是什么?
简短的回答:无
长答案: SimpleDateFormat 无法正确处理超过毫秒的精度(即 . 之后的 3 位数字),因此没有任何格式可以正确解析它。使其正确的唯一方法是将. 之后的数字保留为最多三位,例如2014-12-03T10:05:59.564+08:00、2014-12-03T10:05:59.56+08:00 等。让我们看看SimpleDateFormat 将如何错误地解析2014-12-03T10:05:59.5646+08:00。
SimpleDateFormat 将. 之后的数字视为毫秒数(而不是现代日期时间 API 所考虑的秒数)。因此,计算如下:
5646 milliseconds = 5 seconds + 646 milliseconds
2014-12-03T10:05:59 + 5 seconds + 646 milliseconds = 2014-12-03T10:06:04.646
让我们使用代码来验证它:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
String strDateTime = "2014-12-03T10:05:59.5646+08:00";
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
Date date = sdf.parse(strDateTime);
sdf.setTimeZone(TimeZone.getTimeZone("GMT+08:00"));
System.out.println(sdf.format(date));
}
}
输出:
2014-12-03T10:06:04.646+08:00
java.time
随着 2014 年 3 月 Java SE 8 的发布,过时且容易出错的旧版 Date-Time API(java.util Date-Time 类型及其格式类型,SimpleDateFormat 等)被 java.time 取代,modern Date-Time API*。强烈建议停止使用旧版 API 并切换到此新 API。
使用现代 API java.time 的解决方案:
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
OffsetDateTime odt = OffsetDateTime.parse("2014-12-03T10:05:59.5646+08:00");
System.out.println(odt);
}
}
输出:
2014-12-03T10:05:59.564600+08:00
是不是很酷?
现代日期时间 API 基于 ISO 8601,只要日期时间字符串符合 ISO 8601 标准,就不需要明确使用 DateTimeFormatter 对象。
顺便说一句,如果你需要将OffsetDateTime的这个对象转换为java.util.Date的对象,你可以这样做:
Date date = Date.from(odt.toInstant());
从Trail: Date Time了解更多关于java.time,modern Date-Time API*。
* 出于任何原因,如果您必须坚持使用 Java 6 或 Java 7,您可以使用 ThreeTen-Backport,它将大部分 java.time 功能向后移植到 Java 6 和 7 . 如果您正在为一个 Android 项目工作并且您的 Android API 级别仍然不符合 Java-8,请检查 Java 8+ APIs available through desugaring 和 How to use ThreeTenABP in Android Project。