ややこしい日付の書式について
Twitterにログインできない方々がいらっしゃるようです。担当チームが対応中ですので、しばらくお待ちくださいませ。たいへんご面倒をおかけいたします。
— TwitterJP (@TwitterJP) December 29, 2014
2014/12/29 に発生した Twitter にログインできない問題が Rebuild で言及されていた。
Date header がおかしくなっていた原因として、暦週の基準年(ISO 8601) が用いられていたのではないかという話があった。
Just don't use "Week year" (YYYY or %G) when printing time. #twitter http://t.co/Io057bVHWU
— Tatsuhiko Miyagawa (@miyagawa) December 29, 2014
暦週の基準年
たとえば、1998 年 1 月 1 日は木曜日です。getFirstDayOfWeek() が MONDAY で getMinimalDaysInFirstWeek() が 4 (ISO 8601 規格に準拠した設定) の場合、1998 年の第 1 週は 1997 年 12 月 29 日に始まり 1998 年 1 月 4 日で終わります。 暦年が 1997 年の最後の 3 日については、暦週の基準年が 1998 になります。 ただし、getFirstDayOfWeek() が SUNDAY の場合、1998 年の第 1 週は 1998 年 1 月 4 日に始まり 1998 年 1 月 10 日に終わります。1998 年の最初の 3 日間は 1997 年の第 53 週に入り、それらの日の暦週の基準年は 1997 です。
GregorianCalendar (Java Platform SE 7)
月曜始まりの場合、getMinimalDaysInFirstWeek() が 4 だと最初の週が 1998 年になる。
月 | 火 | 水 | 木 | 金 | 土 | 日 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
日曜始まりの場合、getMinimalDaysInFirstWeek() が 4 だと二週目から 1998 年になる。
日 | 月 | 火 | 水 | 木 | 金 | 土 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
上記をふまえ、1998/1/1 に日付の書式 yyyy を使うと最初の例の場合 1998、YYYY だと 1997 となる。
文字 | 日付日付または時刻のコンポーネント |
---|---|
y | 年 |
Y | 暦週の基準年 |
SimpleDateFormat (Java Platform SE 7)
Java でこれを確認すると、2014/12/29 は 2015 年になった。
import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class Main { public static void main(String[] args) { Date date = null; try { date = DateFormat.getDateInstance().parse("2014/12/29"); } catch (ParseException e) { e.printStackTrace(); } SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); System.out.println(sdf.format(date)); sdf.applyPattern("YYYY/MM/dd"); System.out.println(sdf.format(date)); } }
出力結果:
2014/12/29 2015/12/29
上記の結果になるということは、月曜始まりの暦週の基準年(ISO 8601)が使われていたのだろう。
月 | 火 | 水 | 木 | 金 | 土 | 日 |
---|---|---|---|---|---|---|
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 | 1 | 2 | 3 | 4 |
なお .NET の場合、ISO 8601 とは微妙に違う挙動をする。
ISO 8601 Week of Year format in Microsoft .Net
Imports System Imports System.Globalization Module Module1 Sub Main() Dim cal As Calendar = New CultureInfo("en-US").Calendar Dim cwr As CalendarWeekRule = CalendarWeekRule.FirstFourDayWeek Dim dow As DayOfWeek = DayOfWeek.Monday Dim dt = New System.DateTime(2014, 12, 29) Console.WriteLine("{0}, {1}", cal.GetWeekOfYear(dt, cwr, dow), dt.Year) dt = New System.DateTime(2015, 1, 1) Console.WriteLine("{0}, {1}", cal.GetWeekOfYear(dt, cwr, dow), dt.Year) End Sub End Module
出力結果:
53, 2014 1, 2015
上記の設定の場合、年初が木曜日を含むとその週の 1 月の GetWeekOfYear が 1 を返し、年初が金曜以降の場合、その週の 1 月の GetWeekOfYear は前年の最終週を返す。