Conversión de fecha a un idioma diferente

Estoy trabajando en un proyecto de Android en el que implemento la localización.

Voy a estar recibiendo la configuración regional y la zona horaria. Usando esta información, he escrito el siguiente código:

 String []locale= User.getInstance().getLanguage().split("-");//Assume, locale[0]=hi, locale[1]=IN Calendar choosenDate = Calendar.getInstance(new Locale(locale[0],locale[1])); SimpleDateFormat Dformat = new SimpleDateFormat("MMMM dd yyyy",new Locale(locale[0],locale[1])); Log.d("MY_APP","***********Newly converted date:"+Dformat.format(choosenDate.getTime())); 

El registro que obtengo del código anterior es:

 **********Newly converted date:सितंबर 07 2016 

Por lo tanto, básicamente el problema que estoy enfrentando es sólo el "MMMM" es decir: la parte del mes se está convirtiendo en la localidad especificada (en el idioma anterior es Hindi (hi-IN)). Sin embargo, el "dd yyyy" no se está convirtiendo en hindi.

¿Puede alguien decirme qué estoy haciendo mal o cómo puedo asegurarme de que incluso la parte ddyyyy también se convierten a la configuración especificada.

Los números de estilo árabe versus hindú

Aparentemente esperabas que los dígitos se convirtieran del estilo árabe al estilo hindú, como se ve en este artículo de Wikipedia sobre números árabe-hindúes . (No es que yo sepa algo sobre este tema. Por favor perdone cualquier uso inadecuado de términos de idioma / país / tradición aquí.)

Imagen de las variaciones de los números árabe-hindúes (procedentes de Wikipedia)

Su pregunta no hace obvio que usted estaba después del estilo alternativo de dígitos numéricos; por favor tenga más cuidado al publicar en Desbordamiento de pila.

Estilo árabe en Oracle Java 8

FYI, corrí el código siguiente usando las clases java.time modernas en lugar de las clases de fecha-hora heredadas problemáticas usadas en la Pregunta. Tengo sólo el estilo árabe de los números.

Hago un bucle a través de una colección arbitraria de objetos Locale . Para cada I bucle a través de los cuatro de FormatStyle objetos para especificar la longitud de la abreviatura para utilizar en la localización automática de la salida del momento actual.

 ZoneId z = ZoneId.of ( "America/Montreal" ); ZonedDateTime zdt = ZonedDateTime.now ( z ); List<Locale> locales = new ArrayList<> (); locales.add ( Locale.US ); locales.add ( Locale.CANADA_FRENCH ); locales.add ( Locale.TAIWAN ); locales.add ( new Locale ( "hi" , "IN" ) ); // Hindi, India. // locales.add ( new Locale ( "ar" , "MA" ) ); // Arabic, Morocco EnumSet<FormatStyle> formatStyles = EnumSet.allOf ( FormatStyle.class ); for ( Locale locale : locales ) { System.out.println ( "—————" ); System.out.println ( "Locale: " + locale ); for ( FormatStyle formatStyle : formatStyles ) { DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime ( formatStyle ).withLocale ( locale ); System.out.println ( String.format ( "%1$-" + 20 + "s" , "FormatStyle: " + formatStyle ) + " → " + zdt.format ( f ) ); } } System.out.println ( "—————" ); 

Cuando se ejecuta en la implementación de Oracle de Java SE 8 Update 102 en macOS.

 ————— Locale: en_US FormatStyle: FULL → Wednesday, September 7, 2016 6:46:00 PM EDT FormatStyle: LONG → September 7, 2016 6:46:00 PM EDT FormatStyle: MEDIUM → Sep 7, 2016 6:46:00 PM FormatStyle: SHORT → 9/7/16 6:46 PM ————— Locale: fr_CA FormatStyle: FULL → mercredi 7 septembre 2016 18 h 46 EDT FormatStyle: LONG → 7 septembre 2016 18:46:00 EDT FormatStyle: MEDIUM → 2016-09-07 18:46:00 FormatStyle: SHORT → 16-09-07 18:46 ————— Locale: zh_TW FormatStyle: FULL → 2016年9月7日 星期三 下午06時46分00秒 EDT FormatStyle: LONG → 2016年9月7日 下午06時46分00秒FormatStyle: MEDIUM → 2016/9/7 下午 06:46:00 FormatStyle: SHORT → 2016/9/7 下午 6:46 ————— Locale: hi_IN FormatStyle: FULL → बुधवार, 7 सितंबर, 2016 6:46:00 अपराह्न EDT FormatStyle: LONG → 7 सितंबर, 2016 6:46:00 अपराह्न EDT FormatStyle: MEDIUM → 7 सितंबर, 2016 6:46:00 अपराह्न FormatStyle: SHORT → 7/9/16 6:46 अपराह्न ————— 

Misterio: Las clases heredadas se desempeñan de forma diferente que las clases java.time

Curiosamente, cuando uso el código fuente exacto de la Cuestión, también obtengo la misma salida que la que se ve en la Respuesta de Dac Saunders con los números de estilo hindú / indio .

Así que simplifiqué ese código. Ese código fuente era instanciar java.util.Calendar un objeto java.util.Calendar cuando de hecho un objeto java.util.Date estaba siendo formateado. Así que borré el Calendar completamente.

 Locale l = new Locale ( "hi" , "IN" ); // java.time DateTimeFormatter f = DateTimeFormatter.ofPattern ( "MMMM dd uuuu" ).withLocale ( l ); System.out.println ( ZonedDateTime.now ().format ( f ) ); // Legacy date-time classes. SimpleDateFormat dFormat = new SimpleDateFormat ( "MMMM dd yyyy" , l ); System.out.println ( dFormat.format ( new java.util.Date () ) ); 

सितंबर 07 2016

सितंबर 07 2016

Aunque no entiendo completamente este comportamiento, parece que podemos sacar dos conclusiones basadas en el comportamiento de Zax de Android, la experiencia de Ubuntu Linux de Dac Saunders y mi experiencia con macOS:

  • La implementación de Android de las clases de fecha y hora heredadas difiere de la de Linux y macOS. En Android, los dígitos de estilo árabe, mientras que en Linux / macOS tenemos estilo hindú.
  • Las clases java.time dan sólo dígitos de estilo árabe, que difieren en el comportamiento de las clases heredadas que suplantan en las que se obtiene el estilo hindú. Tal vez un informe de fallo debe ser presentado.

Acerca de java.time

El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantan las viejas y java.text.SimpleDateFormat clases de fecha y hora, como java.util.Date , .Calendar , y java.text.SimpleDateFormat .

El proyecto Joda-Time , ahora en modo de mantenimiento , recomienda la migración a java.time.

Para obtener más información, consulte el Tutorial de Oracle . Y busca Stack Overflow para muchos ejemplos y explicaciones.

Gran parte de la funcionalidad de java.time se retroporta a Java 6 y 7 en ThreeTen-Backport y se adapta a Android en ThreeTenABP (consulte Cómo utilizar … ).

El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un terreno probatorio para posibles adiciones futuras a java.time. Puede encontrar algunas clases útiles como Interval , YearWeek , YearQuarter y más.

Parece que funciona:

 import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Locale; public class Main { public static void main(String[] args) { System.out.println("Hello World!"); String []locale = {"hi", "IN"}; Calendar choosenDate = Calendar.getInstance(new Locale(locale[0],locale[1])); SimpleDateFormat Dformat = new SimpleDateFormat("MMMM dd yyyy",new Locale(locale[0],locale[1])); System.out.println("MY_APP***********Newly converted date:"+ Dformat.format(choosenDate.getTime() )); } } 

Prueba:

 /usr/lib/jvm/java-1.8.0-openjdk-amd64/bin/java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:32790,suspend=y,server=n -Dfile.encoding=UTF-8 -classpath /usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/charsets.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/cldrdata.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/dnsns.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/icedtea-sound.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/jaccess.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/localedata.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/nashorn.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/sunec.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/sunjce_provider.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/sunpkcs11.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/ext/zipfs.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/jce.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/jsse.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/management-agent.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/resources.jar:/usr/lib/jvm/java-1.8.0-openjdk-amd64/jre/lib/rt.jar:/home/dac/proj/javatest2016/out/production/javatest2016:/home/dac/Downloads/idea-IU-145.972.3/lib/idea_rt.jar Main Connected to the target VM, address: '127.0.0.1:32790', transport: 'socket' Hello World! MY_APP***********Newly converted date:सितंबर ०७ २०१६ Disconnected from the target VM, address: '127.0.0.1:32790', transport: 'socket' Process finished with exit code 0 

Puede probar el programa en línea .

¿Por qué los formateadores utilizan a veces los dígitos árabes a veces hindúes?

Los motores de formato detrás de SimpleDateFormat o DateTimeFormatter (en Java 8) usan recursos localizados que se basan originalmente en los datos del Local Community Date Repository (CLDR) del Consorcio Unicode . En datos más antiguos de CLDR (por ejemplo v17) encontramos como sistema de numeración por defecto para el idioma hindi (iso-639-code hi):

 <defaultNumberingSystem>deva</defaultNumberingSystem> 

Pero la más reciente versión CLDR-v29 muestra :

 <defaultNumberingSystem>latn</defaultNumberingSystem> 

Las palabras de código CLDR "deva" y "latn" representan los dígitos hindúes (comenzando en el código 0x966) resp. los dígitos árabes 0-9. Así que el comportamiento de la plataforma Java o Android depende de la versión. Las versiones antiguas de la plataforma utilizan datos antiguos mientras que las versiones más recientes usan los datos CLDR actualizados. Para teléfonos móviles, es difícil o incluso imposible predecir qué datos Android realmente utilizará. No todos los usuarios se utilizan para actualizar la versión de Android, ya veces el fabricante también manipula los recursos.

¿Se puede configurar el sistema numérico utilizado por los formateadores?

¡SÍ! Muestra tres maneras.

a) java.text.SimpleDateFormat

 Locale hindi = new Locale("hi", "IN"); DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(hindi); char required = '०'; // copied from your comment DecimalFormat numberFormat = new DecimalFormat(); dfs.setZeroDigit(required); // or any other zero digit like '0' numberFormat.setDecimalFormatSymbols(dfs); SimpleDateFormat sdf = new SimpleDateFormat("MMMM dd yyyy", hindi); sdf.setNumberFormat(numberFormat); System.out.println("SimpleDateFormat: " + sdf.format(new Date())); // सितंबर २३ २०१६ 

b) java.time.format.DateTimeFormatter (en Android puedes usar ThreetenABP en su lugar)

 Locale hindi = new Locale("hi", "IN"); char required = '०'; // copied from your comment DecimalStyle style = DecimalStyle.of(hindi).withZeroDigit(required); DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMMM dd yyyy", hindi).withDecimalStyle(style); System.out.println("java.time: " + LocalDate.now().format(dtf)); // सितंबर २३ २०१६ 

Nota: Esta solución todavía utiliza los recursos de la plataforma Android (por ejemplo, buscar los nombres de mes en Android).

c) Mi biblioteca Time4A (gestiona sus propios recursos i18n independientes)

 Locale hindi = new Locale("hi", "IN"); ChronoFormatter<PlainDate> cf = ChronoFormatter.ofDatePattern("MMMM dd yyyy", PatternType.CLDR, hindi).with( Attributes.NUMBER_SYSTEM, NumberSystem.DEVANAGARI ); System.out.println("Time4A: " + cf.format(PlainDate.nowInSystemTime())); // सितंबर २३ २०१६ 
  • Recuperación de los mensajes SMS desde la tarjeta SIM con android
  • SecurityException: No se puede encontrar el campo para dex.jar android
  • ¿Cómo puedo obtener nodos específicos de XML usando XPath en Java?
  • No se puede realizar la comprobación de instancia contra el tipo parametrizado ArrayList <Foo>
  • Menú en la barra del sistema de Android 3.0
  • ¿Cómo saber si la cámara está en uso?
  • ¿Cómo puede una aplicación Android funcionar como un controlador remoto a una aplicación de escritorio? (Spotify)
  • IllegalStateException: <MyFragment> no está actualmente en el FragmentManager
  • Obtener OnActivityResult al volver de startActivityForResult en Adapter
  • Cómo borrar la imagen con el dedo en Android
  • El mensaje de HttpPost de Android no enviará su carga útil a través del cable
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.