日期时间字符串中的 'z' 在不同的语言环境中是否有不同的输出?
Does a 'z' in a datetime String have different outputs in different locales?
不久前,我回答了一个关于如何从 ZonedDateTime
中提取时区的问题,该 ZonedDateTime
是从 String
解析的。
它总体上有效,但在 OP 的系统和我的系统上,相同代码的输出不同,不知何故不再让我离开。
询问如何从 ZonedDateTime
获取 ZoneId
,我提供了一种方法。诚然,这不是公认的答案,但似乎仍然值得某人点赞。
我的回答的特别之处在于用于解析时间 String
的模式中的 'z'
。 String
中有一个时区名称,代表时区 "Australia/Adelaide"
"... ACST"
(澳大利亚中部标准时间)。
当我在我的系统上解析它并使用 DateTimeFormatter.ISO_ZONED_DATE_TIME
print/format ZonedDateTime
时,它会在 "America/Manaus"
中打印时间并提取 ZoneId
,还是那个来自南美的。 OP 在我的回答下方的评论中指出,在他的系统上,至少有一个输出行显示 desired/correct ZoneId
.
这怎么可能?系统默认语言环境对解析 'z'
in datetime String
s 有影响吗?
这是我在问题中的回答的代码加上我的 ZoneId.systemDefault()
:
的输出
public static void main(String args[]) throws Exception {
String time = "2 Jun 2019 03:51:17 PM ACST";
String pattern = "d MMM yyyy hh:mm:ss a z"; // z detects the time zone (ACST here)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
// parse a time object using the formatter and the time String
ZonedDateTime zdt = ZonedDateTime.parse(time, formatter);
// print it using a standard formatter
System.out.println(zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
// extract the zone id
ZoneId zoneId = zdt.getZone();
ZoneId sysDefault = ZoneId.systemDefault();
// print the zone id
System.out.println("Time zone of parsed String is " + zoneId);
System.out.println("System default time zone is " + sysDefault);
// retrieve the instant seconds
Instant instant = zdt.toInstant();
// print the epoch seconds of another time zone
System.out.println("Epoch seconds in Australia/Adelaide are "
+ instant.atZone(ZoneId.of("Australia/Adelaide")).toEpochSecond());
}
它的输出是这样的:
2019-06-02T15:51:17-04:00[America/Manaus]
Time zone of parsed String is America/Manaus
System default time zone is Europe/Berlin
Epoch seconds in Australia/Adelaide are 1559505077
任何人都可以指出我所犯的错误或确认并解释不同系统默认值 ZoneId
对将 String
解析为 ZonedDateTime
的影响吗?
我也遇到过在不同的 JVM 上解析不明确的时区缩写(在提供语言环境时也是如此,所以这不是唯一的问题)。我认为没有记录确切的行为。在某些情况下,选择了 JVM 的默认时区,但我不知道它是否总是匹配。
您可以通过重载DateTimeFormatterBuilder.appendZoneText(TextStyle, Set<ZoneId>)
方法来控制不明确情况下的时区选择。
区域设置不同的示例:Europe/Berlin 和许多其他欧洲时区在许多区域设置中将被格式化为 Central European Time
或 CET
。在德语语言环境中,它们变成 Mitteleuropäische Zeit
或 MET
.
是正确的。
ISO 8601
此外,"2 Jun 2019 03:51:17 PM ACST"
等字符串不应被解析。这种格式不应该用于交换日期时间值。这样的字符串应该只用于向人类用户展示,而不是用于数据交换。
你会尝试将 USD 23.67
的金额兑换成 twenty three dollars and sixty-seven cents in United States dollars
还是 vingt-trois dollars et soixante-sept cents en dollars des États-Unis
?
要通过文本交换日期时间值,请始终使用标准 ISO 8601 格式。合理的格式被设计为明确的,易于机器解析,并且易于跨文化的人类阅读。
如果使用时区,请使用ZonedDateTime::toString
方法生成文本。此方法明智地扩展了 ISO 8601 格式,将时区名称附加在方括号中。
ZoneId z = ZoneId.of( "Australia/Adelaide" ) ;
String output = ZonedDateTime.now( z ).toString() ;
2020-02-10T06:30:57.756491+10:30[Australia/Adelaide]
运行 即 code live at IdeOne.com.
正在解析。
ZonedDateTime zdt = ZonedDateTime.parse( output ) ;
更好的是,当时区不直接相关时使用 UTC 值。要以 UTC 格式捕获和传达当前时刻,请使用 Instant
。
再次调用 toString
& parse
来生成和解析标准 ISO 8601 格式的文本。末尾的 Z
表示 UTC,零小时-分钟-秒的偏移量,发音为“Zulu”。
String output = Instant.now().toString() ;
2020-02-09T20:07:42.718473Z
不久前,我回答了一个关于如何从 ZonedDateTime
中提取时区的问题,该 ZonedDateTime
是从 String
解析的。
它总体上有效,但在 OP 的系统和我的系统上,相同代码的输出不同,不知何故不再让我离开。
ZonedDateTime
获取 ZoneId
,我提供了一种方法。诚然,这不是公认的答案,但似乎仍然值得某人点赞。
我的回答的特别之处在于用于解析时间 String
的模式中的 'z'
。 String
中有一个时区名称,代表时区 "Australia/Adelaide"
"... ACST"
(澳大利亚中部标准时间)。
当我在我的系统上解析它并使用 DateTimeFormatter.ISO_ZONED_DATE_TIME
print/format ZonedDateTime
时,它会在 "America/Manaus"
中打印时间并提取 ZoneId
,还是那个来自南美的。 OP 在我的回答下方的评论中指出,在他的系统上,至少有一个输出行显示 desired/correct ZoneId
.
这怎么可能?系统默认语言环境对解析 'z'
in datetime String
s 有影响吗?
这是我在问题中的回答的代码加上我的 ZoneId.systemDefault()
:
public static void main(String args[]) throws Exception {
String time = "2 Jun 2019 03:51:17 PM ACST";
String pattern = "d MMM yyyy hh:mm:ss a z"; // z detects the time zone (ACST here)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
// parse a time object using the formatter and the time String
ZonedDateTime zdt = ZonedDateTime.parse(time, formatter);
// print it using a standard formatter
System.out.println(zdt.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
// extract the zone id
ZoneId zoneId = zdt.getZone();
ZoneId sysDefault = ZoneId.systemDefault();
// print the zone id
System.out.println("Time zone of parsed String is " + zoneId);
System.out.println("System default time zone is " + sysDefault);
// retrieve the instant seconds
Instant instant = zdt.toInstant();
// print the epoch seconds of another time zone
System.out.println("Epoch seconds in Australia/Adelaide are "
+ instant.atZone(ZoneId.of("Australia/Adelaide")).toEpochSecond());
}
它的输出是这样的:
2019-06-02T15:51:17-04:00[America/Manaus]
Time zone of parsed String is America/Manaus
System default time zone is Europe/Berlin
Epoch seconds in Australia/Adelaide are 1559505077
任何人都可以指出我所犯的错误或确认并解释不同系统默认值 ZoneId
对将 String
解析为 ZonedDateTime
的影响吗?
我也遇到过在不同的 JVM 上解析不明确的时区缩写(在提供语言环境时也是如此,所以这不是唯一的问题)。我认为没有记录确切的行为。在某些情况下,选择了 JVM 的默认时区,但我不知道它是否总是匹配。
您可以通过重载DateTimeFormatterBuilder.appendZoneText(TextStyle, Set<ZoneId>)
方法来控制不明确情况下的时区选择。
区域设置不同的示例:Europe/Berlin 和许多其他欧洲时区在许多区域设置中将被格式化为 Central European Time
或 CET
。在德语语言环境中,它们变成 Mitteleuropäische Zeit
或 MET
.
ISO 8601
此外,"2 Jun 2019 03:51:17 PM ACST"
等字符串不应被解析。这种格式不应该用于交换日期时间值。这样的字符串应该只用于向人类用户展示,而不是用于数据交换。
你会尝试将 USD 23.67
的金额兑换成 twenty three dollars and sixty-seven cents in United States dollars
还是 vingt-trois dollars et soixante-sept cents en dollars des États-Unis
?
要通过文本交换日期时间值,请始终使用标准 ISO 8601 格式。合理的格式被设计为明确的,易于机器解析,并且易于跨文化的人类阅读。
如果使用时区,请使用ZonedDateTime::toString
方法生成文本。此方法明智地扩展了 ISO 8601 格式,将时区名称附加在方括号中。
ZoneId z = ZoneId.of( "Australia/Adelaide" ) ;
String output = ZonedDateTime.now( z ).toString() ;
2020-02-10T06:30:57.756491+10:30[Australia/Adelaide]
运行 即 code live at IdeOne.com.
正在解析。
ZonedDateTime zdt = ZonedDateTime.parse( output ) ;
更好的是,当时区不直接相关时使用 UTC 值。要以 UTC 格式捕获和传达当前时刻,请使用 Instant
。
再次调用 toString
& parse
来生成和解析标准 ISO 8601 格式的文本。末尾的 Z
表示 UTC,零小时-分钟-秒的偏移量,发音为“Zulu”。
String output = Instant.now().toString() ;
2020-02-09T20:07:42.718473Z