Java 是时区指示符-“;";及;Z";ISO8601格式是否区分大小写?

Java 是时区指示符-“;";及;Z";ISO8601格式是否区分大小写?,java,java-time,iso8601,datetimeformatter,offsetdatetime,Java,Java Time,Iso8601,Datetimeformatter,Offsetdatetime,我使用以下ISO8601格式: YYYY-MM-DDThh:mm:ssZ 我使用了OffsetDateTime.parse()来解析这种格式。我可以通过在这里传递t(而不是t)和z(而不是z)来解析日期时间 那么,有人能告诉我们,它是在ISO8601中被允许的,还是仅仅在解析逻辑中被遗漏了 那么,有人能告诉我们,在ISO8601中,它是被允许的,还是仅仅在解析逻辑中被遗漏了 我认为生成它们是无效的,尽管我认为解析器允许这样做是好的(尽管不是很好) 我可以访问的规范性EBNF(8601-1 DI

我使用以下ISO8601格式:

YYYY-MM-DDThh:mm:ssZ
我使用了
OffsetDateTime.parse()
来解析这种格式。我可以通过在这里传递
t
(而不是
t
)和
z
(而不是
z
)来解析日期时间

那么,有人能告诉我们,它是在ISO8601中被允许的,还是仅仅在解析逻辑中被遗漏了

那么,有人能告诉我们,在ISO8601中,它是被允许的,还是仅仅在解析逻辑中被遗漏了

我认为生成它们是无效的,尽管我认为解析器允许这样做是好的(尽管不是很好)

我可以访问的规范性EBNF(8601-1 DIS附录A)对所有指示符仅使用大写拉丁字母,无论它们是Z、T、W、R、p、Y、M、D、H、M或S,并且与(非A)BNF不同,据我所知,EBNF终端区分大小写。

Z
Z
不同。
DateTimeFormatter
将前者计算为区域偏移量,将后者计算为时区名称

另一个示例可以是
M
,它用于一年中的月份,以及
M
,它用于小时分钟

日期、时间、时区等组成部分的符号区分大小写。检查以了解有关这些符号的更多信息

快速演示:

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        ZonedDateTime odt = ZonedDateTime.now(ZoneId.of("Asia/Calcutta"));
        System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssZ").format(odt));
        System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssz").format(odt));
    }
}
2020-12-22T00:14:44+0530
2020-12-22T00:14:44IST
2020-12-22T00:30:40+0530
Exception in thread "main" java.time.DateTimeException: Unable to extract ZoneId from temporal 2020-12-22T00:30:40.865087+05:30
    at java.base/java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:289)
    at java.base/java.time.format.DateTimeFormatterBuilder$ZoneTextPrinterParser.format(DateTimeFormatterBuilder.java:4072)
    at java.base/java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2341)
    at java.base/java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1843)
    at java.base/java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1817)
    at Main.main(Main.java:9)
2020-12-22T00:45:50+05:30
2020-12-22T00:45:50+05:30
输出:

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        ZonedDateTime odt = ZonedDateTime.now(ZoneId.of("Asia/Calcutta"));
        System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssZ").format(odt));
        System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssz").format(odt));
    }
}
2020-12-22T00:14:44+0530
2020-12-22T00:14:44IST
2020-12-22T00:30:40+0530
Exception in thread "main" java.time.DateTimeException: Unable to extract ZoneId from temporal 2020-12-22T00:30:40.865087+05:30
    at java.base/java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:289)
    at java.base/java.time.format.DateTimeFormatterBuilder$ZoneTextPrinterParser.format(DateTimeFormatterBuilder.java:4072)
    at java.base/java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2341)
    at java.base/java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1843)
    at java.base/java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1817)
    at Main.main(Main.java:9)
2020-12-22T00:45:50+05:30
2020-12-22T00:45:50+05:30
区域偏移量与时区不同。时区的ID格式为,
大陆/城市
,例如
亚洲/加尔各答
,而时区偏移量以小时和分钟表示,表示一个地点的日期和时间与
UTC
日期和时间的偏移量。因此,许多时区ID可以具有相同的区域偏移量。换言之,可以从时区ID导出区域偏移量,但反过来是不可能的。例如,在下面的演示中,
OffsetDateTime
将能够从
Asia/Calcutta
的时区ID确定区域偏移量,但尝试使用
z
获取时区名称(如上例所示)将失败

import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        OffsetDateTime odt = OffsetDateTime.now(ZoneId.of("Asia/Calcutta"));
        System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssZ").format(odt));
        System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssz").format(odt));
    }
}
输出:

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        ZonedDateTime odt = ZonedDateTime.now(ZoneId.of("Asia/Calcutta"));
        System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssZ").format(odt));
        System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssz").format(odt));
    }
}
2020-12-22T00:14:44+0530
2020-12-22T00:14:44IST
2020-12-22T00:30:40+0530
Exception in thread "main" java.time.DateTimeException: Unable to extract ZoneId from temporal 2020-12-22T00:30:40.865087+05:30
    at java.base/java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:289)
    at java.base/java.time.format.DateTimeFormatterBuilder$ZoneTextPrinterParser.format(DateTimeFormatterBuilder.java:4072)
    at java.base/java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2341)
    at java.base/java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1843)
    at java.base/java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1817)
    at Main.main(Main.java:9)
2020-12-22T00:45:50+05:30
2020-12-22T00:45:50+05:30
我使用“OffsetDateTime.parse()”(java)来解析这种格式。我 能够通过传递“t”(而不是“t”)和“z”来解析日期时间 (而不是“Z”)在这里

我已经解释了
Z
Z
。让我们关注
T
T
。如果仔细观察,您会发现我在
T
周围使用了单引号,即
'T'
,这使得它成为一个字符串文字,可以在日期时间字符串中使用。这意味着它可以是任何东西,例如
't'
'Foo'
'Bar'
。只要
DateTimeFormatter
中的文本与日期时间字符串中的文本在相同的情况下匹配,它就可以正常工作。我在下面的演示中展示了它:

import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "2020-12-22T00:45:50+05:30";

        // The given string is already in the format which is use by OffsetDateTime for
        // parsing without a DateTimeFormatter
        OffsetDateTime odt = OffsetDateTime.parse(strDateTime);

        // Let's try to parse it using different types of DateTimeFormatter instances
        System.out.println(OffsetDateTime.parse(strDateTime, DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssXXX")));
        
        //The following line will fail as the literal does not match case-wise
        //System.out.println(OffsetDateTime.parse(strDateTime, DateTimeFormatter.ofPattern("uuuu-MM-dd't'HH:mm:ssXXX")));
        
        strDateTime = "2020-12-22t00:45:50+05:30";// Now, DateTimeFormatter with 't' will work successfully
        System.out.println(OffsetDateTime.parse(strDateTime, DateTimeFormatter.ofPattern("uuuu-MM-dd't'HH:mm:ssXXX")));
    }
}
输出:

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

public class Main {
    public static void main(String[] args) {
        ZonedDateTime odt = ZonedDateTime.now(ZoneId.of("Asia/Calcutta"));
        System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssZ").format(odt));
        System.out.println(DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ssz").format(odt));
    }
}
2020-12-22T00:14:44+0530
2020-12-22T00:14:44IST
2020-12-22T00:30:40+0530
Exception in thread "main" java.time.DateTimeException: Unable to extract ZoneId from temporal 2020-12-22T00:30:40.865087+05:30
    at java.base/java.time.format.DateTimePrintContext.getValue(DateTimePrintContext.java:289)
    at java.base/java.time.format.DateTimeFormatterBuilder$ZoneTextPrinterParser.format(DateTimeFormatterBuilder.java:4072)
    at java.base/java.time.format.DateTimeFormatterBuilder$CompositePrinterParser.format(DateTimeFormatterBuilder.java:2341)
    at java.base/java.time.format.DateTimeFormatter.formatTo(DateTimeFormatter.java:1843)
    at java.base/java.time.format.DateTimeFormatter.format(DateTimeFormatter.java:1817)
    at Main.main(Main.java:9)
2020-12-22T00:45:50+05:30
2020-12-22T00:45:50+05:30
从TL中了解有关现代日期时间API的更多信息;博士 虽然在这一点上我不知道ISO 8601,但有文档记载Java的one arg
OffsetDateTime.parse(CharSequence)
同时允许大写和小写
t
Z

跟踪文档 文件说:

字符串必须表示有效的日期和时间,并使用
DateTimeFormatter.ISO\u OFFSET\u DATE\u TIME

DateTimeFormatter.ISO\u OFFSET\u DATE\u TIME
的文档说明该格式包括:

  • ISO\u LOCAL\u DATE\u TIME
  • 偏移量ID…解析不区分大小写
最后一句允许大写
Z
和小写
Z
进行偏移。
ISO\u LOCAL\u DATE\u TIME
的文档说明了
T

  • 字母“T”。解析不区分大小写
因此,这允许大写
T
和小写
T

我们不应该相信Java告诉我们关于标准的真相。ISO 8601标准似乎是一个秘密,除非你花钱买一份(这是一种说服人们遵循标准IMHO的有趣方式)。维基百科上有一篇关于标准的好文章。它用大写字母表示,没有提到是否允许用小写字母表示

链接
  • Java和Java.time文档

哪个版本的ISO8601?[第一条注释]似乎暗示ISO允许小写。但RFC-3339是基于一个古老的ISO8601@GiacomoCatenazzi这是2016年的aound.Aishwer Sharma草案-如果其中一个答案解决了您的问题,您可以通过将其标记为已接受来帮助社区。公认的答案有助于未来的访问者自信地使用解决方案。