SimpleDateFormat та рядок формату на основі мови


83

Я намагаюся відформатувати дату в Java різними способами, виходячи з даної локалі. Наприклад, я хочу, щоб англійські користувачі бачили "1 листопада 2009 р." (Відформатовано "MMM d, yyyy"), а норвезькі - "1. nov. 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

Відповіді:


87

Використовуйте DateFormat.getDateInstance (стиль int, локаль) замість того, щоб створювати власні шаблони за допомогою SimpleDateFormat.


1
Дякую, це працює добре. Я вибрав DateFormat.LONG, який найкраще відповідає моїм потребам. BTW, норвезька мова та DateFormat.MEDIUM - глупство (!)
fiskeben

Ви маєте рацію, дивний середній для норвежця шаблон мені ніколи не траплявся. Будній день також відсутній у повному форматі, на відміну від більшості інших мов.
jarnbjo 02

2
FYI, клопітні класи класів java.util.Dateі SimpleDateFormatтепер є застарілими, витіснені класами java.time.
Василь Бурк

89

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
Додавання виводу вашого коду було б більш повним
Сем

1
Правильна ідея для визначення стилю та мови. Але використовувані класи зараз застаріли. Проблемні старі класи дати та часу, такі як java.util.Date, java.util.Calendarі java.text.SimpleDateFormatтепер є застарілими , витіснені класами java.time, вбудованими в Java 8 і Java 9. Див. Підручник Oracle .
Basil Bourque

15

tl; д-р

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. 

Перегляньте формати

Ось приклад коду для перегляду результатів декількох форматів у декількох локалях, які автоматично локалізуються.

Це EnumSetреалізація Set, високо оптимізована як для низького використання пам'яті, так і для швидкої швидкості виконання при збиранні Enumоб'єктів. Отже, EnumSet.allOf( FormatStyle.class )ми отримуємо колекцію всіх чотирьох перерахованих FormatStyleоб’єктів для циклу. Для отримання додаткової інформації див. Підручник Oracle щодо типів перечислення .

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 . І шукайте в 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, і більш .


8

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

На основі допису Редсоніка:

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 - хороша ідея.
Оле В. В.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.