ISO8601 格式的时区指示符 "T" 和 "Z" 是否区分大小写?

Are time zone designators- "T" and "Z" case sensitive in ISO8601 format?

我正在使用以下 ISO8601 格式:

YYYY-MM-DDThh:mm:ssZ

我用OffsetDateTime.parse()来解析这个格式。我能够通过在此处传递 t(而不是 T)和 z(而不是 Z)来解析日期时间。

那么谁能告诉我它是否在 ISO8601 中被允许,还是仅在解析逻辑中被遗漏了?

So can anyone tell if it is allowed in ISO8601 or is it missed only in parsing logic?

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

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

Zz 不同。

DateTimeFormatter 评估前者为 zone-offset 而后者为 time-zone name.

另一个示例可以是 M,它用于 月份 ,以及 m,它用于 分钟-小时.

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

快速演示:

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

时区偏移与时区不同。时区的 ID 格式为 Continent/City,例如Asia/Calcutta 而时区偏移量以小时和分钟表示,表示某个地点的日期和时间相对于 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));
    }
}

输出:

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)

And I used "OffsetDateTime.parse()" (in java) to parse this format. I was able to parse date time by passing "t" (instead of "T") and "z" (instead of "Z") here.

关于Zz我已经解释过了。让我们关注 Tt。如果你仔细观察,你会发现我在 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")));
    }
}

输出:

2020-12-22T00:45:50+05:30
2020-12-22T00:45:50+05:30

Trail: Date Time.

了解有关现代日期时间 API 的更多信息

TL;DR

虽然在这一点上我不知道 ISO 8601,但据记载 Java 的单参数 OffsetDateTime.parse(CharSequence) 允许大写和小写 TZ.

通过文档进行追踪

文档说:

The string must represent a valid date-time and is parsed using DateTimeFormatter.ISO_OFFSET_DATE_TIME.

DateTimeFormatter.ISO_OFFSET_DATE_TIME 的文档说格式包括:

  • The ISO_LOCAL_DATE_TIME
  • The offset ID. … Parsing is case insensitive.

最后一句允许大写Z和小写z进行偏移。 ISO_LOCAL_DATE_TIME 的文档说 T:

  • The letter 'T'. Parsing is case insensitive.

所以这允许大写 T 和小写 t.

我们不应该相信 Java 告诉我们有关标准的真相。似乎 ISO 8601 标准是一个秘密,除非您支付一份副本(这是一种说服人们遵循标准恕我直言的有趣方式)。有一篇关于该标准的精彩维基百科文章。它以大写字母给出字母,但没有提及是否也允许使用小写字母。

链接

记录一下,ISO 8601:2004 数据元素和交换格式——信息交换——日期和时间的表示,第 11 页说(我引用):

NOTE 1 In date and time representations lower case characters may be used when upper case letters are not available.

第 11 页列举了适用的代号,同上

  • P:持续时间指示符,P 的使用基于术语“期间”的“历史”使用)
  • R:循环时间间隔指示符
  • T: 时间指示符
  • W: 周指示符
  • Z:UTC 指示符(Z 的使用基于将 UTC 称为“祖鲁时间”的常见军事、海洋和航空用法)。