Y trả về 2012 trong khi y trả về 2011 trong SimpleDateFormat


85

Tôi tự hỏi tại sao 'Y' trả về năm 2012 trong khi 'y' trả về năm 2011 trong 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ỳ ai có thể giải thích tại sao?


36
Cũng như một lưu ý cho các độ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

Câu trả lời:


91

tuần năm và năm. Từ javadoc

Một năm đồng bộ với chu kỳ WEEK_OF_YEAR. Tất cả các tuần giữa tuần đầu tiên và tuần trước (bao gồm) có cùng giá trị tuần trong năm. Do đó, ngày đầu tiên và ngày cuối cùng của một năm 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à THỨ HAI và getMinimalDaysInFirstWeek () là 4 (cài đặt tương thích với tiêu chuẩn ISO 8601), thì tuần 1 của 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. Tuần của năm 1998 là ba ngày cuối cùng của năm dương lịch 1997. Tuy nhiên, nếu getFirstDayOfWeek () là CHỦ NHẬT, thì tuần 1 của 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 10 tháng 1 năm 1998; ba ngày đầu tiên của năm 1998 sau đó là một phần của tuần 53 của năm 1997 và năm trong tuần của họ là năm 1997.


$ date Wed Dec 30 00:42:51 UTC 2015 $ date +%G 2015 $ date +%Y 2015 Một số phần mềm bị nhầm lẫn: strftimetính toán ngày hôm nay (29/12/2015) là tuần thứ 53 và tuần trong năm là năm 2015.
aks

11

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

Mã mới được xử lý trong WeekFieldslớp và cụ thể cho chữ thường y/ chữ hoa Yvới bộ truy cập weekBasedYear()trường.

Trả về một trường để truy cập năm của năm dựa trên tuần dựa trên Trường trong tuần này. Điều này thể hiện khái niệm về năm mà các tuần bắt đầu 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 đúng 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 trên getFirstDayOfWeek (), nơi có ít nhất getMinimalDaysInFirstWeek () ngày trong năm. Do đó, tuần đầu tiên có thể bắt đầu trước khi bắt đầu năm. Nếu tuần đầu tiên bắt đầu sau ngày bắt đầu của năm thì khoảng thời gian trước đó là vào tuần cuối cùng 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 cú pháp, một ngày có thể được tạo từ tuần dựa trên năm, tuần trong năm và ngày trong tuần.

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

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

Trong chế độ khoan dung, năm và ngày trong tuần được xác thực theo phạm vi 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. Trước tiên, hãy tạo một ngày vào ngày đầu tiên của tuần đầu tiên trong năm dựa trên tuần được yêu cầu. Sau đó, lấy tuần của tuần dựa trên năm, trừ đi một và cộng số tuần vào ngày. Cuối cùng, điều chỉnh cho đúng ngày trong tuần trong tuần được bản địa hóa.

Việc thiết lập cái này WeekFields phụ thuộc vào ngôn ngữ và có thể có các cài đặt khác nhau tùy thuộc vào nó, các quốc gia Hoa Kỳ và Châu Âu như Pháp có thể có một ngày khác kể từ đầu tuần.

Ví dụ DateFormatterBuildervề Java 8, khởi tạo trình phân tích cú pháp với ngôn ngữ và sử dụng ngôn ngữ này cho Yký hiệu:

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

        ...
    }

    ...
}

Đâ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à về vấn đề của địa phương và các trường hợp trên Y, bạn có thể chơi với các 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)));

5

Định dạng Yđể nhận năm tuần nếu lịch hỗ trợ năm. ( getCalendar().isWeekDateSupported())


1

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


0

Tôi chuyển đổi ngày tháng qua lại - bạn sẽ mong đợi cùng một năm khi bạn làm điều này.

Chú ý cách nó tiến một!

Tệ thật: YYYY! YYYY

Bạn có thể chạy nó ở đây .

import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import static java.lang.System.out;
class Playground {
    public static Date convertYYYYMMDDStr(String s) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date result = null;
        try {
            result = sdf.parse(s);
        } catch(ParseException e) {
            e.printStackTrace();
        }
        return result;
    }
    public static String formatDateToStrWithSDF(Date d, SimpleDateFormat s) {
        return s.format(d);
    }
    public static void main(String[ ] args) {
        // DON'T DO. Use yyyy instead of YYYY
        SimpleDateFormat sdfdmy = new SimpleDateFormat("dd-MM-YYYY"); 
        String jan1st2020sb = "2020-01-01";
        Date jan1st2020d = convertYYYYMMDDStr(jan1st2020sb);
        String jan1st2020sa = formatDateToStrWithSDF(jan1st2020d, sdfdmy);
        out.println(jan1st2020sb);
        out.println(jan1st2020d);
        out.println(jan1st2020sa);
        String dec31st2020sb = "2020-12-31";
        Date dec31st2020d = convertYYYYMMDDStr(dec31st2020sb);
        String dec31st2020sa = formatDateToStrWithSDF(dec31st2020d, sdfdmy);
        out.println(dec31st2020sb);
        out.println(dec31st2020d);
        out.println(dec31st2020sa);
    }
}

Điều này là tốt: yyyy

yyyy

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.