Y는 2012를 반환하고 y는 SimpleDateFormat에서 2011을 반환합니다.


85

왜 'Y'가 2012를 반환하고 'y'가 2011을 반환하는지 궁금합니다 SimpleDateFormat.

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

아무도 이유를 설명 할 수 있습니까?


40
미래 독자를위한 참고 사항 :이 동작은 해당 연도의 마지막 주 또는 해당 연도의 첫 주에만 발생합니다.
ryvantage 2014 년

답변:


94

주 연도 . javadoc에서

1 주일은 WEEK_OF_YEAR주기와 동기화됩니다. 첫 주와 마지막 주 (포함) 사이의 모든 주에는 동일한 주 연도 값이 있습니다. 따라서 한주의 첫 번째 날과 마지막 날은 다른 역년 값을 가질 수 있습니다.

예를 들어 1998 년 1 월 1 일은 목요일입니다. getFirstDayOfWeek ()가 MONDAY이고 getMinimalDaysInFirstWeek ()가 4 (ISO 8601 표준 호환 설정)이면 1998 년의 1주는 1997 년 12 월 29 일에 시작하여 1998 년 1 월 4 일에 끝납니다. 주 연도는 지난 3 일 동안 1998 년입니다. 그러나 getFirstDayOfWeek ()가 SUNDAY이면 1998 년 1 주차는 1998 년 1 월 4 일에 시작하여 1998 년 1 월 10 일에 끝납니다. 1998 년의 처음 3 일은 1997 년 53 주차의 일부이며 주연도는 1997 년입니다.


$ date Wed Dec 30 00:42:51 UTC 2015 $ date +%G 2015 $ date +%Y 2015 일부 소프트웨어는 혼란 스럽습니다. strftime오늘 (2015 년
aks

11

GregorianCalendar는 향후 JDK 버전에서 더 이상 사용되지 않거나 제거 될 것이므로 일부 코드가 포함 된 Java 8 업데이트가 있습니다.

새 코드는 WeekFields클래스 에서 처리되며 특히 필드 접근자가 있는 소문자 y/ 대문자에 대해 처리됩니다 .YweekBasedYear()

이 WeekFields를 기반으로 한 주 기반 연도의 연도에 액세스하는 필드를 반환합니다. 이것은 주가 월요일과 같이 고정 된 요일에 시작되고 각 주가 정확히 1 년에 속하는 연도의 개념을 나타냅니다. 이 필드는 일반적으로 dayOfWeek () 및 weekOfWeekBasedYear ()와 함께 사용됩니다.

1 주차는 1 년에 최소한 getMinimalDaysInFirstWeek () 일이있는 getFirstDayOfWeek ()에 시작하는 주입니다. 따라서 1 주차는 연도가 시작되기 전에 시작될 수 있습니다. 첫 번째 주가 연도가 시작된 후 시작되는 경우 이전 기간은 전년도의 마지막 주입니다.

이 필드는 모든 달력 시스템에서 사용할 수 있습니다.

구문 분석의 해결 단계에서 주 기반 연도, 주 및 요일로 날짜를 만들 수 있습니다.

엄격 모드에서는 세 필드 모두 유효한 값 범위에 대해 유효성이 검사됩니다. 주 단위 필드는 결과 주 단위 연도가 요청 된 주 단위 연도인지 확인하기 위해 유효성이 검사됩니다.

스마트 모드에서는 세 필드 모두 유효한 값 범위에 대해 유효성이 검사됩니다. 주 기준 연도 필드는 1부터 53까지의 유효성을 검사합니다. 즉, 결과 날짜는 지정된 연도의 다음 주 기준 연도 일 수 있습니다.

관대 모드에서는 유효한 값 범위에 대해 연도와 요일의 유효성이 검사됩니다. 결과 날짜는 다음 3 단계 접근 방식과 동일하게 계산됩니다. 먼저 요청 된 주 기반 연도의 첫 번째주의 첫 번째 날에 날짜를 만듭니다. 그런 다음 주 단위 연도를 가져 와서 1을 빼고 날짜에 주 단위의 금액을 더합니다. 마지막으로 현지화 된 주 내에서 올바른 요일로 조정합니다.

이것의 설정 WeekFields 인스턴스 로케일에 따라 다르며 이에 따라 설정이 다를 수 있으며, 미국 및 프랑스와 같은 유럽 국가에서는 요일이 요일로 다를 수 있습니다.

예를 들어 DateFormatterBuilderJava 8의 경우 로케일로 구문 분석기를 인스턴스화하고 Y기호에 다음 로케일을 사용하십시오 .

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

        ...
    }

    ...
}

다음은 몇 가지 예입니다.

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

그리고 로케일과 상부 케이스의 점에서 Y, 명령 행 옵션을 사용하여 재생할 수 있습니다 -Duser.language=( fr, en, es, 등), 또는 호출시에 로케일을 강제로 :

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

Y달력이 주 연도를 지원하는 경우 주 연도를 가져 오는 형식 입니다. ( getCalendar().isWeekDateSupported())


0

요청 된 형식이 커버 아래에서 YYYY를 사용하므로 JSTL 태그 라이브러리 format:date가 어려운 방법을 배웠습니다 short. 실제로 인쇄 된 날짜를 1 년 앞당길 수 있습니다.


0

날짜를 앞뒤로 변환합니다. 이렇게하면 같은 해를 예상 할 수 있습니다.

그것이 어떻게 발전하는지 주목하십시오!

이것은 나쁘다 : YYYY! YYYY

여기서 실행할 수 있습니다 .

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

이것은 좋다 : yyyy

yyyy

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.