【问题标题】:Are time zone designators- "T" and "Z" case sensitive in ISO8601 format?ISO8601 格式的时区指示符“T”和“Z”是否区分大小写?
【发布时间】:2020-12-01 08:20:42
【问题描述】:

我正在使用以下 ISO8601 格式:

YYYY-MM-DDThh:mm:ssZ

我使用OffsetDateTime.parse() 来解析这种格式。我可以通过在这里传递t(而不是T)和z(而不是Z)来解析日期时间。

那么任何人都可以判断它是否在 ISO8601 中被允许,还是仅在解析逻辑中被遗漏?

【问题讨论】:

  • Aishwer Sharma - 如果其中一个答案解决了您的问题,您可以通过将其标记为已接受来帮助社区。接受的答案有助于未来的访问者自信地使用该解决方案。

标签: java java-time iso8601 datetimeformatter offsetdatetime


【解决方案1】:

那么任何人都可以判断它是否在 ISO8601 中被允许,还是仅在解析逻辑中被遗漏?

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

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

【讨论】:

  • ISO8601 的哪个版本? tools.ietf.org/html/rfc3339#section-5.6 [first note] 似乎暗示 ISO 允许小写。但 RFC-3339 是基于旧的 ISO8601
  • @GiacomoCatenazzi 这是 2016 年的草案。
【解决方案2】:

Zz 不同。

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

另一个例子可以是M,它用于月份m,它用于分钟数。。 p>

日期、时间、时区等组件的符号区分大小写。查看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 将能够确定时区 ID 与 Asia/Calcutta 的时区偏移量,但尝试使用 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)

我使用“OffsetDateTime.parse()”(在 java 中)来解析这种格式。一世 能够通过传递“t”(而不是“T”)和“z”来解析日期时间 (而不是“Z”)。

我已经解释了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 的更多信息。

【讨论】:

    【解决方案3】:

    TL;DR

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

    跟踪文档

    文档说:

    字符串必须代表一个有效的日期时间,并使用解析 DateTimeFormatter.ISO_OFFSET_DATE_TIME.

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

    • ISO_LOCAL_DATE_TIME
    • 偏移 ID。 … 解析不区分大小写。

    最后一句允许大写Z和小写z进行偏移。 ISO_LOCAL_DATE_TIME 的文档中提到了 T

    • 字母“T”。解析不区分大小写。

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

    我们不应该相信 Java 会告诉我们有关标准的真相。似乎 ISO 8601 标准是一个秘密,除非您支付副本费用(说服人们遵循标准恕我直言的有趣方式)。有一篇关于该标准的精美 Wikipedia 文章。它以大写字母给出,但也没有提到它们是否也可以小写。

    链接

    【讨论】:

      猜你喜欢
      • 2012-06-25
      • 1970-01-01
      • 2011-11-16
      • 1970-01-01
      • 2011-03-08
      • 2013-03-16
      • 2012-08-07
      • 2013-03-06
      • 2020-02-18
      相关资源
      最近更新 更多