使用 Java 查找区域的标准时间名称
Find standard time name for a region using Java
有没有办法找到时区区域下的标准时间,
例如
America/New_York and America/NewJersey -> EST
我正在开发一个 REST 服务,其中请求将基于区域的时区 (America/NewJersey) 作为参数,我需要找到它所遵循的标准时间并将其传递给遗留 API, 只接受 3 位时区(EST/MST/CST/AET).
我正在使用 Java 8,我检查了时间 API,但它没有任何这样的 feature/functionality。作为一种解决方法,我可以在文件或数据库中进行映射,但只想知道是否有其他人遇到过这个问题,是否有任何干净的解决方案。
如果我理解正确,主要要求是有一些特定的三个字母的缩写,API 超出您的控制范围。例如:
- EST 代表东部标准时间(可能是北美东部标准时间?),而不是 ET 代表东部时间。
- 另一方面,AET 代表澳大利亚东部时间,而不是 AEST 代表澳大利亚东部标准时间(也不是 EST 代表东部标准时间,尽管我已经读到 EST 在澳大利亚也被用作缩写)。
在我看来,Java 知道的时区缩写(来自 CLDR 或您使用的区域设置数据提供商)与 API 所需的缩写之间没有系统的对应关系.作为另一个问题,三个字母的时区缩写通常是模棱两可的,所以我怀疑有很多时区是您的遗留 API 根本无法识别的(或者它需要一些我们几乎没有机会的晦涩的朴素缩写猜测)。
方法有两种:
- Deadpool 长期以来在评论中建议的安全但又间接和费力的方法:构建并保留所需缩写的映射。
- 看看你能用 Java 知道的缩写词走多远。请做好准备,您将无法涵盖所有情况,并且您可能偶尔会做出错误的猜测。
我会根据我的建议将选项 1 留给您自己。
如果您想尝试选项 2 的运气,我的尝试如下。
private static final DateTimeFormatter ZONE_FORMATTER
= DateTimeFormatter.ofPattern("zzz", Locale.ENGLISH);
private static String getThreeLetterAbbreviation(ZoneId zone) {
// Try the display name first
String displayName = zone.getDisplayName(TextStyle.SHORT_STANDALONE, Locale.ENGLISH);
if (displayName.length() == 3) {
return displayName;
}
// Try formatting a date in standard time; try southern hemisphere first
ZonedDateTime timeInStandardTime = LocalDate.of(2021, Month.JULY, 1)
.atStartOfDay(zone);
if (zone.getRules().isDaylightSavings(timeInStandardTime.toInstant())) {
// Then northern hemisphere
timeInStandardTime = LocalDate.of(2021, Month.JANUARY, 1)
.atStartOfDay(zone);
if (zone.getRules().isDaylightSavings(timeInStandardTime.toInstant())) {
throw new IllegalArgumentException("Unable to find a date in standard time");
}
}
return timeInStandardTime.format(ZONE_FORMATTER);
}
这个辅助方法试试看:
private static void printAbbreviation(String zid) {
System.out.format("%19s -> %s%n", zid,
getThreeLetterAbbreviation(ZoneId.of(zid)));
}
所以我们开始使用它:
printAbbreviation("America/Los_Angeles");
printAbbreviation("America/Denver");
printAbbreviation("America/Chicago");
printAbbreviation("America/New_York");
printAbbreviation("Australia/Sydney");
输出:
America/Los_Angeles -> PST
America/Denver -> MST
America/Chicago -> CST
America/New_York -> EST
Australia/Sydney -> AET
我不会称之为干净的解决方案。我特别担心的是,该方法会产生错误的结果,您的 API 解释的结果与预期的不同,并且没有人会注意到它反过来会产生错误的结果,或者直到为时已晚。例如:
printAbbreviation("Asia/Shanghai");
Asia/Shanghai -> CST
这里的 CST 是指中国标准时间,但我猜你的 API 会把它理解为北美中部标准时间。我们真的应该 永远不要 依赖三个字母的时区缩写。它们是模棱两可的,也许更多时候是模棱两可的。正如这个问题所示,它们不是标准化的。
有没有办法找到时区区域下的标准时间, 例如
America/New_York and America/NewJersey -> EST
我正在开发一个 REST 服务,其中请求将基于区域的时区 (America/NewJersey) 作为参数,我需要找到它所遵循的标准时间并将其传递给遗留 API, 只接受 3 位时区(EST/MST/CST/AET).
我正在使用 Java 8,我检查了时间 API,但它没有任何这样的 feature/functionality。作为一种解决方法,我可以在文件或数据库中进行映射,但只想知道是否有其他人遇到过这个问题,是否有任何干净的解决方案。
如果我理解正确,主要要求是有一些特定的三个字母的缩写,API 超出您的控制范围。例如:
- EST 代表东部标准时间(可能是北美东部标准时间?),而不是 ET 代表东部时间。
- 另一方面,AET 代表澳大利亚东部时间,而不是 AEST 代表澳大利亚东部标准时间(也不是 EST 代表东部标准时间,尽管我已经读到 EST 在澳大利亚也被用作缩写)。
在我看来,Java 知道的时区缩写(来自 CLDR 或您使用的区域设置数据提供商)与 API 所需的缩写之间没有系统的对应关系.作为另一个问题,三个字母的时区缩写通常是模棱两可的,所以我怀疑有很多时区是您的遗留 API 根本无法识别的(或者它需要一些我们几乎没有机会的晦涩的朴素缩写猜测)。
方法有两种:
- Deadpool 长期以来在评论中建议的安全但又间接和费力的方法:构建并保留所需缩写的映射。
- 看看你能用 Java 知道的缩写词走多远。请做好准备,您将无法涵盖所有情况,并且您可能偶尔会做出错误的猜测。
我会根据我的建议将选项 1 留给您自己。
如果您想尝试选项 2 的运气,我的尝试如下。
private static final DateTimeFormatter ZONE_FORMATTER
= DateTimeFormatter.ofPattern("zzz", Locale.ENGLISH);
private static String getThreeLetterAbbreviation(ZoneId zone) {
// Try the display name first
String displayName = zone.getDisplayName(TextStyle.SHORT_STANDALONE, Locale.ENGLISH);
if (displayName.length() == 3) {
return displayName;
}
// Try formatting a date in standard time; try southern hemisphere first
ZonedDateTime timeInStandardTime = LocalDate.of(2021, Month.JULY, 1)
.atStartOfDay(zone);
if (zone.getRules().isDaylightSavings(timeInStandardTime.toInstant())) {
// Then northern hemisphere
timeInStandardTime = LocalDate.of(2021, Month.JANUARY, 1)
.atStartOfDay(zone);
if (zone.getRules().isDaylightSavings(timeInStandardTime.toInstant())) {
throw new IllegalArgumentException("Unable to find a date in standard time");
}
}
return timeInStandardTime.format(ZONE_FORMATTER);
}
这个辅助方法试试看:
private static void printAbbreviation(String zid) {
System.out.format("%19s -> %s%n", zid,
getThreeLetterAbbreviation(ZoneId.of(zid)));
}
所以我们开始使用它:
printAbbreviation("America/Los_Angeles");
printAbbreviation("America/Denver");
printAbbreviation("America/Chicago");
printAbbreviation("America/New_York");
printAbbreviation("Australia/Sydney");
输出:
America/Los_Angeles -> PST America/Denver -> MST America/Chicago -> CST America/New_York -> EST Australia/Sydney -> AET
我不会称之为干净的解决方案。我特别担心的是,该方法会产生错误的结果,您的 API 解释的结果与预期的不同,并且没有人会注意到它反过来会产生错误的结果,或者直到为时已晚。例如:
printAbbreviation("Asia/Shanghai");
Asia/Shanghai -> CST
这里的 CST 是指中国标准时间,但我猜你的 API 会把它理解为北美中部标准时间。我们真的应该 永远不要 依赖三个字母的时区缩写。它们是模棱两可的,也许更多时候是模棱两可的。正如这个问题所示,它们不是标准化的。