Java: 日期解析,为什么会报错
Java: Date parsing, why do I get an error
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SZ");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
Date test = dateFormat.parse(text);
前三行工作正常。当我再次尝试将字符串解析为日期时,出现错误。我该如何解决?
错误如下所示:
Caused by: java.text.ParseException: Unparseable date: "2018-02-07T15:32:13.214+0100"
at java.text.DateFormat.parse(DateFormat.java:366) ~[na:1.8.0_151]
at TimeRange.parseDateFromIsoString(TimeRange.java:33) ~[classes/:na]
我删除了与时区相关的简单日期格式的 Z,给出了正确的结果放下面是片段。
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
try {
Date test = dateFormat.parse(text);
} catch (ParseException e) {
e.printStackTrace();
}
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
try {
Date test = dateFormat.parse(text);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
对我有用。在模式末尾使用 "SSSZ" 而不是 "SZ"。
我想贡献现代答案。因为我不鼓励使用 SimpleDateFormat
,所以稍后会详细介绍。
java.time
OffsetDateTime dateTime = OffsetDateTime.now(ZoneId.of("Europe/Rome"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxx");
String text = dateTime.format(formatter);
OffsetDateTime test = OffsetDateTime.parse(text, formatter);
这会生成一个类似于 2018-02-07T17:51:21.087+0100
的字符串,非常接近我认为您在问题中所追求的内容,并且可以很好地解析它。在格式模式字符串中使用 SSS
它总是在秒上产生 3 位小数,并且通过解析也需要恰好 3 位小数。例如,您可以使用 S
或 SSSSSS
来获得 1 位或 6 位小数。在我的 Java 9 上,OffsetDateTime.now()
的精度为 6 位小数(微秒),因此如果我指定的更少,我就会失去格式精度。
编辑:为了向后兼容,您不能使用以下内容,但对于阅读本文的任何人,我想提供一个没有显式格式化程序的变体:
String text = dateTime.toString();
OffsetDateTime test = OffsetDateTime.parse(text);
生成的字符串中的两个不同点是:
- 它生成尽可能多的 3 位小数组以呈现精度。通常我的 Java 8 有 3 位小数,我的 Java 9 有 6 位小数,但有时它会达到毫秒数并产生更少的小数。它解析一个包含从 0 到 9 小数的所有内容的字符串,因此这在解析中不会出现问题。而且我总是保留原始
OffsetDateTime
对象的完整预测。
- 与 UTC 的偏移量用冒号呈现,例如
+01:00
。
你的代码出了什么问题?
SimpleDateFormat
class 早已过时且出了名的麻烦,所以即使你目前没有遇到问题,我仍然建议你放弃它并使用 java.time
,现代 Java 日期和时间 API,而不是像我在上面所做的那样。
旧 SimpleDateFormat
和现代 DateTimeFormatter
之间的一个区别是,虽然 S
在现代格式化程序中表示秒的分数,但在 SimpleDateFormat
中表示毫秒,所以除三之外的任何其他数字都是没有意义的。但是,它接受其他数字。格式化时,您的格式化程序为毫秒生成了足够的数字,例如 89
如果有 21.089 秒或 214
当您有 13.214 时 question.The 前者是不正确的,21.089 秒是呈现为 21.89
。我坚信,当你只有一个 S
时,三位数的毫秒数会导致你的解析失败。在我的 Java 8 和 9 上,它可以工作并且还将 21.89
解析为 21 秒 89 毫秒,因此错误会消失。
此行为与 Java9 文档一致,该文档指出:“对于格式设置,模式字母的数量是最小数字位数,较短的数字将用零填充到该数量。对于解析,模式字母的数量将被忽略,除非需要分隔两个相邻字段。”
Link
- Oracle tutorial: Date Time 解释如何使用
java.time
。
SimpleDateFormat
documentation for Java 9
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SZ");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
Date test = dateFormat.parse(text);
前三行工作正常。当我再次尝试将字符串解析为日期时,出现错误。我该如何解决?
错误如下所示:
Caused by: java.text.ParseException: Unparseable date: "2018-02-07T15:32:13.214+0100"
at java.text.DateFormat.parse(DateFormat.java:366) ~[na:1.8.0_151]
at TimeRange.parseDateFromIsoString(TimeRange.java:33) ~[classes/:na]
我删除了与时区相关的简单日期格式的 Z,给出了正确的结果放下面是片段。
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
try {
Date test = dateFormat.parse(text);
} catch (ParseException e) {
e.printStackTrace();
}
Date date = new Date();
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");//2018-02-05T18:00:51.001+0000
String text = dateFormat.format(date);
try {
Date test = dateFormat.parse(text);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
对我有用。在模式末尾使用 "SSSZ" 而不是 "SZ"。
我想贡献现代答案。因为我不鼓励使用 SimpleDateFormat
,所以稍后会详细介绍。
java.time
OffsetDateTime dateTime = OffsetDateTime.now(ZoneId.of("Europe/Rome"));
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSxx");
String text = dateTime.format(formatter);
OffsetDateTime test = OffsetDateTime.parse(text, formatter);
这会生成一个类似于 2018-02-07T17:51:21.087+0100
的字符串,非常接近我认为您在问题中所追求的内容,并且可以很好地解析它。在格式模式字符串中使用 SSS
它总是在秒上产生 3 位小数,并且通过解析也需要恰好 3 位小数。例如,您可以使用 S
或 SSSSSS
来获得 1 位或 6 位小数。在我的 Java 9 上,OffsetDateTime.now()
的精度为 6 位小数(微秒),因此如果我指定的更少,我就会失去格式精度。
编辑:为了向后兼容,您不能使用以下内容,但对于阅读本文的任何人,我想提供一个没有显式格式化程序的变体:
String text = dateTime.toString();
OffsetDateTime test = OffsetDateTime.parse(text);
生成的字符串中的两个不同点是:
- 它生成尽可能多的 3 位小数组以呈现精度。通常我的 Java 8 有 3 位小数,我的 Java 9 有 6 位小数,但有时它会达到毫秒数并产生更少的小数。它解析一个包含从 0 到 9 小数的所有内容的字符串,因此这在解析中不会出现问题。而且我总是保留原始
OffsetDateTime
对象的完整预测。 - 与 UTC 的偏移量用冒号呈现,例如
+01:00
。
你的代码出了什么问题?
SimpleDateFormat
class 早已过时且出了名的麻烦,所以即使你目前没有遇到问题,我仍然建议你放弃它并使用 java.time
,现代 Java 日期和时间 API,而不是像我在上面所做的那样。
旧 SimpleDateFormat
和现代 DateTimeFormatter
之间的一个区别是,虽然 S
在现代格式化程序中表示秒的分数,但在 SimpleDateFormat
中表示毫秒,所以除三之外的任何其他数字都是没有意义的。但是,它接受其他数字。格式化时,您的格式化程序为毫秒生成了足够的数字,例如 89
如果有 21.089 秒或 214
当您有 13.214 时 question.The 前者是不正确的,21.089 秒是呈现为 21.89
。我坚信,当你只有一个 S
时,三位数的毫秒数会导致你的解析失败。在我的 Java 8 和 9 上,它可以工作并且还将 21.89
解析为 21 秒 89 毫秒,因此错误会消失。
此行为与 Java9 文档一致,该文档指出:“对于格式设置,模式字母的数量是最小数字位数,较短的数字将用零填充到该数量。对于解析,模式字母的数量将被忽略,除非需要分隔两个相邻字段。”
Link
- Oracle tutorial: Date Time 解释如何使用
java.time
。 SimpleDateFormat
documentation for Java 9