暦週の基準年について

1,はじめに

昨日Twitterを流し見していたところ、Javaの日付の書式について興味深いTweetがあった。

それは、暦週の基準年という考え方についてであった。

暦週の基準年とは、新年度の1月1日と同じ週に属する日については、新年度に属するとする考え方である(ISO 8601, 2.3.暦週日付)。

この日付の仕様が、私が使用している他の言語(Perl)ではどうなのかについて、調べてみたい。

2,暦週の基準年

(1)何が問題なのか

以下がJavaの日付の特殊な書式について発見をした方のTweetである。

まずは、問題の再現を試みたい。

筆者の環境は下記の通りである。

R:\>javac -version
javac 1.8.0_152

以上の環境で、先述のJavaの仕様を確認できたコードは下記の通りである。

TestDataFormat.java

/*
 * TestDateFormat
 * 2018/12/31
 * jskny
 */

import java.util.Date;
import java.text.SimpleDateFormat;
import java.text.ParseException;

public class TestDateFormat {
	public static void main(String[] args) {
		Date tDate = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
		// 暦週の基準年を使用する場合、
		// 年の指定の「y」を小文字の「y」から大文字の「Y」にする。
		SimpleDateFormat sdf2 = new SimpleDateFormat("YYYY/MM/dd");


		System.out.println("===== Data Format Test =====");
		// 現在の日時を表示
		System.out.println("@ Running Date");
		System.out.println(tDate);

		// 指定日時のセットとその表示 (2018/1/1)
		System.out.println("@ Selected Date (2018/1/1)");
		try {
			tDate = sdf.parse("2018/1/1");
		}
		catch (ParseException e) {
			e.printStackTrace();
		}
		System.out.println(tDate);


		System.out.println("");
		System.out.println("[NORMAL CASE]");
		// 問題となる暦週の基準年(正常変換の場合)
		System.out.println("@ Figure yyyy (2018/12/31)");
		try {
			tDate = sdf.parse("2018/12/31");
		}
		catch (ParseException e) {
			e.printStackTrace();
		}
		System.out.println(tDate);


		System.out.println("[ABNORMAL CASE]");
		System.out.println("@ Figure YYYY (2018/12/31)");
		try {
			tDate = sdf2.parse("2018/12/31");
		}
		catch (ParseException e) {
			e.printStackTrace();
		}
		System.out.println(tDate);

		// 2018/12/31 12:39
		// 暦週の基準年の方は、年が2018ではなく2019になると思っていたが、
		// 2017として出力されていた。前年がなぜ出力されるのだろうか。
/* 出力結果
[NORMAL CASE]
@ Figure yyyy (2018/12/31)
Mon Dec 31 00:00:00 JST 2018
[ABNORMAL CASE]
@ Figure YYYY (2018/12/31)
Sun Dec 31 00:00:00 JST 2017
*/

		System.out.println("====================");
		try {
			tDate = sdf.parse("2018/12/31");

			System.out.println("[NORMAL CASE 2]");
			System.out.println(sdf.format(tDate));
			System.out.println("[ABNORMAL CASE 2]");
			System.out.println(sdf2.format(tDate));
		}
		catch (ParseException e) {
			e.printStackTrace();
		}

// 問題の再現確認 2018/12/31 12:44
/* 出力結果
[NORMAL CASE 2]
2018/12/31
[ABNORMAL CASE 2]
2019/12/31
*/
	}
}

出力結果

R:\>java TestDateFormat
===== Data Format Test =====
@ Running Date
Mon Dec 31 12:45:18 JST 2018
@ Selected Date (2018/1/1)
Mon Jan 01 00:00:00 JST 2018

[NORMAL CASE]
@ Figure yyyy (2018/12/31)
Mon Dec 31 00:00:00 JST 2018
[ABNORMAL CASE]
@ Figure YYYY (2018/12/31)
Sun Dec 31 00:00:00 JST 2017
====================
[NORMAL CASE 2]
2018/12/31
[ABNORMAL CASE 2]
2019/12/31

以上のように、暦週の基準年が使用された場合、新年の1月1日と同じ週に属する12月31等は、2018年ではなく、2019年として処理されている。

(2)Perlの場合

この暦週の基準年という日付処理は、他の言語でも取り入れられている考え方だろうか。

まずは、Perlの日付処理で試してみたい。

結論から言えば、標準モジュールには搭載されていないと思われるが、よくわからない。

TestDataFormat.pl

# Perlでの日付処理
# 2018/12/31
# jskny

use strict;
use warnings;

# Perl 5.10 から標準搭載
# 詳しい使用方法等につき、下記サイトをご確認ください。
# http://d.hatena.ne.jp/perlcodesample/20091105/1246274997
use Time::Piece;


# Time::Pieceオブジェクトの取得
my $t = localtime;

# 現在日時の表示
print $t->datetime . "\n";


# 指定日時のセット
$t = Time::Piece->strptime("2018/1/1", "%Y/%m/%d");
print $t->datetime . "\n";


print "[NORMAL CAEE]\n";
$t = Time::Piece->strptime("2018/12/31", "%Y/%m/%d");
print $t->datetime . "\n";


# モジュールがあるのかよくわからないので、手動で実装すればよい。
# 次の年度の1月1日が月曜日でない場合、
# 1/1の曜日から何日減算すれば月曜日になるかを計算し、
# その減算値分、前年度の12月末日から新年度に属する日数を算出する。

print "[ABNORMAL CAEE]\n";
$t = Time::Piece->strptime($t->year + 1 . "/1/1", "%Y/%m/%d");
# 1が日曜日
my $tmp = $t->wday;
if ($tmp eq 1) {
	# ISO 8061 的には月曜日からのカウント開始なので、
	# 日曜日を最後に持ってくる。
	$tmp = 8;
}

if ($tmp eq 2) {
	print "年の更新の必要はありません。" . "\n";
}
else {
	# 1/1の週初めが月曜日ではないため、12月末日からさかのぼる数日が、
	# 新年度に属する日を出す。
	$tmp -= 2;
	for (my $i = 0; $i strptime("2018/12/" . (31 - $i), "%Y/%m/%d");
		print $t->year . "/" . $t->mon . "/" . $t->mday . " is [2019]\n";
	}

}

出力結果

R:\>perl TestDateFormat.pl
2018-12-31T13:46:36
2018-01-01T00:00:00
[NORMAL CAEE]
2018-12-31T00:00:00
[ABNORMAL CAEE]
2018/12/31 is [2019]

3,おわりに

これで最悪の場合、年末がつぶれるエンジニアが出るかと思うと、大文字の「Y」と小文字の「y」に違いを持たせたJavaの作者たちは正気を失っていると思う。

せめて別な文字にしてほしいな。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA