Y以SimpleDateFormat返回2012,而y返回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

谁能解释为什么?


36
谨记给将来的读者:这种行为只会发生在一年的最后一周或一年的第一周。
ryvantage 2014年

Answers:


90

一年又一年。从javadoc

一周的一周与WEEK_OF_YEAR周期保持同步。第一周到最后一周(包括最后一周)之间的所有星期都具有相同的周年值。因此,一周的第一天和最后一天可能具有不同的日历年值。

例如,1998年1月1日是星期四。如果getFirstDayOfWeek()为MONDAY并且getMinimalDaysInFirstWeek()为4(ISO 8601标准兼容设置),则1998年的第1周从1997年12月29日开始,到1998年1月4日结束。最后三天的年是1998年。但是,如果getFirstDayOfWeek()是SUNDAY,则1998年的第1周从1998年1月4日开始,到1998年1月10日结束。1998年的前三天是1997年第53周的一部分,而一周是1997年。


$ date Wed Dec 30 00:42:51 UTC 2015 $ date +%G 2015 $ date +%Y 2015 一些软件很困惑:strftime今天(2015
。– aks

11

这是Java 8的更新,其中包含一些代码,因为GregorianCalendar可能会在以后的JDK版本中弃用或删除。

新代码在WeekFields该类中处理,尤其是使用字段访问器的小写y/大写形式。YweekBasedYear()

返回一个字段,以基于此WeekFields访问基于星期的年份。这代表一年的概念,其中周从固定的一周中的某一天开始,例如星期一,而每个星期恰好属于一年。该字段通常与dayOfWeek()和weekOfWeekBasedYear()一起使用。

第一周(1)是从getFirstDayOfWeek()开始的一周,一年中至少有getMinimalDaysInFirstWeek()天。 因此,第一周可能会在今年年初之前开始。如果第一周在年初之后开始,则之前的时间段是在上一年的最后一周。

该字段可用于任何日历系统。

在解析的解析阶段,可以从基于周的年份,一年中的某周和一周中的某天创建日期。

在严格模式下,将针对这三个字段的有效值范围进行验证。验证“年度周”字段以确保所得的基于周的年是请求的基于周的年。

在智能模式下,将对三个字段的有效值范围进行验证。以周为基础的年份字段从1到53进​​行验证,这意味着结果日期可以是指定日期之后的以周为基础的年份。

在宽大模式下,将根据有效值范围来验证年和星期几。计算得出的日期等效于以下三个阶段的方法。首先,在所请求的基于周的年份的第一周的第一天创建日期。然后,以周为基础的年份为基础,减去一,并将日期中的周数相加。最后,在本地化周内调整为正确的星期几。

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=frenes等),或强制在调用时的语言环境:

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.