Как я могу получить "текущую" аббревиатуру часового пояса IANA в течение всего времени в ICU4J?
В настоящее время я пытаюсь написать набор программ проверки часовых поясов, чтобы узнать, интерпретируют ли различные платформы время IANA данные зоны.
Формат вывода, на который я нацелен, включает аббревиатуру, действующую в течение определенного времени - например, "BST" для "Британского летнего времени" или "PST" для "Тихоокеанского стандартного времени".
На большинстве платформ это легко - но ICU4J, похоже, не работает, как ни странно. Согласно документации SimpleDateFormat
, я должен использовать шаблон "zzz", чтобы получить то, что я ищу, но это, похоже, возвращается к "O" в GMT + X в течение долгого времени. Для некоторых часовых поясов аббревиатуры вообще отсутствуют.
Короткий пример с использованием Нью-Йорка:
import java.util.Date;
import java.util.Locale;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.text.SimpleDateFormat;
public class Test {
public static void main(String[] args) {
TimeZone zone = TimeZone.getTimeZone("America/New_York");
SimpleDateFormat format = new SimpleDateFormat("zzz", Locale.US);
format.setTimeZone(zone);
// One month before the unix epoch
System.out.println(format.format(new Date(-2678400000L))); // GMT-5
// At the unix epoch
System.out.println(format.format(new Date(0L))); // EST
}
}
(Я запускаю с помощью ICU4J 55.1, как загрузку запаса, так и после обновления с выпуском данных 2015e.)
Мне не ясно, получает ли ICU4J свои сокращения из данных tz или из CLDR - я подозреваю, что это последнее, учитывая, что в данных tz нет ничего, чтобы предложить здесь разницу.
На него, похоже, также влияет языковой стандарт, который, я полагаю, является разумным - с использованием американского языка я могу видеть EST/EDT для America/New_York, но ничего для Европы/Лондона; с британским языком я вижу GMT/BST для Европы/Лондона, но ничего для Америки /New _York: (
Есть ли способ убедить ICU4J вернуться к сокращениям tz? В моем конкретном случае, все, что я ищу.
Обновление
Благодаря комментариям RealSkeptic, похоже, что TimeZoneNames
- более чистый способ получения этих данных без форматирования. Все это звучит так многообещающе - там даже TimeZoneNames.getTZDBInstance
:
Возвращает экземпляр TimeZoneNames, содержащий только короткие имена определенных зон (TimeZoneNames.NameType.SHORT_STANDARD
и TimeZoneNames.NameType.SHORT_DAYLIGHT
), совместимые с аббревиатурами зоны базы данных IANA tz (не локализованные).
Это в значительной степени то, что я хочу - но это не происходит в 1970 году в большинстве случаев и не включает в себя все соответствующие данные:
import static com.ibm.icu.text.TimeZoneNames.NameType.SHORT_STANDARD;
import com.ibm.icu.text.TimeZoneNames;
import com.ibm.icu.text.TimeZoneNames.NameType;
import com.ibm.icu.util.ULocale;
public class Test {
public static void main(String[] args) {
TimeZoneNames names = TimeZoneNames.getTZDBInstance(ULocale.ROOT);
long december1969 = -2678400000L;
// 24 hours into the Unix epoch...
long january1970 = 86400000L;
// null
System.out.println(
names.getDisplayName("America/New_York", SHORT_STANDARD, december1969));
// EST
System.out.println(
names.getDisplayName("America/New_York", SHORT_STANDARD, january1970));
// null
System.out.println(
names.getDisplayName("Europe/London", SHORT_STANDARD, december1969));
// null
System.out.println(
names.getDisplayName("Europe/London", NameType.SHORT_STANDARD, january1970));
}
}
Учитывая, что на данный момент на самом деле очень мало косвенности - я говорю ICU4J точно, что хочу, - мое подозрение в том, что информация просто недоступна: (
Ответы
Ответ 1
Прослеживая источники, чтобы узнать, как это работает, выясняется, что для поиска отображаемого имени он получает имя мета зоны от имени зоны и даты, а затем из мета зоны и типа, отображаемое имя.
com.ibm.icu.impl.TZDBTimeZoneNames
, который является классом, возвращаемым из TimeZoneNames.getTZDBInstance(ULocale)
, реализует getMetaZoneID(String,Long)
, вызывая com.ibm.icu.impl.TimeZoneNamesImpl._getMetaZoneID(String,long)
, который извлекает сопоставления из данного имени часового пояса в имена метазоны и затем проверяет, находится ли дата между параметры from
и to
в любом из этих сопоставлений.
Отображение считывается вложенным классом, например:
for (int idx = 0; idx < zoneBundle.getSize(); idx++) {
UResourceBundle mz = zoneBundle.get(idx);
String mzid = mz.getString(0);
String fromStr = "1970-01-01 00:00";
String toStr = "9999-12-31 23:59";
if (mz.getSize() == 3) {
fromStr = mz.getString(1);
toStr = mz.getString(2);
}
long from, to;
from = parseDate(fromStr);
to = parseDate(toStr);
mzMaps.add(new MZMapEntry(mzid, from, to));
}
(источник)
Как вы можете видеть, он имеет жестко заданные значения для значений to
и from
, которые он вернет (хотя он читает to
и from
из самого ресурсного пакета, когда запись метазоны имеет три элемента, большинство из них - нет - как можно видеть в фактическом файле мета-зоны, из которого построен пакет, и тех, кто это делает, также не имеют "от" дат до января 1970 года.)
Таким образом, идентификатор метазоны будет null
для любой даты до января 1970 года, и, в свою очередь, так будет отображаемое имя.