Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我需要一个java.time解析器,它可以处理任何有效的W3C ISO 8601日期/时间字符串_Java_Time_Iso8601 - Fatal编程技术网

我需要一个java.time解析器,它可以处理任何有效的W3C ISO 8601日期/时间字符串

我需要一个java.time解析器,它可以处理任何有效的W3C ISO 8601日期/时间字符串,java,time,iso8601,Java,Time,Iso8601,似乎没有一个内置的java.time解析器可以处理任何有效的日期/时间字符串 它应该返回ZonedDateTime,并按照W3C规范的规定将缺少的字段设置为0 这似乎是一个如此常见的用例,我很惊讶它不是标准库的一部分,我想象它在库外被多次解决。有人有解决办法吗 W3C ISO 8601 是标准的自我声明的“概要”,而不是标准本身 这似乎是一个如此常见的用例,我很惊讶它不是标准库的一部分 在解析文本时,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更合适。你的解决方案看起来不错,我接受它作为答案。谢谢