java 中的日期格式化程序
Dateformatter in java
我正在使用以下代码来格式化毫秒分辨率日期字符串。它适用于 2018-09-14T13:05:21.329Z
但不适用于 2018-09-14T13:05:21.3Z
。任何人都可以提出原因以及如何纠正它吗?
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
SimpleDateFormat sdfDestination = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date parsedDate = formatter.parse(date);
String destDate = sdfDestination.format(parsedDate);
return destDate;
} catch (java.text.ParseException parseException) {
logger.error("Parse Exception occured while converting publication time to date "
+ "format 'yyyy-MM-dd HH:mm:ss'", parseException);
}
我遇到以下异常:
java.text.ParseException: Unparseable date: "2018-09-14T13:05:21.3Z"
at java.text.DateFormat.parse(Unknown Source) ~[na:1.8.0_181]
at com.noordpool.api.implementation.utility.Utility.parseDate(Utility.java:136) [classes/:na]
at com.noordpool.api.implementation.utility.Utility.parseMessage(Utility.java:77) [classes/:na]
我能看到的唯一可能的问题是您传递的毫秒数不正确,程序不知道该怎么做。
所以格式化程序的最后一部分用毫秒和时区表示为 .SSSX
但是它如何评估 3Z 的输入呢?我的意思是,你是说它是 300 时区 Z,还是说它是 003 时区 Z,或者更糟,尝试将其解析为 3Z,希望你能看到你不能将“3Z”变成数字。
为了解决这个问题,我会验证您的输入 'date' 并确保毫秒部分始终为 3 位数字,这消除了歧义并且程序始终知道您的意思是“300 毫秒,时区 Z” .
你唯一的问题是你为SimpleDateFormat
使用了错误的模式,你需要改变:
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
收件人:
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
因为 date
字符串中使用的 Z
意味着 "zero hour offset" 所以你只需要在你的模式中将它作为 'Z'
传递。
这是 a working demo,格式正确。
编辑:
为了让事情适用于不同的语言环境和时区,您需要在创建 SimpleDateFormat
实例时使用适当的 Locale
,代码应该是这样的:
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
java8 中存在一个问题,您使用格式化程序指定的字符数应该完全匹配(文档中未指定)。
您可以使用三种不同的格式化程序并使用嵌套异常,如下所示:
DateFormat format1 = new SimpleDateFormat("y-M-d'T'H:m:s.SX");
DateFormat format2 = new SimpleDateFormat("y-M-d'T'H:m:s.SSX");
DateFormat format3 = new SimpleDateFormat("y-M-d'T'H:m:s.SSSX");
Date parsedDate;
try {
// Parsing for the case - 2018-09-14T13:05:21.3Z
parsedDate = format1.parse(date);
} catch (ParseException e1) {
try {
// Parsing for the case - 2018-09-14T13:05:21.32Z
parsedDate = format2.parse(date);
} catch (ParseException e2) {
try {
// Parsing for the case - 2018-09-14T13:05:21.329Z
parsedDate = format3.parse(date);
} catch (ParseException e2) {
//The input date format is wrong
logger.error("Wrong format for date - " + date);
}
}
}
java.time
DateTimeFormatter dtfDestination
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
String date = "2018-09-14T13:05:21.3Z";
String destDate = Instant.parse(date)
.atZone(ZoneId.of("Indian/Comoro"))
.format(dtfDestination);
System.out.println(destDate);
此片段的输出是:
2018-09-14 16:05:21
如果不是 Indian/Comoro,请替换为正确的时区,因为正确的输出取决于使用正确的时区。如果要使用 JVM 的默认时区,请指定 ZoneId.systemDefault()
,但请注意,可以随时从程序的其他部分或同一 JVM 中的其他程序 运行 更改默认值。
我正在利用你的字符串 "2018-09-14T13:05:21.3Z"
是 ISO 8601 格式的事实,java.time 的 类 解析为默认格式,也就是说,没有任何显式格式化程序。 Instant.parse
接受从 0 到 9 秒的任何小数位,因此像您一样给它一个只有 1 位小数的字符串是没有问题的。相比之下,老式的 SimpleDateFormat
无法完全精确地解析秒的 1 位小数,因为它采用模式字母(大写)S
来表示毫秒,因此 .3
将被解析为 3 毫秒,而不是十分之三秒,正如它的意思。
已经正确诊断并解释了你得到异常的原因。
您使用的日期时间 类 DateFormat
、SimpleDateFormat
和 Date
都早已过时,尤其是 SimpleDateFormat
是出了名的麻烦。由于您似乎在使用 Java 8(即使您没有使用),我建议您完全避免使用 类 并改用 java.time。
链接
- Oracle tutorial: Date Time 解释如何使用
java.time
。
- Wikipedia article: ISO 8601
我正在使用以下代码来格式化毫秒分辨率日期字符串。它适用于 2018-09-14T13:05:21.329Z
但不适用于 2018-09-14T13:05:21.3Z
。任何人都可以提出原因以及如何纠正它吗?
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
SimpleDateFormat sdfDestination = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date parsedDate = formatter.parse(date);
String destDate = sdfDestination.format(parsedDate);
return destDate;
} catch (java.text.ParseException parseException) {
logger.error("Parse Exception occured while converting publication time to date "
+ "format 'yyyy-MM-dd HH:mm:ss'", parseException);
}
我遇到以下异常:
java.text.ParseException: Unparseable date: "2018-09-14T13:05:21.3Z"
at java.text.DateFormat.parse(Unknown Source) ~[na:1.8.0_181]
at com.noordpool.api.implementation.utility.Utility.parseDate(Utility.java:136) [classes/:na]
at com.noordpool.api.implementation.utility.Utility.parseMessage(Utility.java:77) [classes/:na]
我能看到的唯一可能的问题是您传递的毫秒数不正确,程序不知道该怎么做。
所以格式化程序的最后一部分用毫秒和时区表示为 .SSSX
但是它如何评估 3Z 的输入呢?我的意思是,你是说它是 300 时区 Z,还是说它是 003 时区 Z,或者更糟,尝试将其解析为 3Z,希望你能看到你不能将“3Z”变成数字。
为了解决这个问题,我会验证您的输入 'date' 并确保毫秒部分始终为 3 位数字,这消除了歧义并且程序始终知道您的意思是“300 毫秒,时区 Z” .
你唯一的问题是你为SimpleDateFormat
使用了错误的模式,你需要改变:
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
收件人:
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
因为 date
字符串中使用的 Z
意味着 "zero hour offset" 所以你只需要在你的模式中将它作为 'Z'
传递。
这是 a working demo,格式正确。
编辑:
为了让事情适用于不同的语言环境和时区,您需要在创建 SimpleDateFormat
实例时使用适当的 Locale
,代码应该是这样的:
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
java8 中存在一个问题,您使用格式化程序指定的字符数应该完全匹配(文档中未指定)。 您可以使用三种不同的格式化程序并使用嵌套异常,如下所示:
DateFormat format1 = new SimpleDateFormat("y-M-d'T'H:m:s.SX");
DateFormat format2 = new SimpleDateFormat("y-M-d'T'H:m:s.SSX");
DateFormat format3 = new SimpleDateFormat("y-M-d'T'H:m:s.SSSX");
Date parsedDate;
try {
// Parsing for the case - 2018-09-14T13:05:21.3Z
parsedDate = format1.parse(date);
} catch (ParseException e1) {
try {
// Parsing for the case - 2018-09-14T13:05:21.32Z
parsedDate = format2.parse(date);
} catch (ParseException e2) {
try {
// Parsing for the case - 2018-09-14T13:05:21.329Z
parsedDate = format3.parse(date);
} catch (ParseException e2) {
//The input date format is wrong
logger.error("Wrong format for date - " + date);
}
}
}
java.time
DateTimeFormatter dtfDestination
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
String date = "2018-09-14T13:05:21.3Z";
String destDate = Instant.parse(date)
.atZone(ZoneId.of("Indian/Comoro"))
.format(dtfDestination);
System.out.println(destDate);
此片段的输出是:
2018-09-14 16:05:21
如果不是 Indian/Comoro,请替换为正确的时区,因为正确的输出取决于使用正确的时区。如果要使用 JVM 的默认时区,请指定 ZoneId.systemDefault()
,但请注意,可以随时从程序的其他部分或同一 JVM 中的其他程序 运行 更改默认值。
我正在利用你的字符串 "2018-09-14T13:05:21.3Z"
是 ISO 8601 格式的事实,java.time 的 类 解析为默认格式,也就是说,没有任何显式格式化程序。 Instant.parse
接受从 0 到 9 秒的任何小数位,因此像您一样给它一个只有 1 位小数的字符串是没有问题的。相比之下,老式的 SimpleDateFormat
无法完全精确地解析秒的 1 位小数,因为它采用模式字母(大写)S
来表示毫秒,因此 .3
将被解析为 3 毫秒,而不是十分之三秒,正如它的意思。
您使用的日期时间 类 DateFormat
、SimpleDateFormat
和 Date
都早已过时,尤其是 SimpleDateFormat
是出了名的麻烦。由于您似乎在使用 Java 8(即使您没有使用),我建议您完全避免使用 类 并改用 java.time。
链接
- Oracle tutorial: Date Time 解释如何使用
java.time
。 - Wikipedia article: ISO 8601