Я работаю над проектом 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
Zax 7 Сен 2016 в 11:38

3 ответа

Лучший ответ

Сравнение арабских и индуистских цифр

По-видимому, вы ожидали, что цифры будут преобразованы из арабского стиля в индуистский стиль, как показано в этой статье в Википедии о Арабско-индуистские цифры. (Не то чтобы я что-нибудь по этому поводу. Прошу прощения за неуместное использование здесь терминов языка / страны / традиции.)

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

Ваш Вопрос не делает очевидным, что вы выбрали альтернативный стиль цифровых цифр; пожалуйста, будьте осторожны при публикации в 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

Как ни странно, когда я использую точный исходный код из Вопроса, я тоже получаю тот же результат, что и в Ответе Дака Сондерса с цифрами в индуистском / индийском стиле.

Поэтому я упростил этот код. Этот исходный код извне создавал экземпляр объекта 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 и другие.

2
Community 23 Май 2017 в 12:19

Вроде работает:

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

Вы можете попробовать программу в Интернете.

2
Niklas R. 7 Сен 2016 в 09:42

Почему форматеры иногда используют арабские, иногда индуистские цифры?

Механизмы форматирования, стоящие за 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())); // सितंबर २३ २०१६
2
Basil Bourque 24 Сен 2016 в 03:22