SimpleDateFormat i ciąg formatu oparty na ustawieniach regionalnych

83

Próbuję sformatować datę w Javie na różne sposoby w oparciu o podane ustawienia regionalne. Na przykład chcę, aby użytkownicy angielscy widzieli „1 listopada 2009” (sformatowany jako „d MMM, rrrr”), a użytkownicy norwescy - „1. listopad 2009” („d. MMM. Rrrr”).

Część miesiąca działa dobrze, jeśli dodam ustawienia regionalne do konstruktora SimpleDateFormat, ale co z resztą?

Miałem nadzieję, że uda mi się dodać ciągi formatujące połączone z lokalizacjami do SimpleDateFormat, ale nie mogę znaleźć żadnego sposobu, aby to zrobić. Czy jest to możliwe, czy też muszę pozwolić mojemu kodowi sprawdzić ustawienia regionalne i dodać odpowiedni ciąg formatu?

fiskeben
źródło
1
FYI, kłopotliwe stare klasy daty i godziny, takie jak java.util.Date, java.util.Calendari java.text.SimpleDateFormatsą teraz starsze , zastąpione przez klasy java.time wbudowane w Java 8 i Java 9. Zobacz samouczek Oracle .
Basil Bourque

Odpowiedzi:

86

Użyj DateFormat.getDateInstance (styl int, locale locale) zamiast tworzyć własne wzorce z SimpleDateFormat.

jarnbjo
źródło
1
Dzięki, to działa OK. Wybrałem DateFormat.LONG, który najlepiej odpowiada moim potrzebom. BTW, norweskie locale i DateFormat.MEDIUM to bzdury (!)
fiskeben
Masz rację, dziwny wzór MEDIUM dla norweskiego nigdy mi się nie pojawił. W przeciwieństwie do większości innych języków brakuje również dnia tygodnia w PEŁNYM formacie.
jarnbjo
2
FYI, kłopotliwe klasy klas java.util.Datei SimpleDateFormatsą teraz starsze, wyparte przez klasy java.time.
Basil Bourque
88

SimpleDateFormat dateFormat = new SimpleDateFormat("EEEE dd MMM yyyy", Locale.ENGLISH);
String formatted = dateFormat.format(the_date_you_want_here);
redochka
źródło
29

Użyj style + locale : DateFormat.getDateInstance (styl int, locale locale)

Sprawdź http://java.sun.com/j2se/1.5.0/docs/api/java/text/DateFormat.html

Uruchom następujący przykład, aby zobaczyć różnice:

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));
  }
}

Wynik:

United Kingdom: 25-Sep-2017
USA: Sep 25, 2017
France: 25 sept. 2017
Italy: 25-set-2017
Japan: 2017/09/25
JuanZe
źródło
1
Nie zapomnij o stylach DateFormat.LONGi DateFormat.DEFAULT!
JDJ
6
Dodanie wyjścia kodu byłoby bardziej kompletne
sam
1
Właściwy pomysł na określenie stylu i lokalizacji. Ale używane klasy są teraz przestarzałe. Kłopotliwe stare klasy daty i godziny, takie jak java.util.Date, java.util.Calendari java.text.SimpleDateFormatsą teraz starsze , zastąpione przez klasy java.time wbudowane w Java 8 i Java 9. Zobacz samouczek firmy Oracle .
Basil Bourque
15

tl; dr

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

Kłopotliwego klasy java.util.Datei SimpleDateFormatsą teraz Legacy, wyparta przez klasy java.time.

LocalDate

LocalDateKlasa reprezentuje wartość data-tylko bez time-of-day i bez strefy czasowej.

Strefa czasowa ma kluczowe znaczenie przy ustalaniu daty. W dowolnym momencie data różni się na całym świecie według strefy. Na przykład kilka minut po północy Paryżu Francja jest nowym dniem, podczas gdy w Montrealu Quebec wciąż trwa „wczoraj” .

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

DateTimeFormatter

Służy DateTimeFormatterdo generowania ciągów reprezentujących tylko część daty lub część czasu.

DateTimeFormatterKlasa może automatycznie zlokalizować .

Aby zlokalizować, określ:

  • FormatStyle aby określić, jak długi lub jak skrócony powinien być ciąg.
  • Locale określenie (a) języka ludzkiego do przetłumaczenia nazwy dnia, nazwy miesiąca itp. oraz (b) norm kulturowych decydujących o kwestiach skrótów, wielkich liter, interpunkcji i tym podobnych.

Przykład:

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

Idąc w drugą stronę, możesz przeanalizować zlokalizowany ciąg.

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

Zwróć uwagę, że ustawienia regionalne i strefa czasowa są całkowicie ortogonalne. Możesz mieć moment z Montrealu przedstawiony w języku japońskim lub moment z Auckland w Nowej Zelandii przedstawiony w języku hindi.

Inny przykład: Zmień 6 junio 2012(hiszpański) na 2012-06-06(standardowy format ISO 8601 ). Klasy java.time używają domyślnie formatów ISO 8601 do analizowania / generowania ciągów.

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. 

Przeglądaj formaty

Oto przykładowy kod do przeglądania wyników w wielu formatach w wielu lokalizacjach, automatycznie zlokalizowany.

An EnumSetto implementacja Setwysoce zoptymalizowana zarówno pod kątem niskiego zużycia pamięci, jak i dużej szybkości wykonywania podczas zbierania Enumobiektów. Więc EnumSet.allOf( FormatStyle.class )daje nam kolekcję wszystkich czterech FormatStyleobiektów enum do zapętlenia. Aby uzyskać więcej informacji, zobacz samouczek Oracle dotyczący typów wyliczeń .

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() );

Wynik.

------|  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 »

Informacje o java.time

Struktura java.time jest wbudowana w Javę 8 i nowsze. Klasy te kłopotliwe zastąpić stary starszych klas Date-Time, takich jak java.util.Date, Calendar, i SimpleDateFormat.

Projekt Joda-Time , obecnie w trybie konserwacji , zaleca migrację do klas java.time .

Aby dowiedzieć się więcej, zobacz samouczek Oracle . I przeszukaj Stack Overflow, aby znaleźć wiele przykładów i wyjaśnień. Specyfikacja to JSR 310 .

Możesz wymieniać obiekty java.time bezpośrednio ze swoją bazą danych. Użyj sterownika JDBC zgodnego z JDBC 4.2 lub nowszym. Nie ma potrzeby stosowania ciągów ani java.sql.*klas.

Skąd wziąć klasy java.time?

  • Java SE 8 , Java SE 9 i nowsze
    • Wbudowany.
    • Część standardowego interfejsu API języka Java z dołączoną implementacją.
    • Java 9 dodaje kilka drobnych funkcji i poprawek.
  • Java SE 6 i Java SE 7
    • Wiele funkcji java.time jest przenoszonych z powrotem do Javy 6 i 7 w ThreeTen-Backport .
  • Android
    • Późniejsze wersje pakietów systemu Android implementacji klas java.time.
    • Na wcześniejszym Androidzie ThreeTenABP projekt dostosowuje ThreeTen-backportu (wymienione powyżej). Zobacz Jak używać ThreeTenABP… .

Projekt ThreeTen-Extra rozszerza java.time o dodatkowe klasy. Ten projekt jest poligonem doświadczalnym dla ewentualnych przyszłych dodatków do java.time. Można znaleźć kilka przydatnych klas tutaj takie jak Interval, YearWeek, YearQuarter, i więcej .

Basil Bourque
źródło
7

Lokalizacja ciągu daty:

Na podstawie postu 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"));

będzie jak 05- 九月 -2013

Yaro
źródło
4

Spowoduje to wyświetlenie daty zgodnie z aktualnymi ustawieniami regionalnymi użytkownika :

Aby zwrócić datę i godzinę:

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

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

31 grudnia 1969 19:00:02

Aby zwrócić tylko datę, użyj:

DateFormat.getDateInstance() 

31 grudnia 1969

miłość na żywo
źródło
1

Styl Java 8 dla danego dnia

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)));
Mircea Stanciu
źródło
Wydaje mi się, że omawiałem tego rodzaju rozwiązanie rok temu.
Basil Bourque
0
String text = new SimpleDateFormat("E, MMM d, yyyy").format(date);
Hadid Graphics
źródło
0

Mam nadzieję, że to komuś pomoże. Znajdź w poniższym kodzie, który akceptuje instancję Locale i zwraca format / wzorzec daty specyficzny dla lokalizacji.

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;
}
Dinesh Lomte
źródło
-2

Java8

 import java.time.format.DateTimeFormatter;         
 myDate.format(DateTimeFormatter.ofPattern("dd-MMM-YYYY",new Locale("ar")))
Abdennour TOUMI
źródło
Użycie ofPatternz argumentem locale da ci nazwę miesiąca w żądanym języku, ale nie w innych formatach, jak żądano w pytaniu. Używanie wielkich liter YYYYda niepoprawne i bardzo zaskakujące wyniki w przypadkach narożnych. Używanie Java 8 to dobry pomysł.
Ole VV