【问题标题】:Find standard time name for a region using Java使用 Java 查找区域的标准时间名称
【发布时间】:2020-07-10 17:23:49
【问题描述】:

有没有办法找到属于时区区域的标准时间, 例如

America/New_York and America/NewJersey -> EST

我正在开发一个 REST 服务,其中请求将基于区域的时区(美国/新泽西州)作为参数,我需要找到它所遵循的标准时间并将其传递给仅接受 3 位数时区的旧版 API (EST/MST/CST/AET)。

我正在使用 Java 8 并检查了 Time API,但它没有任何此类特性/功能。作为一种解决方法,我可以在文件或数据库中进行映射,但只是想知道其他人是否遇到过这个问题,是否有任何干净的解决方案。

【问题讨论】:

  • 看来得自己动手了stackoverflow.com/questions/2807197/…
  • @OleV.V.您的解决方案似乎很好,但是某些时区无法识别,例如,我得到的是 AEST 而不是 AET,而旧系统需要 AET,这不是因为 DST,而是 Java 时区本身没有三位数

标签: java java-8 java-time


【解决方案1】:

如果我理解正确的话,主要要求是有一些特定的三字母缩写,这是您无法控制的 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 会将它理解为北美中部标准时间。我们真的应该永远依赖三个字母的时区缩写。它们是模棱两可的,也许经常是这样。正如这个问题所示,它们不是标准化的。

【讨论】:

  • 我尝试过使用方法,但遗漏了一些时区,因此我深入研究了遗留 API 并找到了一种传递时区的方法,因为这是 Java 中的最佳解决方案,我接受它为回答
猜你喜欢
  • 1970-01-01
  • 2015-07-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多