DateTimeFormatterのyyyyとYYYYの違いについて
Javaで日付と時刻をフォーマットするためのクラスとしてDateTimeFormatter
があります。このクラスは、日付や時刻を文字列に変換したり、文字列から日付や時刻を解析するためのフォーマットパターンを指定できます。たとえば、"yyyy-MM-dd"
のようなフォーマットを指定すると、日付を「2025-01-06」のような形式に変換できます。
(Java 8以降なら変わらないと思いますが、Java21で動作確認しました)
| JShellへようこそ -- バージョン21.0.4
| 概要については、次を入力してください: /help intro
jshell> import java.time.format.DateTimeFormatter;
jshell> import java.time.LocalDate;
jshell> LocalDate date = LocalDate.now();
date ==> 2025-01-12
jshell> var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
formatter ==> Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)
jshell> date.format(formatter);
$7 ==> "2025-01-12"
このうち年を表すパターン文字列についてはドキュメントに
Symbol Meaning Presentation Examples
------ ------- ------------ -------
y year-of-era year 2004; 04
Y week-based-year year 1996; 96
と2つありましたので、この違いを調べてみました。
yyyyとYYYYの違い
それぞれの特徴を以下にまとめます。
yyyy: 年(Year-of-era)
-
yyyy
はカレンダー年(通常の年)を表します。 - 年の始まりは1月1日で、年末は12月31日です。
- 例:
2025-01-01
はyyyy
で「2025」となります。
YYYY: 週基準の年(Week-based-year)
YYYY
はISO週番号に基づく年を表します。
具体的にどういうことかというと、
The ISO 8601 definition for week 01 is the week with the first Thursday of the Gregorian year (i.e., of January) in it.
とのことで、「最初の木曜日を含む週」がその年の最初の週となります。
つまり、以下のようになります。
jshell> var formatter = DateTimeFormatter.ofPattern("YYYY-MM-dd");
formatter ==> Localized(WeekBasedYear,4,19,EXCEEDS_PAD)'-'Value ... r,2)'-'Value(DayOfMonth,2)
jshell> var date = LocalDate.parse("2024-12-31") ;
date ==> 2024-12-31
jshell> date.format(formatter);
$8 ==> "2025-12-31"
2024-12-31
をYYYY-MM-dd
で文字列にフォーマットすると2025-12-31
になってしまいました。
これは2024-12-31の週の木曜日は1/2で2025年であるためです。
uuuu
について
あまり使わないと思いますが、DateTimeFormatter
の書式指定子には uuuu
もあります。
Symbol Meaning Presentation Examples
u year year 2004; 04
この指定子は y
(year-of-era)とよく似ていますが、いくつかの違いがあります。
-
uuuu
:- ISOベースのカレンダーシステムで使用される「年」をそのまま表します。
- 負の値もそのまま扱い、西暦0年や負の年も表現できます。
具体的には以下のようになります。
jshell> var date = LocalDate.of(-44, 3, 15);
date ==> -0044-03-15
jshell> var formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
formatter ==> Value(YearOfEra,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)
jshell> date.format(formatter);
$13 ==> "0045-03-15"
jshell> var formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd");
formatter ==> Value(Year,4,19,EXCEEDS_PAD)'-'Value(MonthOfYear,2)'-'Value(DayOfMonth,2)
jshell> date.format(formatter);
$15 ==> "-0044-03-15"
紀元前44年を扱っているつもりなのですが、yyyyだと紀元45年になってしまいました。uuuuだと紀元前44年になっています。
まとめ
ドキュメントのExamples
Symbol Meaning Presentation Examples
------ ------- ------------ -------
y year-of-era year 2004; 04
Y week-based-year year 1996; 96
だと一見どちらでも良さそうです。
また、例えば、Pythonだと
Python 3.12.7 (main, Oct 30 2024, 03:17:17) [GCC 11.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from datetime import datetime
>>> date = datetime(2024, 12, 31)
>>> date.strftime("%Y-%m-%d")
'2024-12-31'
のようになり、年のフォーマットにはYを使います。
そのため何気なくYYYYを使ってしまいそうです。
しかし、week-based-year
も必要な人はどこかにいるのだと思いますが、基本的にDateTimeFormatterでYYYYを使っていたらバグの可能性が高いです。