Zax Zax - 3 months ago 19
Android Question

Date conversion to a different locale

I am working on an

project in which I'm implementing localization.

I'll be getting the locale and the time zone. Using this information, I have written the below code:

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()));

The log that I'm getting from the above code is:

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

So, basically the problem I'm facing is only the
i.e: the month part is getting converted into the Locale specified (in above language it is Hindi(hi-IN)). However, the
"dd yyyy"
is not getting converted into Hindi.

Can someone tell me what am I doing wrong or how can I make sure that even the dd and yyyy part also get converted to the specified locale.


Arabic versus Hindu styled numerals

Apparently you expected the digits to be converted from the Arabic style to the Hindu style, as seen in this Wikipedia article on Arabic-Hindu numerals. (Not that I know anything about this subject. Please forgive any inappropriate use of language/country/tradition terms here.)

Image of variations on the Arabic-Hindu numerals (sourced from Wikipedia)

Your Question does not make obvious that you were after the alternative style of numeral digits; please take more care when posting to Stack Overflow.

Arabic style on Oracle Java 8

FYI, I ran the following code using the modern java.time classes rather than the troublesome legacy date-time classes used in the Question. I get only the Arabic style of numerals.

I loop through an arbitrary collection of Locale objects. For each I loop through all four of FormatStyle objects to specify the length of abbreviation to use in automatically localizing the output of the current moment.

ZoneId z = ZoneId.of ( "America/Montreal" );
ZonedDateTime zdt = ( 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 ( "—————" );

When run on the Oracle implementation of Java SE 8 Update 102 on 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 अपराह्न

Mystery: Legacy classes perform differently than java.time classes

Strangely, when I use the exact source code from the Question, I too get the same output as that seen in the Answer by Dac Saunders with the Hindu/Indian-style numerals.

So I simplified that code. That source code was extraneously instantiating a java.util.Calendar object when in fact a java.util.Date object was being formatted. So I deleted the Calendar entirely.

Locale l = new Locale ( "hi" , "IN" );

// java.time
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "MMMM dd uuuu" ).withLocale ( l );
System.out.println ( ().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

सितंबर ०७ २०१६

While I do not fully understand this behavior, it seems we can draw two conclusions based on the Android behavior of Zax, the Ubuntu Linux experience of Dac Saunders, and my experience on macOS:

  • Android implementation of legacy date-time classes differs from that of Linux & macOS. In Android, Arabic-style digits while on Linux/macOS we get Hindu-style.
  • The java.time classes give only Arabic-style digits, differing in behavior from the legacy classes they supplant where we get Hindu-style. Perhaps a bug report should be filed.

About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.

The Joda-Time project, now in maintenance mode, advises migration to java.time.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.

Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to use…).

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.