使用 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 根本无法识别的(或者它需要一些我们几乎没有机会的晦涩的朴素缩写猜测)。

方法有两种:

  1. Deadpool 长期以来在评论中建议的安全但又间接和费力的方法:构建并保留所需缩写的映射。
  2. 看看你能用 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 会把它理解为北美中部标准时间。我们真的应该 永远不要 依赖三个字母的时区缩写。它们是模棱两可的,也许更多时候是模棱两可的。正如这个问题所示,它们不是标准化的。