我需要一个java.time解析器,它可以处理任何有效的W3C ISO 8601日期/时间字符串
似乎没有一个内置的java.time解析器可以处理任何有效的日期/时间字符串 它应该返回ZonedDateTime,并按照W3C规范的规定将缺少的字段设置为0 这似乎是一个如此常见的用例,我很惊讶它不是标准库的一部分,我想象它在库外被多次解决。有人有解决办法吗 W3C ISO 8601 是标准的自我声明的“概要”,而不是标准本身 这似乎是一个如此常见的用例,我很惊讶它不是标准库的一部分 在解析文本时,java.time类确实默认使用ISO8601格式 没有通用的解析器,因为上下文很重要。一年、一年、一个月、一个日期、一天中的某个时间、一天中的某个时间、一天中的某个时间具有偏移量的日期、一天中的某个时间具有时区的日期都是不同的动物。您通常不会期望不同类型的值任意到达 如果您确实有这样一个任意类型的集合,那么只需执行一系列解析尝试。我需要一个java.time解析器,它可以处理任何有效的W3C ISO 8601日期/时间字符串,java,time,iso8601,Java,Time,Iso8601,似乎没有一个内置的java.time解析器可以处理任何有效的日期/时间字符串 它应该返回ZonedDateTime,并按照W3C规范的规定将缺少的字段设置为0 这似乎是一个如此常见的用例,我很惊讶它不是标准库的一部分,我想象它在库外被多次解决。有人有解决办法吗 W3C ISO 8601 是标准的自我声明的“概要”,而不是标准本身 这似乎是一个如此常见的用例,我很惊讶它不是标准库的一部分 在解析文本时,java.time类确实默认使用ISO8601格式 没有通用的解析器,因为上下文很重要。一年、一
DateTimeParseException
异常的陷阱。如果使用一个java.time类解析失败,请转到下一个java.time类
你说:
它应该返回ZonedDateTime,并按照W3C规范的规定将缺少的字段设置为0
如何将仅年份值转换为ZonedDateTime
对象?月和日的值应该是多少?零是不能接受的。什么时区?您需要指定所需的区域。一天几点?时间的零不起作用,因为并非某些区域中的所有天都从00:00:00开始
由于这些原因,通用解析器是不可能的。您需要根据特定应用程序的业务规则对特定输入数据执行解析
通过使用DateTimeFormatterBuilder
类建立默认值,您可以更接近所需的通用解析器。看
链接中的示例是OffsetDateTime
,而不是zoneDateTime
。ZoneDateTime
需要时区ID,例如Europe/London
。另外,JDBC4.2支持OffsetDateTime
,而不支持ZonedDateTime
您可以使用DateTimeFormatterBuilder#parseDefaulting
将字符串解析为具有默认值的OffsetDateTime
演示:
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
ZoneId zoneId = ZoneId.systemDefault();
LocalDate now = LocalDate.now(zoneId);
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendPattern("uuuu[-MM[-dd]]['T'HH[:mm[:ss[.SSSSSSSSS][.SSSSSSSS][.SSSSSSS][.SSSSSS][.SSSSS][.SSSS][.SSS][.SS][.S]]]][XXX]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, now.getMonthValue())
.parseDefaulting(ChronoField.DAY_OF_MONTH, now.getDayOfMonth())
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter(Locale.ENGLISH);
//Test
Stream.of(
"1997",
"1997-07",
"1997-07-16",
"1997-07-16T19:20+01:00",
"1997-07-16T19:20:30+01:00",
"1997-07-16T19:20:30.45+01:00"
).forEach(s -> System.out.println(OffsetDateTime.parse(s, dtf)));
}
}
1997-05-21T00:00Z
1997-07-21T00:00Z
1997-07-16T00:00Z
1997-07-16T19:20+01:00
1997-07-16T19:20:30+01:00
1997-07-16T19:20:30.450+01:00
输出:
import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.temporal.ChronoField;
import java.util.Locale;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
ZoneId zoneId = ZoneId.systemDefault();
LocalDate now = LocalDate.now(zoneId);
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendPattern("uuuu[-MM[-dd]]['T'HH[:mm[:ss[.SSSSSSSSS][.SSSSSSSS][.SSSSSSS][.SSSSSS][.SSSSS][.SSSS][.SSS][.SS][.S]]]][XXX]")
.parseDefaulting(ChronoField.MONTH_OF_YEAR, now.getMonthValue())
.parseDefaulting(ChronoField.DAY_OF_MONTH, now.getDayOfMonth())
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0)
.parseDefaulting(ChronoField.NANO_OF_SECOND, 0)
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter(Locale.ENGLISH);
//Test
Stream.of(
"1997",
"1997-07",
"1997-07-16",
"1997-07-16T19:20+01:00",
"1997-07-16T19:20:30+01:00",
"1997-07-16T19:20:30.45+01:00"
).forEach(s -> System.out.println(OffsetDateTime.parse(s, dtf)));
}
}
1997-05-21T00:00Z
1997-07-21T00:00Z
1997-07-16T00:00Z
1997-07-16T19:20+01:00
1997-07-16T19:20:30+01:00
1997-07-16T19:20:30.450+01:00
输出中的Z
为零时区偏移。它代表Zulu并指定Etc/UTC
时区(其时区偏移量为+00:00
小时)
了解更多关于java.time
、来自的*
*无论出于何种原因,如果您必须坚持使用Java6或Java7,您可以使用哪个backport将大部分Java.time功能移植到Java6&7。如果您正在为Android项目工作,并且您的Android API级别仍然不符合Java-8,请检查并确认。
为什么不使用
java.time.format.DateTimeFormatter#ISO_ZONED_DATE_time
?“我想它在图书馆外被解决了多次”也许是这样,但要求图书馆是离题的。我甚至不确定你在问什么。您想要一个可以读取一年、一年和一个月、一年和一个月和一天等的解析器吗?是否要将缺少的字段设置为零?那么“2021”应该被解析为2021年零月份的00:00:00第零次?ZoneDateTime不能代表这一点。这一观点为读者提供了正确的指导。我犹豫地开始使用编写答案,但后来我看到了这个很棒的答案并放弃了我的答案。@ArvindKumarAvinash我认为使用parseDefaulting
示例的答案在这里会很有用。同时,我在回答中还提到了你的评论。谢谢你,巴兹尔·布尔克。我已经发布了答案。我同意,OffsetDateTime比ZoneDateTime更合适。你的解决方案看起来不错,我接受它作为答案。谢谢