Java Y以SimpleDateFormat返回2012,而Y以SimpleDateFormat返回2011

Java Y以SimpleDateFormat返回2012,而Y以SimpleDateFormat返回2011,java,date,simpledateformat,Java,Date,Simpledateformat,我想知道为什么“Y”返回2012而“Y”在SimpleDataFormat中返回2011: System.out.println(new SimpleDateFormat("Y").format(new Date())); // prints 2012 System.out.println(new SimpleDateFormat("y").format(new Date())); // prints 2011 有人能解释为什么吗?和年份。来自javadoc 一周一年与一周一年的周期同步。两周

我想知道为什么“Y”返回2012而“Y”在
SimpleDataFormat
中返回2011:

System.out.println(new SimpleDateFormat("Y").format(new Date())); // prints 2012
System.out.println(new SimpleDateFormat("y").format(new Date())); // prints 2011
有人能解释为什么吗?

和年份。来自javadoc

一周一年与一周一年的周期同步。两周之间 第一周和最后一周(含)具有相同的周-年值。 因此,一年中一周的第一天和最后几天可能会有不同的结果 日历年值。

例如,1998年1月1日是星期四。如果getFirstDayOfWeek()为 星期一和getMinimalDaysInFirstWeek()为4(ISO 8601标准 然后1998年第1周从1997年12月29日开始, 并于一九九八年一月四日结束。过去三年的一周是1998年 1997日历年的天数。但是,如果getFirstDayOfWeek()是 星期日,然后是1998年第1周,开始于1998年1月4日,结束于 一九九八年一月十日;;1998年的前三天是一周的一部分 1997年的第53周,他们的周年是1997年


格式化
Y
以获取周年(如果日历支持周年)。(
getCalendar().isWeekDateSupported()

我用
short
艰难地学习了JSTL标记库
格式:date
,因为请求的格式在封面下使用YYYY。这确实可以将打印日期提前一年。

这里有一个Java 8更新,其中包含一些代码,因为GregoriaCalendar可能会被弃用或从未来的JDK版本中删除

新代码在
WeekFields
类中处理,特别是对于小写
y
/大写
y
,使用字段访问器

返回一个字段,以便根据此字段访问基于周的年份 WeekFields。这代表了一年中周开始的概念 在一周中的固定日期,如星期一和每周属于 整整一年。此字段通常与dayOfWeek()和 weekOfWeekBasedYear()

第一周(1)是从getFirstDayOfWeek()开始的一周,其中 一年中至少有getMinimalDaysInFirstWeek()天因此, 第一周可以在年初之前开始。如果第一周 在年初之后开始,之前的期间在 上一年的最后一周。

此字段可用于任何日历系统

在解析的解析阶段,可以从 基于周的年、年中的周和周中的天

在严格模式下,所有三个字段都根据其范围进行验证 有效值。验证“年度周”字段,以确保 生成的基于周的年是请求的基于周的年

在智能模式下,所有三个字段都根据其范围进行验证 有效值。基于周的年字段的有效期从1到 53,这意味着结果日期可以是 指定年份的周数

在宽松模式下,根据 有效值的范围。计算得出的日期等于 以下三个阶段的方法。首先,在第一天创建一个日期 请求的基于周的年份中第一周的日期。那就乘火车吧 基于年份的周数,减去一,然后将周数相加到 日期。最后,调整到一周中正确的一天 本地化周

WeekFields
实例的设置取决于区域设置,并且可能有不同的设置,这取决于该区域设置,美国和欧洲国家(如法国)可能有不同的一天作为一周的开始

例如,Java 8的
DateFormatterBuilder
,使用区域设置实例化解析器,并将此区域设置用于
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);
        }

        ...
    }

    ...
}
关于区域设置和大写字母
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)));

我来回转换一个日期——当你这样做的时候,你会期待同一年

注意它是如何进步的

这很糟糕:YYYY!

你可以运行它

这是好的:yyyy


作为对未来读者的提醒:这种行为只会发生在一年的最后一周或一年的第一周。
$date Wed Dec 30 00:42:51 UTC 2015
$date+%G 2015
$date+%Y 2015
一些软件感到困惑:
strftime
将今天(12/29/2015)计算为第53周,2015年为一周。
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)));
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);
    }
}