Я работаю над проектом Android
, в котором я выполняю локализацию.
Я получу регион и часовой пояс. Используя эту информацию, я написал следующий код:
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()));
Журнал, который я получаю из приведенного выше кода:
**********Newly converted date:सितंबर 07 2016
Итак, в основном проблема, с которой я сталкиваюсь, - это только "MMMM"
, то есть часть месяца преобразуется в указанный языковой стандарт (на языке выше это хинди (привет-IN)). Однако "dd yyyy"
не переводится на хинди.
Может ли кто-нибудь сказать мне, что я делаю не так или как я могу убедиться, что даже части dd и yyyy также будут преобразованы в указанную локаль.
3 ответа
Сравнение арабских и индуистских цифр
По-видимому, вы ожидали, что цифры будут преобразованы из арабского стиля в индуистский стиль, как показано в этой статье в Википедии о Арабско-индуистские цифры. (Не то чтобы я что-нибудь по этому поводу. Прошу прощения за неуместное использование здесь терминов языка / страны / традиции.)
Ваш Вопрос не делает очевидным, что вы выбрали альтернативный стиль цифровых цифр; пожалуйста, будьте осторожны при публикации в Stack Overflow.
Арабский стиль в Oracle Java 8
К вашему сведению, я запустил следующий код, используя современные классы java.time, а не утомительные устаревшие классы даты и времени, используемые в Вопросе. Я получаю только арабский стиль цифр.
Я просматриваю произвольную коллекцию Locale
объектов. Для каждого цикла я просматриваю все четыре FormatStyle
, чтобы указать длину аббревиатуры, которая будет использоваться для автоматической локализации вывода текущего момента.
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 ( "—————" );
При запуске в реализации Oracle Java SE 8 Update 102 на 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 अपराह्न
—————
Тайна: устаревшие классы работают иначе, чем классы java.time
Как ни странно, когда я использую точный исходный код из Вопроса, я тоже получаю тот же результат, что и в Ответе Дака Сондерса a> с цифрами в индуистском / индийском стиле.
Поэтому я упростил этот код. Этот исходный код извне создавал экземпляр объекта java.util.Calendar
, когда на самом деле форматировался объект java.util.Date
. Поэтому я полностью удалил Calendar
.
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
सितंबर ०७ २०१६
Хотя я не полностью понимаю это поведение, похоже, мы можем сделать два вывода на основе поведения Zax для Android, опыта работы Dac Saunders с Ubuntu Linux и моего опыта работы с macOS:
- Реализация устаревших классов даты и времени в Android отличается от реализации в Linux и macOS. В Android цифры в арабском стиле, а в Linux / macOS - в индуистском стиле.
- Классы java.time выдают только цифры в арабском стиле, отличаясь поведением от устаревших классов, которые они вытесняют там, где мы получаем индусский стиль. Возможно, следует отправить отчет об ошибке.
О java.time
Структура java.time - это встроен в Java 8 и новее. Эти классы заменяют неудобные старые классы даты и времени, такие как java.util.Date
, .Calendar
и java.text.SimpleDateFormat
.
Проект Joda-Time теперь в режим обслуживания, советует перейти на java.time.
Чтобы узнать больше, см. Учебник Oracle. И поищите в Stack Overflow множество примеров и объяснений.
Большая часть функций java.time перенесена на Java 6 и 7 в ThreeTen-Backport и дополнительно адаптирован к Android в ThreeTenABP (см. Как использовать… ).
Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательной площадкой для возможных будущих дополнений к java.time. Здесь вы можете найти несколько полезных классов, таких как Interval
, YearWeek
, YearQuarter
и другие.
Вроде работает:
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() ));
}
}
Контрольная работа:
/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
Вы можете попробовать программу в Интернете.
Почему форматеры иногда используют арабские, иногда индуистские цифры?
Механизмы форматирования, стоящие за SimpleDateFormat
или { {X1}} (на Java 8) использует локализованные ресурсы, которые изначально основаны на Common Locale Date Repository (CLDR) данные из Консорциума Unicode. В более старых данных CLDR (например, v17) мы находим систему нумерации по умолчанию для языка хинди (iso-639-code hi):
<defaultNumberingSystem>deva</defaultNumberingSystem>
Но последняя CLDR-версия v29 показывает:
<defaultNumberingSystem>latn</defaultNumberingSystem>
Кодовые слова CLDR «deva» и «latn» представляют индусские цифры (начиная с кодовой точки 0x966) соответственно. арабские цифры 0-9. Так что поведение Java- или Android-платформы зависит от версии. Старые версии платформы используют старые данные, а новые версии используют обновленные данные CLDR. Для мобильных телефонов сложно или даже невозможно предсказать, какие данные Android действительно будет использовать. Не каждый пользователь используется для обновления версии Android, и иногда производитель также манипулирует ресурсами.
Можно ли настроить систему счисления, используемую форматерами?
ДА! Я показываю три пути.
А) 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())); // सितंबर २३ २०१६
Б) java.time.format.DateTimeFormatter (на Android можно использовать ThreetenABP вместо)
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)); // सितंबर २३ २०१६
Примечание. Это решение по-прежнему использует ресурсы платформы Android (например, поиск названий месяцев в Android).
C) Моя библиотека Time4A (управляет собственными независимыми i18n-ресурсами)
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())); // सितंबर २३ २०१६
Похожие вопросы
Связанные вопросы
Новые вопросы
java
Java — это высокоуровневый объектно-ориентированный язык программирования. Используйте этот тег, если у вас возникли проблемы с использованием или пониманием самого языка. Этот тег часто используется вместе с другими тегами для библиотек и/или фреймворков, используемых разработчиками Java.