¿Cómo obtengo una cadena de patrón de fecha localizada?

Es bastante fácil formatear y analizar clases de Java Date (o Calendar) con instancia de DateFormat , es decir, podría formatear la fecha actual en una fecha de localización corta como esta:

DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()); String today = formatter.format(new Date()); 

Mi problema es: necesito obtener esta cadena de patrones localizados (es decir, algo así como "MM/dd/yy" ). Esto debería ser una tarea trivial, pero no pude encontrar el proveedor …

Para SimpleDateFormat , llama aLoLocalizedPattern ()

EDITAR:

Para usuarios de Java 8:

Java 8 Date Time API es similar a Joda-time. Para obtener un patrón localizado podemos usar la clase DateTimeFormatter

DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM);

Tenga en cuenta que cuando llama aString () en LocalDate, obtendrá la fecha en formato ISO-8601

Tenga en cuenta que Date Time API en Java 8 está inspirado en Joda Time y la mayoría de las soluciones se pueden basar en preguntas relacionadas con el tiempo.

Para aquellos que todavía usan Java 7 y versiones anteriores:

Puedes usar algo como esto:

 DateFormat formatter = DateFormat.getDateInstance(DateFormat.SHORT, Locale.getDefault()); String pattern = ((SimpleDateFormat)formatter).toPattern(); String localPattern = ((SimpleDateFormat)formatter).toLocalizedPattern(); 

Dado que DateFormat devuelto desde getDateInstance() es instancia de SimpleDateFormat . Esos dos métodos deberían estar realmente en el DateFormat también para que esto sea menos hacky, pero actualmente no lo son.

Puede ser extraño, estoy respondiendo mi propia pregunta, pero creo que puedo agregar algo a la imagen.

Implementación de la UCI

Obviamente, Java 8 te da mucho, pero también hay algo más: ICU4J . Esta es en realidad la fuente de la implementación original de Java de elementos como Calendar , DateFormat y SimpleDateFormat , por nombrar algunos.
Por lo tanto, no debería sorprender que SimpleDateFormat de ICU también contenga métodos como toPattern() o toLocalizedPattern() . Puedes verlos en acción aquí:

 DateFormat fmt = DateFormat.getPatternInstance( DateFormat.YEAR_MONTH, Locale.forLanguageTag("pl-PL")); if (fmt instanceof SimpleDateFormat) { SimpleDateFormat sfmt = (SimpleDateFormat) fmt; String pattern = sfmt.toPattern(); String localizedPattern = sfmt.toLocalizedPattern(); System.out.println(pattern); System.out.println(localizedPattern); } 

Mejoras de ICU

Esto no es nada nuevo, pero lo que realmente quería señalar es esto:

 DateFormat.getPatternInstance(String pattern, Locale locale); 

Este es un método que puede devolver un conjunto completo de patrones específicos de la configuración regional, como por ejemplo:

  • ABBR_QUARTER
  • TRIMESTRE
  • AÑO
  • YEAR_ABBR_QUARTER
  • YEAR_QUARTER
  • YEAR_ABBR_MONTH
  • AÑO MES
  • YEAR_NUM_MONTH
  • YEAR_ABBR_MONTH_DAY
  • YEAR_NUM_MONTH_DAY
  • AÑO MES DIA
  • YEAR_ABBR_MONTH_WEEKDAY_DAY
  • YEAR_MONTH_WEEKDAY_DAY
  • YEAR_NUM_MONTH_WEEKDAY_DAY
  • ABBR_MONTH
  • MES
  • NUM_MONTH
  • ABBR_STANDALONE_MONTH
  • STANDALONE_MONTH
  • ABBR_MONTH_DAY
  • MES DIA
  • NUM_MONTH_DAY
  • ABBR_MONTH_WEEKDAY_DAY
  • MONTH_WEEKDAY_DAY
  • NUM_MONTH_WEEKDAY_DAY
  • DÍA
  • ABBR_WEEKDAY
  • DÍA LABORABLE
  • HORA
  • HOUR24
  • HOUR_MINUTE
  • HOUR_MINUTE_SECOND
  • HOUR24_MINUTE
  • HOUR24_MINUTE_SECOND
  • HOUR_TZ
  • HOUR_GENERIC_TZ
  • HOUR_MINUTE_TZ
  • HOUR_MINUTE_GENERIC_TZ
  • MINUTO
  • MINUTE_SECOND
  • SEGUNDO
  • ABBR_UTC_TZ
  • ABBR_SPECIFIC_TZ
  • SPECIFIC_TZ
  • ABBR_GENERIC_TZ
  • GENERIC_TZ
  • LOCATION_TZ

Claro, hay bastantes. Lo bueno de ellos es que estos patrones son en realidad cadenas (como en java.lang.String ), es decir, si usas el patrón inglés "MM/d" , obtendrás a cambio un patrón específico de configuración regional. Puede ser útil en algunos casos de esquina. Por lo general, solo usaría la instancia de DateFormat , y no le importaría el patrón en sí.

Patrón específico de configuración regional frente a patrón localizado

La intención de la pregunta era ser localizado, y no el patrón específico de la configuración regional. ¿Cual es la diferencia?

En teoría, toPattern() le dará un patrón específico de configuración regional (dependiendo de la Locale que utilizó para crear una instancia (Simple)DateFormat ). Es decir, sin importar el idioma o país de destino que coloque, obtendrá el patrón compuesto de símbolos como y , M , d , h , H , M , etc.

Por otro lado, toLocalizedPattern() debería devolver un patrón localizado, que es algo que los usuarios finales deben leer y comprender. Por ejemplo, el patrón de fecha medio (predeterminado) alemán sería:

  • toPattern (): dd.MM.aaaa
  • toLocalizedPattern (): tt.MM.jjjj (día = Etiqueta, mes = Monat, año = Jahr)

La intención de la pregunta era: “cómo encontrar el patrón localizado que podría servir como pista sobre el formato de fecha / hora”. Es decir, supongamos que tenemos un campo de fecha que el usuario puede completar utilizando el patrón específico de la configuración regional, pero quiero mostrar una sugerencia de formato en la forma localizada.

Lamentablemente, hasta ahora no hay una buena solución. La UCI que mencioné anteriormente en esta publicación, funciona parcialmente. Esto se debe a que los datos que utiliza ICU provienen de CLDR , que lamentablemente está parcialmente traducido / parcialmente correcto. En el caso de la lengua de mi madre, en el momento de escribir esto, ni los patrones, ni sus formas localizadas se traducen correctamente. Y cada vez que los corrijo, me ganaron otras dos personas, que no es necesario vivir en Polonia, ni hablar polaco …

La moraleja de esta historia: no confíes plenamente en CLDR. Aún necesita tener auditores locales / revisores lingüísticos.

Puede usar DateTimeFormatterBuilder en Java 8. El siguiente ejemplo devuelve un patrón de fecha localizada, por ejemplo, "dMyyyy" .

 String datePattern = DateTimeFormatterBuilder.getLocalizedDateTimePattern( FormatStyle.SHORT, null, IsoChronology.INSTANCE, Locale.GERMANY); // or whatever Locale 

El siguiente código le dará el patrón para la configuración regional:

 final String pattern1 = ((SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale)).toPattern(); System.out.println(pattern1); 

Java 8 proporciona algunas funciones útiles listas para utilizar con el formato y la fecha / hora de análisis, incluido el manejo de configuraciones regionales. Aquí hay una breve introducción.

Patrones básicos

En el caso más simple para formatear / analizar una fecha, usaría el siguiente código con un patrón de Cadena:

 DateTimeFormatter.ofPattern("MM/dd/yyyy") 

El estándar es usar esto con el objeto de fecha directamente para formatear:

 return LocalDate.now().format(DateTimeFormatter.ofPattern("MM/dd/yyyy")); 

Y luego usando el patrón de fábrica para analizar una fecha:

 return LocalDate.parse(dateString, DateTimeFormatter.ofPattern("MM/dd/yyyy")); 

El patrón en sí tiene una gran cantidad de opciones que cubrirán la mayoría de las cajas de uso, aquí se puede encontrar un resumen completo en la ubicación de javadoc.

Locales

La inclusión de una configuración regional es bastante simple, para la configuración regional predeterminada tiene las siguientes opciones que luego se pueden aplicar a las opciones de formato / análisis demostradas anteriormente:

 DateTimeFormatter.ofLocalizedDate(dateStyle); 

El ‘dateStyle’ anterior es una opción FormatStyle Enum para representar las versiones completa, larga, media y corta de la Fecha localizada cuando se trabaja con DateTimeFormatter . Con FormatStyle también tiene las siguientes opciones:

 DateTimeFormatter.ofLocalizedTime(timeStyle); DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle); DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle, timeStyle); 

La última opción le permite especificar un FormatStyle diferente para la fecha y la hora. Si no está trabajando con la Configuración regional predeterminada, la devolución de cada uno de los métodos Localizados se puede ajustar utilizando la opción .withLocale, por ejemplo

 DateTimeFormatter.ofLocalizedTime(timeStyle).withLocale(Locale.ENGLISH); 

Alternativamente, the ofPattern tiene una versión sobrecargada para especificar la configuración regional también

 DateTimeFormatter.ofPattern("MM/dd/yyyy",Locale.ENGLISH); 

¡Necesito más!

DateTimeFormatter cumplirá con la mayoría de los casos de uso, sin embargo, se basa en DateTimeFormatterBuilder, que proporciona una gran variedad de opciones para el usuario del generador. Use DateTimeFormatter para comenzar y, si necesita estas amplias características de formato, vuelva al constructor.

Busque en el código a continuación que acepta la instancia de configuración regional y devuelve el formato / patrón de datos específicos de la configuración regional.

  public static String getLocaleDatePattern(Locale locale) { // Validating if Locale instance is null if (locale == null || locale.getLanguage() == null) { return "MM/dd/yyyy"; } // Fetching the locale specific date pattern String localeDatePattern = ((SimpleDateFormat) DateFormat.getDateInstance( DateFormat.SHORT, locale)).toPattern(); // Validating if locale type is having language code for Chinese and country // code for (Hong Kong) with Date Format as - yy'?'M'?'d'?' if (locale.toString().equalsIgnoreCase("zh_hk")) { // Expected application Date Format for Chinese (Hong Kong) locale type return "yyyy'MM'dd"; } // Replacing all d|m|y OR Gy with dd|MM|yyyy as per the locale date pattern localeDatePattern = localeDatePattern.replaceAll("d{1,2}", "dd").replaceAll( "M{1,2}", "MM").replaceAll("y{1,4}|Gy", "yyyy"); // Replacing all blank spaces in the locale date pattern localeDatePattern = localeDatePattern.replace(" ", ""); // Validating the date pattern length to remove any extract characters if (localeDatePattern.length() > 10) { // Keeping the standard length as expected by the application localeDatePattern = localeDatePattern.substring(0, 10); } return localeDatePattern; } 

Dado que es solo la información de localización que buscas, creo que lo que tendrás que hacer es ubicar el archivo que la JVM (OpenJDK o Harmony) realmente usa como entrada para toda la localización y averiguar cómo analizarlo. O simplemente use otra fuente en la web (seguramente hay una lista en alguna parte). Eso salvará a esos pobres traductores.

Puedes probar algo como:

 LocalDate fromCustomPattern = LocalDate.parse("20.01.2014", DateTimeFormatter.ofPattern("MM/dd/yy")) 

No estoy seguro de lo que quieres, pero …

Ejemplo de SimpleDateFormat:

 SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yy"); Date date = sdf.parse("12/31/10"); String str = sdf.format(new Date());