我的应用程序应该能够解析忽略时区的日期(我总是知道它是UTC)。问题是日期可能会出现以下两种形式 -
2017-09-11T12:44:07.793Z
0001-01-01T00:00:00
我可以使用LocalDateTime
解析第一个,使用Instant
类解析第二个。有没有办法使用单一机制?
P.S。我试图避免在输入字符串
的末尾硬编码Z
答案 0 :(得分:5)
如果Z
偏移是可选的,您可以使用带有可选部分的java.time.format.DateTimeFormatterBuilder
:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// optional offset
.optionalStart().appendOffsetId()
// create formatter
.toFormatter();
然后,您可以使用parseBest
方法,以及尝试创建通信对象的TemporalQuery
列表。然后检查返回类型并采取相应措施:
Instant instant = null;
// tries to create Instant, and if it fails, try a LocalDateTime
TemporalAccessor parsed = fmt.parseBest("2017-09-11T12:44:07.793Z", Instant::from, LocalDateTime::from);
if (parsed instanceof Instant) {
instant = (Instant) parsed;
} else if (parsed instanceof LocalDateTime) {
// convert LocalDateTime to UTC instant
instant = ((LocalDateTime) parsed).atOffset(ZoneOffset.UTC).toInstant();
}
System.out.println(instant); // 2017-09-11T12:44:07.793Z
使用第二个输入(0001-01-01T00:00:00
)运行会产生相当于Instant
的{{1}}。
在上面的示例中,我只使用了0001-01-01T00:00:00Z
和Instant::from
,因此格式化程序会尝试首先创建LocalDateTime::from
。如果不可能,则尝试创建Instant
。您可以在列表中添加任意数量的类型(例如,我可以添加LocalDateTime
,如果创建了ZonedDateTime::from
,我只能使用{{1}转换为ZonedDateTime
方法)。
如您所知,输入始终为UTC,您也可以直接在格式化程序中设置:
Instant
因此,您可以直接将其解析为toInstant()
:
DateTimeFormatter fmt = new DateTimeFormatterBuilder()
// date/time
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
// optional offset
.optionalStart().appendOffsetId()
// create formatter with UTC
.toFormatter().withZone(ZoneOffset.UTC);
答案 1 :(得分:4)
你可以“parseBest”,像这样:
DateTimeFormatter parser = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[Z]");
Temporal parsed = parser.parseBest(inputString, Instant::from, LocalDateTime::from);
然后你应该检查解析的内容,并采取相应的行动。
parseBest
方法适用于任何类型的TemporalQuery
,包括from
类上可用的大多数java.time
方法。因此,您可以使用LocalDate.from
来延长该列表。
你也可以使用该方法和lambdas来强制解析结果到你想要的类型,而不需要instanceof
检查结果解决外部(虽然没有一个强制转换):
Instant parsed = (Instant) parser.parseBest(inputString,
Instant::from,
interResult -> LocalDateTime.from(interResult).atZone(ZoneOffset.UTC).toInstant())
请注意,第二个选项使用lambda将LocalDateTime
转换为ZonedDateTime
,然后转换为Instant
,因此解析结果始终转换为Instant
。