読者です 読者をやめる 読者になる 読者になる

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.htmlGNU ユーティリティの場合は以下の 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