Если я правильно понимаю, основным требованием является наличие некоторых специфических c трехбуквенных сокращений, которые требуются API вне вашего контроля. Так, например:
- EST для восточного стандартного времени (вероятно, североамериканское восточное стандартное время?), А не ET для восточного времени.
- С другой стороны, AET для восточного времени Австралии, не AEST для восточного стандартного времени Австралии (а также не EST для восточного стандартного времени, хотя я читал, что EST также используется как сокращение в Австралии).
Мне кажется, c соответствие между сокращениями часовых поясов, которые известны Java (из CLDR или от поставщика данных локали, который вы используете), и сокращений, требуемых этим API. В качестве дополнительной проблемы трехбуквенные сокращения часовых поясов часто неоднозначны, поэтому я подозреваю, что существует много часовых поясов, которые ваш устаревший API просто не может распознать (или для которых требуется какая-то неясная аббревиатура домотканой, которую у нас мало шансов угадать).
Есть два подхода:
- Безопасный, но также обстоятельный и трудоемкий способ - это тот, который Дэдпул давно предлагал в своем комментарии: Создайте и сохраните карту необходимых сокращений.
- Посмотрите, как далеко вы можете зайти с сокращениями, которые знает 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)));
}
Итак, используя его, мы go:
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 будет понимать его как североамериканское центральное стандартное время. Нам действительно не следует никогда полагаться на трехбуквенные сокращения часовых поясов. Они неоднозначны, может быть, чаще всего. И, как показывает этот вопрос, они не стандартизированы.