问题描述
根据 http://apiux.com/2013/03/20/5-laws-api-dates-and-times/ 我们应该使用ISO 8601格式化日期。 我系统上的输出是:
$ date --iso-8601=ns
2020-10-29T10:38:59,112768965+01:00
哪个Java格式化程序可以正确解析此字符串? 我已经尝试过DateTimeFormatter.ISO_OFFSET_DATE_TIME和其他一些,他们不喜欢这种格式。我希望应该立即支持这种格式,就像Oracle在其页面https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html中声称的那样,但不是。
另一件事是Spring宣布广泛支持日期格式: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.3-Release-Notes#date-time-conversion-in-web-applications。然后,我可以将所有属性设置为“ iso”。但是它到底是哪种格式,在哪里使用?
我在这里看到两个问题。
- 一个是https://github.com/FasterXML/jackson-databind/issues/2643(带或不带分号的偏移量)
- 第二个是纳秒/毫秒的存在(我想使用它们)
我希望在整个应用程序中采用一致的日期格式方法,并且希望使用标准轻松地与世界其他地区集成。我该怎么用?
编辑:最后碰巧要考虑一些事情:
- Linux控制台中的示例是人为的,因为在现实世界中我没有注意到这种带有“,”的格式。事实证明,Java世界中对它的支持略有不一致
- ObjectMapper,modelmapper和OffsetDateTime使Date对象转换不同,尤其是转换为ISO格式(“ Z”或“ 00:00”)
- Java中也存在“ 0000”形式的偏移量定义,我必须修复转换
解决方法
ISO 8601-1允许,
和.
都作为小数点分隔符,尽管实际上这是我第一次看到,
实际使用。 JDK 11中的默认格式仅支持解析.
(即使文档说十进制分隔符已本地化)。要处理这种格式,您可以选择以下几种方式:
- 在解析之前修改字符串:
OffsetDateTime.parse(value.replaceAll(",","."));
- 定义自定义格式:
new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(ISO_LOCAL_DATE)
.appendLiteral('T')
.appendValue(HOUR_OF_DAY,2)
.appendLiteral(':')
.appendValue(MINUTE_OF_HOUR,2)
.optionalStart()
.appendLiteral(':')
.appendValue(SECOND_OF_MINUTE,2)
.optionalStart()
.appendLiteral(',')
.appendFraction(NANO_OF_SECOND,9,false)
.parseLenient()
.appendOffsetId()
.toFormatter()
.parse(value)
- 使用使用
,
分隔符的语言环境(在JDK 15中已确认工作):
DateTimeFormatter.ISO_OFFSET_DATE_TIME.localizedBy(Locale.FRANCE).parse(value);
似乎没有一种方法可以定义允许,
或.
但不允许两者都使用的格式。您将不得不尝试一种捕获异常然后再尝试另一种,或者检测异常所采用的格式(例如value.contains(",")
)并使用适当的格式化程序。
如果您的字符串在逗号后总是有9个小数,只需在格式模式字符串中指定一个逗号即可:
DateTimeFormatter isoWithCommaFormatter = DateTimeFormatter
.ofPattern("uuuu-MM-dd'T'HH:mm:ss,SSSSSSSSSXXX");
String iso = "2020-10-29T10:38:59,112768965+01:00";
OffsetDateTime odt = OffsetDateTime.parse(iso,isoWithCommaFormatter);
System.out.println(odt);
输出:
2020-10-29T10:38:59.112768965 + 01:00
如果小数位数可能有所不同,则需要一个DateTimeFormatterBuilder
,但基本技巧是相同的简单技巧:在格式模式字符串中放入逗号。
DateTimeFormatter isoWithCommaFormatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.appendPattern("HH:mm:ss[,")
.appendFraction(ChronoField.NANO_OF_SECOND,false)
.appendPattern("]XXX")
.toFormatter();
ISO 8601格式建议使用点号上的逗号作为小数点分隔符,因此,内置格式化程序和one-arg parse
方法仅接受点有点可笑。
您可以简单地使用逗号而不是点来分隔纳秒,例如您可以使用DateTimeFormatter.ofPattern("u-M-d'T'H:m:s,nXXX")
。
演示:
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
OffsetDateTime odt = OffsetDateTime.parse("2020-10-29T10:38:59,112768965+01:00",DateTimeFormatter.ofPattern("u-M-d'T'H:m:s,nXXX"));
System.out.println(odt);
}
}
输出:
2020-10-29T10:38:59.112768965+01:00