Y returns 2012 while y returns 2011 in SimpleDateFormat

JavaDateSimpledateformat

Java Problem Overview


I wonder why 'Y' returns 2012 while 'y' returns 2011 in SimpleDateFormat:

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

Can any one explain why?

Java Solutions


Solution 1 - Java

week year and year. From javadoc

> A week year is in sync with a WEEK_OF_YEAR cycle. All weeks between > the first and last weeks (inclusive) have the same week year value. > Therefore, the first and last days of a week year may have different > calendar year values. > > For example, January 1, 1998 is a Thursday. If getFirstDayOfWeek() is > MONDAY and getMinimalDaysInFirstWeek() is 4 (ISO 8601 standard > compatible setting), then week 1 of 1998 starts on December 29, 1997, > and ends on January 4, 1998. The week year is 1998 for the last three > days of calendar year 1997. If, however, getFirstDayOfWeek() is > SUNDAY, then week 1 of 1998 starts on January 4, 1998, and ends on > January 10, 1998; the first three days of 1998 then are part of week > 53 of 1997 and their week year is 1997.

Solution 2 - Java

Here's a Java 8 update with some code, as GregorianCalendar will probably be deprecated or removed from future JDK versions.

The new code is handled in the WeekFields class, and specifically for the lower case y / upper case Y with the weekBasedYear() field accessor.

> Returns a field to access the year of a week-based-year based on this > WeekFields. This represents the concept of the year where weeks start > on a fixed day-of-week, such as Monday and each week belongs to > exactly one year. This field is typically used with dayOfWeek() and > weekOfWeekBasedYear(). > > Week one(1) is the week starting on the getFirstDayOfWeek() where > there are at least getMinimalDaysInFirstWeek() days in the year. Thus, > week one may start before the start of the year. If the first week > starts after the start of the year then the period before is in the > last week of the previous year. > > This field can be used with any calendar system. > > In the resolving phase of parsing, a date can be created from a > week-based-year, week-of-year and day-of-week. > > In strict mode, all three fields are validated against their range of > valid values. The week-of-year field is validated to ensure that the > resulting week-based-year is the week-based-year requested. > > In smart mode, all three fields are validated against their range of > valid values. The week-of-week-based-year field is validated from 1 to > 53, meaning that the resulting date can be in the following > week-based-year to that specified. > > In lenient mode, the year and day-of-week are validated against the > range of valid values. The resulting date is calculated equivalent to > the following three stage approach. First, create a date on the first > day of the first week in the requested week-based-year. Then take the > week-of-week-based-year, subtract one, and add the amount in weeks to > the date. Finally, adjust to the correct day-of-week within the > localized week.

The setup of this WeekFields instance depends on the locale and may have different settings depending on it, US and European countries like France may have a different day as start of the week.

For example the DateFormatterBuilder of Java 8, instantiate the parser with the locale, and use this locale for the Y symbol :

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

        ...
    }

    ...
}

Here's some example

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

And in regard of the locale and the upper case Y, you can either play with the command line option -Duser.language= (fr, en, es, etc.), or force the locale at invocation time :

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

Solution 3 - Java

Format Y to get week year if calendar support week year. (getCalendar().isWeekDateSupported())

Solution 4 - Java

I learned the hard way the JSTL tag library format:date with short as the requested format uses YYYY under the covers. Which can indeed roll the printed date ahead a year.

Solution 5 - Java

I convert a date back and forth - you would expect the same year when you do this.

Notice how it advances one!

This is bad: YYYY! YYYY

You can run it here.

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

This is good: yyyy

yyyy

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEng.FouadView Question on Stackoverflow
Solution 1 - JavaAravind YarramView Answer on Stackoverflow
Solution 2 - JavaBriceView Answer on Stackoverflow
Solution 3 - JavaKV PrajapatiView Answer on Stackoverflow
Solution 4 - JavaErica KaneView Answer on Stackoverflow
Solution 5 - JavaJGFMKView Answer on Stackoverflow