strftimeの %G とは何か?
手元のFreeBSDでman strftimeとしてマニュアルを読むと、
%G is replaced by a year as a decimal number with century. This year is the one that contains the greater part of the week (Monday as the first day of the week).
とあります。これだけではいったい何やらわかりませんので、いくつか実例を試してみます。
(dateコマンドはオプションが -u 以外全く標準化されておらず(参照 http://pubs.opengroup.org/onlinepubs/9699919799/utilities/date.html )GNU ユーティリティの場合は以下の FreeBSD の場合と違ってますので注意してください)まず大晦日の日付から。
$ date -jur `date -ju 200912311200 '+%s'` '+%G' 2009 $ date -jur `date -ju 201012311200 '+%s'` '+%G' 2010 $ date -jur `date -ju 201112311200 '+%s'` '+%G' 2011 $ date -jur `date -ju 201212311200 '+%s'` '+%G' 2013 # 翌年になっている $ date -jur `date -ju 201312311200 '+%s'` '+%G' 2014 # 翌年になっている $ date -jur `date -ju 201412311200 '+%s'` '+%G' 2015 # 翌年になっている $ date -jur `date -ju 201512311200 '+%s'` '+%G' 2015 $ date -jur `date -ju 201612311200 '+%s'` '+%G' 2016 $ date -jur `date -ju 201712311200 '+%s'` '+%G' 2017
続いて元日の日付。
$ date -jur `date -ju 201001011200 '+%s'` '+%G' 2009 # 前年になっている $ date -jur `date -ju 201101011200 '+%s'` '+%G' 2010 # 前年になっている $ date -jur `date -ju 201201011200 '+%s'` '+%G' 2011 # 前年になっている $ date -jur `date -ju 201301011200 '+%s'` '+%G' 2013 $ date -jur `date -ju 201401011200 '+%s'` '+%G' 2014 $ date -jur `date -ju 201501011200 '+%s'` '+%G' 2015 $ date -jur `date -ju 201601011200 '+%s'` '+%G' 2015 # 前年になっている $ date -jur `date -ju 201701011200 '+%s'` '+%G' 2016 # 前年になっている
このように、年末年始の日付の場合にズレ込むことがある「年」を %G は表示します。
マニュアルの最後のほうに、
The peculiar week number and year in the replacements of ‘%G’, ‘%g’ and ‘%V’ are defined in ISO 8601: 1988.
とあるように、これは %V と組み合わせて使うためのものですので、%V の説明を見てみると、
%V is replaced by the week number of the year (Monday as the first day of the week) as a decimal number (01-53). If the week containing January 1 has four or more days in the new year, then it is week 1; otherwise it is the last week of the previous year, and the next week is week 1.
ここでの「週」は月曜始まりで、元日を含む週が4日(以上)あればその週が(その年の)第1週、さもなくばその週は前年の最終週となり次の週が(新年の)第1週である、とあります。
ウィキペディアの、ISO 8601 の記事中にも説明がありますが、このように「週」を規定した場合の「年」を表示するのが %G です。
(余談ですが、%Uおよび%Wは、それぞれの年の第1日曜日あるいは第1月曜日の週を第1週とし、その前の週に含まれるその年の日は第0週とします)
Rubyリファレンスマニュアルのstrftimeの説明では欠けていますが(気が向いたらcontributeする予定)、ソースコード中のrdocでは年と週がまとめてあり、1月4日を含む週の月曜から第1週が始まる、その前の週は前年の最終週である、と説明しています。表現は少し違いますが、内容的には全く同じです。
最後に、2014年末~2015年始を、いくつかの「年・第n週・週内日」表現で見てみます。まずカレンダーを示します。
2014/Dec~2015/Jan Sun Mon Tue Wed Thu Fri Sat 21 22 23 24 25 26 27 28 29 30 31 1 2 3 4 5 6 7 8 9 10
ISO 8601の記法と、strftimeの他のユースケースで、12月26日~1月6日を表示してみます。
$ date -jur `date -ju 201412261200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2014-W52-5 / 2014_51_5 / 2014_51_5 $ date -jur `date -ju 201412271200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2014-W52-6 / 2014_51_6 / 2014_51_6 $ date -jur `date -ju 201412281200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2014-W52-7 / 2014_51_7 / 2014_52_0 $ date -jur `date -ju 201412291200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2015-W01-1 / 2014_52_1 / 2014_52_1 $ date -jur `date -ju 201412301200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2015-W01-2 / 2014_52_2 / 2014_52_2 $ date -jur `date -ju 201412311200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2015-W01-3 / 2014_52_3 / 2014_52_3 $ date -jur `date -ju 201501011200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2015-W01-4 / 2015_00_4 / 2015_00_4 $ date -jur `date -ju 201501021200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2015-W01-5 / 2015_00_5 / 2015_00_5 $ date -jur `date -ju 201501031200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2015-W01-6 / 2015_00_6 / 2015_00_6 $ date -jur `date -ju 201501041200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2015-W01-7 / 2015_00_7 / 2015_01_0 $ date -jur `date -ju 201501051200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2015-W02-1 / 2015_01_1 / 2015_01_1 $ date -jur `date -ju 201501061200 '+%s'` '+%G-W%V-%u / %Y_%W_%u / %Y_%U_%w' 2015-W02-2 / 2015_01_2 / 2015_01_2