Skip to tool
ecech.
🕑 Date, Time & Timezone

YYYY Is Not the Year, and It Is Wrong for Three Days Every January

In Unicode patterns YYYY is the week-numbering year. 31 December 2019 renders as 2020, which is where the New Year date bugs come from.

Renders as

Calendar year

Week-numbering year

what YYYY gives you

ISO week

Day of year

Every token, against this date

The same date in common formats

Advertisement

How the calculation works

31 December 2019, two patterns yyyy-MM-dd 2019-12-31 YYYY-MM-DD 2020-12-31 Capital Y is the ISO week-numbering year, and that week belongs to 2020. It agrees with the calendar year 362 days out of 365, which is why it survives testing.

How to Use This Tool

Pick a token style, type a pattern, and see it rendered. Testing takes a second and catches the mistakes that reasoning about the letters does not.

The one that ruins New Year

In Unicode date patterns — used by Java, .NET, ICU and Moment-style libraries — yyyy is the calendar year and YYYY is the ISO week-numbering year. They are different things.

The ISO week-numbering year follows whole weeks. A week belongs to the year containing its Thursday, so the last few days of December can belong to the following year's week 1. On 31 December 2019 the week-numbering year is 2020, and YYYY-MM-DD renders 2020-12-31.

The reason this survives testing is that the two agree on roughly 362 days out of 365. Code written and tested in March looks perfect, ships, and produces wrong dates for a few days each January — which is why a wave of date bugs appears in the first week of the year, every year.

Unless you are deliberately formatting an ISO week date, you want lowercase yyyy.

Two more that behave the same way

  • D against d. In Unicode patterns d is the day of the month and D is the day of the year. DD renders 05 on 5 January and 152 in June, so it also passes early-January testing.
  • mm against MM. In Unicode patterns lowercase mm is minutes and uppercase MM is months. In strftime it is the opposite way round: %m is the month and %M is minutes. The same habit produces the wrong result in the other system.
Same letters, different meanings strftime Unicode month %mMM minute %Mmm day of month %ddd day of year %jDDD exactly swapped
Which system a library uses is rarely stated prominently, and the failure is silent.

The two systems

  • strftime uses percent-prefixed letters: %Y-%m-%d %H:%M:%S. Used by C, Python, PHP's strftime, shell date and most Unix tooling. The percent prefix makes literal text unambiguous, which is its main advantage.
  • Unicode patterns use repeated letters: yyyy-MM-dd HH:mm:ss. Used by Java, .NET, ICU and libraries modelled on them. Literal text must be quoted with single quotes, which is why ISO patterns contain 'T'.

The number of repeats usually means width: M is 1 or 2 digits, MM is always 2, MMM is a short name and MMMM is the full one.

When not to use a pattern at all

Two cases where hand-writing a format is the wrong instinct:

  • Machine-readable output. Use ISO 8601 and let the library produce it. It is unambiguous, it sorts as text, and every parser accepts it.
  • Text a person reads. Use the platform's locale formatting. Date order, month names, separators and the position of the year all differ by locale, and a hand-written MM/DD/YYYY is wrong for most of the world — and genuinely ambiguous everywhere, since 03/04 is two different days depending on the reader.

Explicit patterns are right for a fixed file format, a legacy interface, or somewhere the exact layout is specified. Everywhere else, a locale-aware formatter produces better output with less code.

Advertisement

Frequently Asked Questions

What is the difference between YYYY and yyyy?
In Unicode patterns, yyyy is the calendar year and YYYY is the ISO week-numbering year. They differ for a few days around each new year — 31 December 2019 renders as 2020 under YYYY, which is where the January date bugs come from.
Why does my date show the wrong year in January?
Almost certainly a capital YYYY in the pattern. The week-numbering year follows whole weeks, so late December can belong to the next year. The two agree about 362 days out of 365, which is why the bug survives testing and appears every January.
Is mm the month or the minute?
It depends on the system, and they are opposite. In Unicode patterns MM is the month and mm is minutes; in strftime %m is the month and %M is minutes. The same habit gives the wrong answer in the other system.
What does DD mean in a date format?
In Unicode patterns, the day of the year — so 05 on 5 January and 152 in June. The day of the month is lowercase dd. Like the year problem, it passes an early-January test and fails later.
What is the difference between strftime and Unicode patterns?
strftime uses percent-prefixed letters like %Y-%m-%d and is used by C, Python, PHP and shell tools. Unicode patterns repeat letters like yyyy-MM-dd and are used by Java, .NET and ICU. Literal text needs single quotes in Unicode patterns, which is why ISO formats contain 'T'.
Should I write my own date format string?
For a fixed file format or a specified interface, yes. For machine-readable output use ISO 8601 and let the library produce it. For text a person reads, use locale formatting — a hand-written MM/DD/YYYY is wrong for most of the world and ambiguous everywhere.

Related tools in Date, Time & Timezone

Browse all Date, Time & Timezone tools
The person who builds ecech., at the desk where the tools are written.

Made by one person

ecech. is not a content farm. Every tool here is written and checked by hand, one at a time, by someone who wanted the tool to exist and could not find a version that showed its working.

No accounts and no sign-in, and nothing you type reaches a server — every calculation on this page runs inside your browser. The ads are served by Google and do set their own cookies, which is set out in full on the privacy page. More about the site.