java - ¿Cómo puedo obtener la abreviatura “actual” de la zona horaria de la IANA a lo largo del tiempo en ICU4J?
timezone (1)
Al rastrear las fuentes para ver cómo funciona esto, resulta que para encontrar el nombre para mostrar, obtiene el nombre de la zona meta del nombre de la zona y la fecha, y luego, de la zona meta y el tipo, el nombre de la pantalla .
com.ibm.icu.impl.TZDBTimeZoneNames
, que es la clase devuelta por TimeZoneNames.getTZDBInstance(ULocale)
, implementa getMetaZoneID(String,Long)
llamando a com.ibm.icu.impl.TimeZoneNamesImpl._getMetaZoneID(String,long)
recupera las asignaciones del nombre de la zona horaria dada a los nombres de la meta zona, y luego verifica si la fecha se encuentra entre los parámetros from
y to
en cualquiera de esas asignaciones.
El mapeo es leído por una clase anidada, como esta:
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));
}
( source )
Como puede ver, tiene valores codificados para los valores de ida y vuelta que devolverá (aunque lee la entrada y from
del paquete de recursos cuando la entrada de la meta zona tiene tres elementos, la mayoría de ellos no lo hacen, como se puede ver en el archivo de meta zona real a partir del cual se construye el paquete, y aquellos que sí lo tienen, tampoco tienen fechas "de" antes de enero de 1970.)
Por lo tanto, el ID de la zona meta será null
para cualquier fecha anterior a enero de 1970 y, a su vez, también lo será el nombre para mostrar.
Actualmente estoy intentando escribir un conjunto de programas de validación de zona horaria para ver si varias plataformas interpretan los datos de zona horaria de la IANA .
El formato de salida al que me dirijo incluye la abreviatura vigente para un momento en particular, como "BST" para "British Summer Time", o "PST" para "Pacific Standard Time".
En la mayoría de las plataformas, esto es fácil, pero ICU4J no parece funcionar, por extraño que parezca. De acuerdo con la documentación de SimpleDateFormat
, debería poder usar un patrón de "zzz" para obtener lo que estoy buscando, pero esto parece recurrir al patrón de "O" de GMT + X durante la mayor parte del tiempo. Para algunas zonas horarias, no hay abreviaturas en absoluto.
Ejemplo corto usando Nueva York:
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
}
}
(Estoy ejecutando utilizando ICU4J 55.1, tanto la descarga de stock como después de actualizarla con el lanzamiento de datos de 2015e).
No me queda claro si ICU4J está obteniendo sus abreviaturas de los datos tz o de CLDR. Sospecho que es lo último, dado que no hay nada en los datos tz que sugiera una diferencia aquí.
También parece estar afectado por la configuración regional, que supongo que es razonable: al utilizar la configuración regional de EE. UU. Puedo ver EST / EDT para América / Nueva_York, pero nada para Europa / Londres; con la configuración regional del Reino Unido veo GMT / BST para Europa / Londres, pero nada para América / Nueva_York :(
¿Hay alguna manera de persuadir a ICU4J para que se apoye en las abreviaturas tz? En mi caso muy específico, eso es todo lo que estoy buscando.
Actualizar
Gracias a los comentarios de RealSkeptic, parece que TimeZoneNames
es una forma más limpia de obtener estos datos sin formatear. Todo suena muy prometedor, incluso hay TimeZoneNames.getTZDBInstance
:
Devuelve una instancia de TimeZoneNames que contiene solo nombres de zona cortos específicos (
TimeZoneNames.NameType.SHORT_STANDARD
yTimeZoneNames.NameType.SHORT_DAYLIGHT
), compatible con las abreviaturas de zona de la base de datos IANA tz (no localizadas).
Eso es casi exactamente lo que quiero, pero en la mayoría de los casos no es anterior a 1970, ni incluye todos los datos relevantes:
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));
}
}
Dado que realmente hay muy poca indirección en este punto, le estoy diciendo a ICU4J exactamente lo que quiero, mi sospecha es que la información simplemente no está disponible :(