SimpleDateFormat và chuỗi định dạng dựa trên ngôn ngữ


83

Tôi đang cố định dạng một ngày trong Java theo nhiều cách khác nhau dựa trên ngôn ngữ đã cho. Ví dụ: tôi muốn người dùng tiếng Anh xem "Ngày 1 tháng 11 năm 2009" (được định dạng bởi "MMM d, yyyy") và người dùng Na Uy xem "1. nov. 2009" ("d. MMM. Yyyy").

Phần tháng hoạt động OK nếu tôi thêm miền địa phương vào hàm tạo SimpleDateFormat, nhưng phần còn lại thì sao?

Tôi đã hy vọng mình có thể thêm các chuỗi định dạng được ghép nối với ngôn ngữ vào SimpleDateFormat, nhưng tôi không thể tìm thấy bất kỳ cách nào để thực hiện việc này. Có được không hay tôi cần để mã của mình kiểm tra ngôn ngữ và thêm chuỗi định dạng tương ứng?


1
FYI, các lớp date-time cũ rắc rối như java.util.Date, java.util.Calendarjava.text.SimpleDateFormatbây giờ là kế thừa , được thay thế bởi các lớp java.time được tích hợp trong Java 8 & Java 9. Xem Hướng dẫn của Oracle .
Basil Bourque

Câu trả lời:


87

Sử dụng DateFormat.getDateInstance (kiểu int, ngôn ngữ Locale) thay vì tạo các mẫu của riêng bạn với SimpleDateFormat.


1
Cảm ơn, điều này hoạt động tốt. Tôi đã chọn DateFormat.LONG phù hợp với nhu cầu của tôi nhất. BTW, ngôn ngữ Na Uy và DateFormat.MEDIUM thật là tào lao (!)
fiskeben

Bạn nói đúng, mô hình VỪA lạ lùng đối với tiếng Na Uy chưa bao giờ xảy ra với tôi. Ngày trong tuần cũng bị thiếu ở định dạng FULL, trái ngược với hầu hết các ngôn ngữ khác.
jarnbjo

2
FYI, các lớp rắc rối java.util.DateSimpleDateFormatbây giờ là kế thừa, được thay thế bằng các lớp java.time.
Basil Bourque

89

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

29

Sử dụng style + locale : DateFormat.getDateInstance (int style, Locale locale)

Kiểm tra http://java.sun.com/j2se/1.5.0/docs/api/java/text/DateFormat.html

Chạy ví dụ sau để xem sự khác biệt:

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

Đầu ra:

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

1
Đừng quên DateFormat.LONGDateFormat.DEFAULTphong cách!
JDJ

6
Thêm đầu ra mã của bạn sẽ hoàn thiện hơn
sam

1
Ý tưởng đúng để chỉ định phong cách và ngôn ngữ. Nhưng các lớp được sử dụng hiện đã lỗi thời. Các lớp date-time cũ rắc rối như java.util.Date, java.util.Calendarjava.text.SimpleDateFormatbây giờ là kế thừa , được thay thế bởi các lớp java.time được tích hợp trong Java 8 & Java 9. Xem Hướng dẫn của Oracle .
Basil Bourque

15

tl; dr

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

Các lớp rắc rối của java.util.DateSimpleDateFormatbây giờ là kế thừa, được thay thế bởi các lớp java.time.

LocalDate

Các LocalDatelớp đại diện cho một giá trị ngày tháng chỉ mà không cần thời gian của ngày và không có múi giờ.

Múi giờ rất quan trọng trong việc xác định ngày. Đối với bất kỳ thời điểm nhất định nào, ngày thay đổi trên toàn cầu theo khu vực. Ví dụ: một vài phút sau nửa đêm ở Paris Pháp là một ngày mới trong khi vẫn là “ngày hôm qua” ở Montréal Québec .

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

DateTimeFormatter

Sử dụng DateTimeFormatterđể tạo chuỗi chỉ đại diện cho phần ngày hoặc phần thời gian.

Các DateTimeFormatterlớp có thể tự động khoanh vùng .

Để bản địa hóa, hãy chỉ định:

  • FormatStyle để xác định độ dài hoặc viết tắt của chuỗi.
  • Locale để xác định (a) ngôn ngữ của con người để dịch tên ngày, tên tháng, v.v., và (b) các chuẩn mực văn hóa quyết định các vấn đề về viết tắt, viết hoa, dấu câu, v.v.

Thí dụ:

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

Đi theo hướng khác, bạn có thể phân tích cú pháp một chuỗi được bản địa hóa.

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

Lưu ý rằng ngôn ngữ và múi giờ là những vấn đề hoàn toàn trực giao. Bạn có thể có một khoảnh khắc Montréal được trình bày bằng tiếng Nhật hoặc một khoảnh khắc ở Auckland New Zealand được trình bày bằng tiếng Hindi.

Một ví dụ khác: Thay đổi 6 junio 2012(tiếng Tây Ban Nha) thành 2012-06-06( định dạng ISO 8601 tiêu chuẩn ). Các lớp java.time sử dụng các định dạng ISO 8601 theo mặc định để phân tích cú pháp / tạo chuỗi.

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. 

Peruse các định dạng

Dưới đây là một số mã ví dụ để duyệt qua các kết quả của nhiều định dạng ở nhiều ngôn ngữ, được bản địa hóa tự động.

An EnumSetlà một triển khai Set, được tối ưu hóa cao để sử dụng bộ nhớ thấp và tốc độ thực thi nhanh khi thu thập Enumcác đối tượng. Vì vậy, EnumSet.allOf( FormatStyle.class )cung cấp cho chúng ta một tập hợp tất cả bốn FormatStyleđối tượng enum để lặp. Để biết thêm thông tin, hãy xem Hướng dẫn của Oracle về các loại enum .

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

Đầu ra.

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

Giới thiệu về java.time

Khung java.time được tích hợp sẵn trong Java 8 trở lên. Những lớp học thay thế cái cũ phiền hà di sản lớp học ngày thời gian như java.util.Date, Calendar, & SimpleDateFormat.

Các Joda thời gian dự án, bây giờ trong chế độ bảo trì , khuyên chuyển đổi sang các java.time lớp.

Để tìm hiểu thêm, hãy xem Hướng dẫn Oracle . Và tìm kiếm Stack Overflow cho nhiều ví dụ và giải thích. Đặc điểm kỹ thuật là JSR 310 .

Bạn có thể trao đổi các đối tượng java.time trực tiếp với cơ sở dữ liệu của mình. Sử dụng trình điều khiển JDBC tương thích với JDBC 4.2 trở lên. Không cần chuỗi, không cần java.sql.*lớp.

Lấy các lớp java.time ở đâu?

  • Java SE 8 , Java SE 9 và mới hơn
    • Được xây dựng trong.
    • Một phần của API Java tiêu chuẩn với một triển khai đóng gói.
    • Java 9 bổ sung một số tính năng nhỏ và các bản sửa lỗi.
  • Java SE 6 Java SE 7
    • Phần lớn chức năng của java.time được chuyển ngược sang Java 6 & 7 trong ThreeTen-Backport .
  • Android
    • Các phiên bản triển khai gói Android mới hơn của các lớp java.time.
    • Đối với Android trước đó, ThreeTenABP dự án thích nghi ThreeTen-backport (nêu trên). Xem Cách sử dụng ThreeTenABP… .

Các ThreeTen-Extra dự án mở rộng java.time với các lớp bổ sung. Dự án này là cơ sở chứng minh cho những bổ sung có thể có trong tương lai cho java.time. Bạn có thể tìm thấy một số các lớp học hữu ích ở đây chẳng hạn như Interval, YearWeek, YearQuarter, và nhiều hơn nữa .


8

Bản địa hóa chuỗi ngày:

Dựa trên bài đăng của 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"));

sẽ giống như 05- 九月 -2013


4

Điều này sẽ hiển thị ngày theo ngôn ngữ hiện tại của người dùng :

Để trả lại ngày và giờ:

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

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

Ngày 31 tháng 12 năm 1969 7:00:02 CH

Để chỉ ngày trở lại, hãy sử dụng:

DateFormat.getDateInstance() 

Ngày 31 tháng 12 năm 1969


1

Kiểu Java 8 cho một ngày nhất định

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

Hy vọng điều này sẽ giúp ai đó. Vui lòng tìm trong đoạn mã dưới đây chấp nhận phiên bản Ngôn ngữ và trả về định dạng / mẫu ngày cụ thể cho ngôn ngữ.

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")))

Sử dụng ofPatternvới đối số ngôn ngữ sẽ cung cấp cho bạn tên tháng ở ngôn ngữ mong muốn, nhưng không phải các định dạng khác nhau như yêu cầu trong câu hỏi. Sử dụng chữ hoa YYYYsẽ cho bạn kết quả không chính xác và rất đáng ngạc nhiên trong các trường hợp ở góc. Sử dụng Java 8 là một ý kiến ​​hay.
Ole VV
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.