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 终端区分大小写。
Z
与 z
不同。
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.
关于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")));
}
}
输出:
2020-12-22T00:45:50+05:30
2020-12-22T00:45:50+05:30
了解有关现代日期时间 API 的更多信息
TL;DR
虽然在这一点上我不知道 ISO 8601,但据记载 Java 的单参数 OffsetDateTime.parse(CharSequence)
允许大写和小写 T
和 Z
.
通过文档进行追踪
文档说:
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 称为“祖鲁时间”的常见军事、海洋和航空用法)。
我正在使用以下 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 终端区分大小写。
Z
与 z
不同。
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.
关于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")));
}
}
输出:
2020-12-22T00:45:50+05:30
2020-12-22T00:45:50+05:30
了解有关现代日期时间 API 的更多信息
TL;DR
虽然在这一点上我不知道 ISO 8601,但据记载 Java 的单参数 OffsetDateTime.parse(CharSequence)
允许大写和小写 T
和 Z
.
通过文档进行追踪
文档说:
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 称为“祖鲁时间”的常见军事、海洋和航空用法)。