Reputation: 3010
I am working on an Android
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 "MMMM"
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.
Upvotes: 3
Views: 2166
Reputation: 44061
The format engines behind SimpleDateFormat
or DateTimeFormatter
(on Java 8) uses localized resources which are originally based the Common Locale Date Repository (CLDR) data from The Unicode Consortium. In older CLDR data (for example v17) we find as default numbering system for the language Hindi (iso-639-code hi):
<defaultNumberingSystem>deva</defaultNumberingSystem>
But the newest CLDR-version v29 shows:
<defaultNumberingSystem>latn</defaultNumberingSystem>
The CLDR code words "deva" and "latn" represent the Hindu digits (starting at codepoint 0x966) resp. the Arabic digits 0-9. So the behaviour of the Java- or Android-platform depends on the version. Old versions of the platform use old data while newer versions use the updated CLDR-data. For mobile phones, it is hard or even impossible to predict which data Android will really use. Not every user is used to update the Android version, and sometimes the manufacturer manipulates the resources, too.
YES! I show three ways.
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 (on Android you could use ThreetenABP instead)
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)); // सितंबर २३ २०१६
Note: This solution still uses the resources of the Android platform (for example looking for the month names in Android).
c) My library Time4A (manages its own independent i18n-resources)
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())); // सितंबर २३ २०१६
Upvotes: 2
Reputation: 338201
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.)
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.
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 = 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 ( "—————" );
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 अपराह्न
—————
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 ( 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
सितंबर ०७ २०१६
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:
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.
Upvotes: 2
Reputation: 26652
It looks like it works:
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() ));
}
}
Test:
/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
You can please try the program online.
Upvotes: 2