Строка формата SimpleDateFormat и локали


83

Я пытаюсь отформатировать дату на Java по-разному в зависимости от данной локали. Например, я хочу, чтобы англоязычные пользователи видели «1 ноября 2009 г.» (отформатировано «MMM d, yyyy»), а норвежские пользователи - «1 ноября 2009 г.» («d. MMM. Yyyy»).

Часть месяца работает нормально, если я добавляю языковой стандарт в конструктор SimpleDateFormat, но как насчет остального?

Я надеялся, что смогу добавить в SimpleDateFormat строки формата в паре с языковыми стандартами, но я не могу найти способ сделать это. Возможно ли или мне нужно, чтобы мой код проверял языковой стандарт и добавлял соответствующую строку формата?


1
FYI, хлопотно старые классы даты и времени , такие как java.util.Date, java.util.Calendarи java.text.SimpleDateFormatтеперь наследие , вытесняется java.time классов , встроенных в Java 8 и Java 9. См руководство по Oracle .
Basil Bourque

Ответы:


86

Используйте DateFormat.getDateInstance (стиль int, языковой стандарт Locale) вместо создания собственных шаблонов с помощью SimpleDateFormat.


1
Спасибо, все работает нормально. Я выбрал DateFormat.LONG, который лучше всего соответствует моим потребностям. Кстати, норвежский язык и DateFormat.MEDIUM - дерьмо (!)
fiskeben

Вы правы, странный шаблон MEDIUM для норвежского никогда не приходил мне в голову. День недели также отсутствует в формате FULL, в отличие от большинства других языков.
jarnbjo 02

2
FYI, проблемные классы java.util.Dateи SimpleDateFormatтеперь унаследованы, вытеснены классами java.time.
Basil Bourque

88

SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE dd MMM yyyy", Locale.ENGLISH);
String formatted = dateFormat.format(the_date_you_want_here);

29

Используйте стиль + языковой стандарт : DateFormat.getDateInstance (стиль int, языковой стандарт языкового стандарта)

Проверьте http://java.sun.com/j2se/1.5.0/docs/api/java/text/DateFormat.html

Выполните следующий пример, чтобы увидеть различия:

import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;

public class DateFormatDemoSO {
  public static void main(String args[]) {
    int style = DateFormat.MEDIUM;
    //Also try with style = DateFormat.FULL and DateFormat.SHORT
    Date date = new Date();
    DateFormat df;
    df = DateFormat.getDateInstance(style, Locale.UK);
    System.out.println("United Kingdom: " + df.format(date));
    df = DateFormat.getDateInstance(style, Locale.US);
    System.out.println("USA: " + df.format(date));   
    df = DateFormat.getDateInstance(style, Locale.FRANCE);
    System.out.println("France: " + df.format(date));
    df = DateFormat.getDateInstance(style, Locale.ITALY);
    System.out.println("Italy: " + df.format(date));
    df = DateFormat.getDateInstance(style, Locale.JAPAN);
    System.out.println("Japan: " + df.format(date));
  }
}

Вывод:

United Kingdom: 25-Sep-2017
USA: Sep 25, 2017
France: 25 sept. 2017
Italy: 25-set-2017
Japan: 2017/09/25

1
Не забывайте DateFormat.LONGи DateFormat.DEFAULTстили!
JDJ

6
Добавление вывода вашего кода было бы более полным
sam

1
Правильная идея указать стиль и локаль. Но используемые классы сейчас устарели. Неприятные старые классы даты и времени, такие как java.util.Date, java.util.Calendarи java.text.SimpleDateFormat, теперь унаследованы , их вытеснили классы java.time, встроенные в Java 8 и Java 9. См. Учебник Oracle .
Basil Bourque

15

tl; dr

LocalDate.now().format(
    DateTimeFormatter.ofLocalizedDate( FormatStyle.MEDIUM )
                     .withLocale( new Locale( "no" , "NO" ) )
)

Беспокойный классы java.util.Dateи SimpleDateFormatтеперь наследие, вытеснили классы java.time.

LocalDate

LocalDateКласс представляет собой дату только значение без времени суток и без временной зоны.

Часовой пояс имеет решающее значение при определении даты. В любой момент дата меняется в зависимости от зоны земного шара. Например, несколько минут после полуночи в Париже, Франция - это новый день, в то время как в Монреаль-Квебеке все еще «вчера» .

ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( z );

DateTimeFormatter

Используется DateTimeFormatterдля создания строк, представляющих только часть даты или часть времени.

DateTimeFormatterКласс может автоматически локализовать .

Для локализации укажите:

  • FormatStyle чтобы определить, насколько длинной или сокращенной должна быть строка.
  • Locale для определения (а) человеческого языка для перевода названия дня, названия месяца и т. д. и (б) культурных норм, решающих вопросы сокращения, заглавной буквы, пунктуации и т. д.

Пример:

Locale l = Locale.CANADA_FRENCH ; 
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate( FormatStyle.FULL ).withLocale( l );
String output = ld.format( f );

Пойдя в другую сторону, вы можете проанализировать локализованную строку.

LocalDate ld = LocalDate.parse( input , f );

Обратите внимание, что языковой стандарт и часовой пояс являются полностью ортогональными проблемами. Вы можете представить момент из Монреаля на японском языке или момент из Окленда, Новой Зеландии, представленный на языке хинди.

Другой пример: измените 6 junio 2012(испанский) на 2012-06-06(стандартный формат ISO 8601 ). Классы java.time по умолчанию используют форматы ISO 8601 для синтаксического анализа / генерации строк.

String input = "6 junio 2012";
Locale l = new Locale ( "es" , "ES" );
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "d MMMM uuuu" , l );
LocalDate ld = LocalDate.parse ( input , f );
String output = ld.toString();  // 2012-06-06. 

Просматривайте форматы

Вот пример кода для просмотра результатов нескольких форматов в нескольких локали, автоматически локализованных.

An EnumSet- это реализация Set, оптимизированная как для низкого использования памяти, так и для высокой скорости выполнения при сборе Enumобъектов. Итак, EnumSet.allOf( FormatStyle.class )мы получаем коллекцию всех четырех FormatStyleобъектов перечисления для цикла. Для получения дополнительной информации см. Oracle Tutorial по типам перечислений .

LocalDate ld = LocalDate.of( 2018 , Month.JANUARY , 23 );

List < Locale > locales = new ArrayList <>( 3 );
locales.add( Locale.CANADA_FRENCH );
locales.add( new Locale( "no" , "NO" ) );
locales.add( Locale.US );

// Or use all locales (almost 800 of them, for about 120K text results).
// Locale[] locales = Locale.getAvailableLocales(); // All known locales. Almost 800 of them.

for ( Locale locale : locales )
{
    System.out.println( "------|  LOCALE: " + locale + " — " + locale.getDisplayName() + "  |----------------------------------" + System.lineSeparator() );

    for ( FormatStyle style : EnumSet.allOf( FormatStyle.class ) )
    {
        DateTimeFormatter f = DateTimeFormatter.ofLocalizedDate( style ).withLocale( locale );
        String output = ld.format( f );
        System.out.println( output );
    }
    System.out.println( "" );
}
System.out.println( "« fin »" + System.lineSeparator() );

Вывод.

------|  LOCALE: fr_CA — French (Canada)  |----------------------------------

mardi 23 janvier 2018
23 janvier 2018
23 janv. 2018
18-01-23

------|  LOCALE: no_NO — Norwegian (Norway)  |----------------------------------

tirsdag 23. januar 2018
23. januar 2018
23. jan. 2018
23.01.2018

------|  LOCALE: en_US — English (United States)  |----------------------------------

Tuesday, January 23, 2018
January 23, 2018
Jan 23, 2018
1/23/18

« fin »

О java.time

Java.time каркас встроен в Java 8 и более поздних версий. Эти классы вытеснять неприятные старые устаревшие классы даты и времени , такие как java.util.Date, Calendar, и SimpleDateFormat.

Проект Joda-Time , находящийся сейчас в режиме обслуживания , рекомендует перейти на классы java.time .

Чтобы узнать больше, см. Oracle Tutorial . И поищите в Stack Overflow множество примеров и объяснений. Спецификация - JSR 310 .

Вы можете обмениваться объектами java.time напрямую с вашей базой данных. Используйте драйвер JDBC, совместимый с JDBC 4.2 или новее. Нет необходимости в строках, нет необходимости в java.sql.*занятиях.

Где взять классы java.time?

  • Java SE 8 , Java SE 9 и более поздние версии
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • В Java 9 добавлены некоторые незначительные функции и исправления.
  • Java SE 6 и Java SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport .
  • Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является испытательной площадкой для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь , такие как Interval, YearWeek, YearQuarter, и более .


7

Локализация строки даты:

На основе сообщения Redsonic:

private String localizeDate(String inputdate, Locale locale) { 

    Date date = new Date();
    SimpleDateFormat dateFormatCN = new SimpleDateFormat("dd-MMM-yyyy", locale);       
    SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy");


    try {
        date = dateFormat.parse(inputdate);
    } catch (ParseException e) {
        log.warn("Input date was not correct. Can not localize it.");
        return inputdate;
    }
    return dateFormatCN.format(date);
}

String localizedDate = localizeDate("05-Sep-2013", new Locale("zh","CN"));

будет как 05- 九月 -2013


4

Это отобразит дату в соответствии с текущим языковым стандартом пользователя :

Чтобы вернуть дату и время:

import java.text.DateFormat;    
import java.util.Date;

Date date = new Date();
DateFormat df = DateFormat.getDateTimeInstance();
String myDate = df.format(date);

31 декабря 1969 г., 19:00:02.

Чтобы вернуть только дату, используйте:

DateFormat.getDateInstance() 

31 декабря 1969 г.


1

Стиль Java 8 на заданную дату

LocalDate today = LocalDate.of(1982, Month.AUGUST, 31);
System.out.println(today.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.ENGLISH)));
System.out.println(today.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.FRENCH)));
System.out.println(today.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.JAPANESE)));



0

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

public static String getLocaleDatePattern(Locale locale) {
    // Validating if Locale instance is null
    if (locale == null || locale.getLanguage() == null) {
        return "MM/dd/yyyy";
    }
    // Fetching the locale specific date pattern
    String localeDatePattern = ((SimpleDateFormat) DateFormat.getDateInstance(
            DateFormat.SHORT, locale)).toPattern();
    // Validating if locale type is having language code for Chinese and country
    // code for (Hong Kong) with Date Format as - yy'?'M'?'d'?'
    if (locale.toString().equalsIgnoreCase("zh_hk")) {
        // Expected application Date Format for Chinese (Hong Kong) locale type
        return "yyyy'MM'dd";
    }
    // Replacing all d|m|y OR Gy with dd|MM|yyyy as per the locale date pattern
    localeDatePattern = localeDatePattern.replaceAll("d{1,2}", "dd")
            .replaceAll("M{1,2}", "MM")
            .replaceAll("y{1,4}|Gy", "yyyy");
    // Replacing all blank spaces in the locale date pattern
    localeDatePattern = localeDatePattern.replace(" ", "");
    // Validating the date pattern length to remove any extract characters
    if (localeDatePattern.length() > 10) {
        // Keeping the standard length as expected by the application
        localeDatePattern = localeDatePattern.substring(0, 10);
    }
    return localeDatePattern;
}

-2

Java8

 import java.time.format.DateTimeFormatter;         
 myDate.format(DateTimeFormatter.ofPattern("dd-MMM-YYYY",new Locale("ar")))

Использование ofPatternаргумента языкового стандарта даст вам название месяца на желаемом языке, но не в разных форматах, как указано в вопросе. Использование прописных букв YYYYдаст вам неправильные и очень неожиданные результаты в угловых случаях. Использование Java 8 - хорошая идея.
Ole VV
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.