2011-12-31 6 views
55

Tôi tự hỏi tại sao 'Y' lợi nhuận năm 2012 trong khi 'y' trả về 2011 tại SimpleDateFormat:Y trả về 2012 trong khi y trở về năm 2011 tại SimpleDateFormat

System.out.println(new SimpleDateFormat("Y").format(new Date())); // prints 2012 
System.out.println(new SimpleDateFormat("y").format(new Date())); // prints 2011 

Bất kỳ một thể giải thích tại sao?

+21

Cũng giống như một lưu ý với độc giả trong tương lai: Hành vi này sẽ chỉ xảy ra trong tuần cuối cùng của năm hoặc tuần đầu tiên của năm. – ryvantage

Trả lời

59

week year và năm. Từ javadoc

Một tuần trong tuần được đồng bộ hóa với chu kỳ WEEK_OF_YEAR. Tất cả các tuần giữa tuần đầu tiên và cuối cùng (bao gồm) có cùng giá trị năm trong tuần. Do đó, ngày đầu tiên và cuối cùng của một tuần có thể có các giá trị năm dương lịch khác nhau.

Ví dụ: ngày 1 tháng 1 năm 1998 là thứ Năm. Nếu getFirstDayOfWeek() là MONDAY và getMinimalDaysInFirstWeek() là 4 (ISO 8601 tiêu chuẩn cài đặt tương thích), sau đó tuần 1 năm 1998 bắt đầu vào ngày 29 tháng 12 năm 1997, và kết thúc vào ngày 4 tháng 1 năm 1998. Năm đó là năm 1998 cho cuối cùng là ba ngày ngày lịch năm 1997. Nếu, tuy nhiên, getFirstDayOfWeek() là SUNDAY, sau đó tuần 1 năm 1998 bắt đầu vào ngày 4 tháng 1 năm 1998 và kết thúc vào ngày ngày 10 tháng 1 năm 1998; ba ngày đầu tiên năm 1998 sau đó là một phần của tuần 53 năm 1997 và năm tuần họ là 1997.

+0

'$ ngày Wed ngày 30 tháng 12 00:42:51 UTC 2015' ' $ date +% G 2015' '$ date +% Y 2015' Một số phần mềm được nhầm lẫn:' strftime' tính ngày nay (12/29/2015) như có tuần 53, và tuần năm 2015. – aks

5

Format Y để có được tuần năm nếu hỗ trợ lịch tuần năm. (getCalendar().isWeekDateSupported())

1

Tôi đã học được cách khó khăn khi thư viện thẻ JSTL format:date với short làm định dạng được yêu cầu sử dụng YYYY bên dưới trang bìa. Mà thực sự có thể cuộn ngày in trước một năm.

9

Đây là bản cập nhật Java 8 với một số mã, vì GregorianCalendar có thể sẽ không còn được dùng hoặc bị loại bỏ khỏi các phiên bản JDK trong tương lai.

Mã mới được xử lý trong lớp WeekFields và dành riêng cho trường hợp thấp hơn y/upper case Y bằng trình truy cập trường weekBasedYear().

Trả về trường để truy cập vào năm của một tuần dựa trên năm dựa trên WeekFields này. Điều này thể hiện khái niệm về năm bắt đầu các tuần vào một ngày cố định trong tuần, chẳng hạn như Thứ Hai và mỗi tuần thuộc về chính xác một năm. Trường này thường được sử dụng với dayOfWeek() và weekOfWeekBasedYear().

Tuần một (1) là tuần bắt đầu từ getFirstDayOfWeek() trong đó có ít nhất getMinimalDaysInFirstWeek() ngày trong năm. Vì vậy, tuần một có thể bắt đầu trước khi bắt đầu năm. Nếu tuần đầu tiên bắt đầu sau đầu năm thì khoảng thời gian trước đó là trong tuần trước của năm trước.

Trường này có thể được sử dụng với bất kỳ hệ thống lịch nào.

Trong giai đoạn phân tích cú pháp phân tích, một ngày có thể được tạo từ tuần, năm, tuần và ngày trong tuần.

Ở chế độ nghiêm ngặt, tất cả ba trường được xác thực dựa trên phạm vi giá trị hợp lệ của chúng. Trường hàng tuần được xác thực để đảm bảo rằng kết quả là tuần theo năm là yêu cầu theo tuần.

Trong chế độ thông minh, tất cả ba trường được xác thực dựa trên phạm vi giá trị hợp lệ của chúng. Trường tuần dựa trên tuần được xác thực từ 1 đến 53, có nghĩa là ngày kết quả có thể nằm trong tuần sau dựa trên năm đó theo quy định.

Trong chế độ khoan dung, năm và ngày trong tuần được xác thực dựa trên dải giá trị hợp lệ . Ngày kết quả được tính tương đương với cách tiếp cận ba giai đoạn sau đây. Trước tiên, hãy tạo ngày vào ngày đầu tiên của tuần đầu tiên trong tuần dựa trên tuần được yêu cầu. Sau đó, lấy năm dựa trên tuần trong tuần, trừ một và thêm số tiền trong tuần tới ngày. Cuối cùng, điều chỉnh theo đúng ngày trong tuần trong tuần địa phương hóa.

Phiên bản WeekFields này phụ thuộc vào ngôn ngữ và có thể có các cài đặt khác tùy thuộc vào quốc gia này và các quốc gia châu Âu như Pháp có thể có một ngày khác vào đầu tuần.

Ví dụ DateFormatterBuilder Java 8, nhanh chóng phân tích cú pháp với miền địa phương, và sử dụng locale này cho Y biểu tượng:

public final class DateTimeFormatterBuilder { 
    ... 

    private void parsePattern(String pattern) { 
     ... 
       } else if (cur == 'Y') { 
        // Fields defined by Locale 
        appendInternal(new WeekBasedFieldPrinterParser(cur, count)); 
       } else { 
     ... 


    static final class WeekBasedFieldPrinterParser implements DateTimePrinterParser { 
     ... 

     /** 
     * Gets the printerParser to use based on the field and the locale. 
     * 
     * @param locale the locale to use, not null 
     * @return the formatter, not null 
     * @throws IllegalArgumentException if the formatter cannot be found 
     */ 
     private DateTimePrinterParser printerParser(Locale locale) { 
      WeekFields weekDef = WeekFields.of(locale); 
      TemporalField field = null; 
      switch (chr) { 
       case 'Y': 
        field = weekDef.weekBasedYear(); 
        if (count == 2) { 
         return new ReducedPrinterParser(field, 2, 2, 0, ReducedPrinterParser.BASE_DATE, 0); 
        } else { 
         return new NumberPrinterParser(field, count, 19, 
                 (count < 4) ? SignStyle.NORMAL : SignStyle.EXCEEDS_PAD, -1); 
        } 
       case 'e': 
       case 'c': 
        field = weekDef.dayOfWeek(); 
        break; 
       case 'w': 
        field = weekDef.weekOfWeekBasedYear(); 
        break; 
       case 'W': 
        field = weekDef.weekOfMonth(); 
        break; 
       default: 
        throw new IllegalStateException("unreachable"); 
      } 
      return new NumberPrinterParser(field, (count == 2 ? 2 : 1), 2, SignStyle.NOT_NEGATIVE); 
     } 

     ... 
    } 

    ... 
} 

Dưới đây là một số ví dụ

System.out.format("Conundrum       : %s%n", 
        ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")) 
           .format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'"))); 
System.out.format("Solution       : %s%n", 
        ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")) 
           .format(DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmms'S'"))); 


System.out.format("JVM Locale first day of week  : %s%n", 
        WeekFields.of(Locale.getDefault()).getFirstDayOfWeek()); 
System.out.format("US first day of week    : %s%n", 
        WeekFields.of(Locale.US).getFirstDayOfWeek()); 
System.out.format("France first day of week   : %s%n", 
        WeekFields.of(Locale.FRANCE).getFirstDayOfWeek()); 
System.out.format("JVM Locale min days in 1st week : %s%n", 
        WeekFields.of(Locale.getDefault()).getMinimalDaysInFirstWeek()); 
System.out.format("US min days in 1st week   : %s%n", 
        WeekFields.of(Locale.US).getMinimalDaysInFirstWeek()); 
System.out.format("JVM Locale min days in 1st week : %s%n", 
        WeekFields.of(Locale.FRANCE).getMinimalDaysInFirstWeek()); 

System.out.format("JVM Locale week based year (big Y): %s%n", 
        ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.FRANCE).weekBasedYear())); 
System.out.format("France week based year (big Y) : %s%n", 
        ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.FRANCE).weekBasedYear())); 
System.out.format("US week based year (big Y)  : %s%n", 
        ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")).get(WeekFields.of(Locale.US).weekBasedYear())); 

Và trong về miền địa phương và chữ hoa trên Y, bạn có thể chơi với tùy chọn dòng lệnh -Duser.language= (fr, en, es, vv), hoặc buộc các miền địa phương vào thời điểm gọi:

System.out.format("English localized     : %s%n", 
        ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")) 
           .format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'", Locale.ENGLISH))); 
System.out.format("French localized     : %s%n", 
        ZonedDateTime.of(2015, 12, 30, 0, 0, 0, 0, ZoneId.of("UTC")) 
           .format(DateTimeFormatter.ofPattern("YYYYMMdd'T'HHmms'S'", Locale.FRENCH)));