DateTimeImmutableに西暦1年を突っ込んだら勝手に2001年になる

概要

DateTimeImmutableに西暦1年を突っ込んだら勝手に2001年になる理由を探る。
なんだか、西暦は4桁0埋めじゃないと西暦1年扱いしてくれないようだった。

起きたこと

こういうコードだった。
無理やり2018年8月23日みたいな数字を2018-08-23にするやつ。

$target_date = '1年08月23日';

$search = array('年','月');
$date = str_replace($search,'-',$target_date);
// string(10) "1-08-23日"

$date = str_replace('日','',$date);
// string(7) "1-08-23"

$date = new \DateTimeImmutable($date);
// object(DateTimeImmutable)#106 (3) {
//   ["date"]=>
//   string(26) "2001-08-23 00:00:00.000000"
//   ["timezone_type"]=>
//   int(3)
//   ["timezone"]=>
//   string(3) "UTC" 
// }

$date = $jp_dt->format('Y-m-d');
// string(10) "2001-08-23"

なんだかDateTimeImmutableで2001年に変換されているみたいだ。
最初はunixtime(1970年1月1日9時0分0秒が0になるやつ)が原因かと思ったけどそれなら1971とかのはず…。

入力数値を変えることにする

0埋めが原因のような気がしたので桁を変える。

入力→出力
1年08月23日→2001-08-23
1年8月23日→2001-08-23
01年8月23日→2001-08-23
001年8月23日→2001-08-23
0001年08月23日→0001-08-23
0001年8月23日→0001-08-23

こんな感じになった。
どうやら西暦は4桁0埋めじゃないと西暦1年扱いしてくれないようだ…。

対策

こういう辛い関数を作って対応した。

	//Y-m-d 00:00:00 形式の年月日を0埋めする
	Public static function convertToZeroPaddingDate($datetime){
		$date = '0000-00-00';
		$time = '00:00:00';
		if(! is_string ( $datetime )){
			return $date . ' ' . $time;
		}

		if(strpos($datetime,'-') === false){
			return $date . ' ' . $time;
		}

		$dt = explode ( ' ' , $datetime );
		if(empty($dt[0])){
			return $date . ' ' . $time;
		}
		$date = $dt[0];
		$fullDate = explode ( '-' , $date );

		//年
		if(empty($fullDate[0])){
			return $date . ' ' . $time;
		}
		$year = $fullDate[0];
		$year = str_pad($year, 4, 0, STR_PAD_LEFT);

		//月
		if(empty($fullDate[1])){
			return $date . ' ' . $time;
		}
		$month = $fullDate[1];
		$month = str_pad($month, 2, 0, STR_PAD_LEFT);

		//日
		if(empty($fullDate[2])){
			return $date . ' ' . $time;
		}
		$day = $fullDate[2];
		$day = str_pad($day, 2, 0, STR_PAD_LEFT);

		//時間
		if(! empty($dt[1])){
			$time = $dt[1];
		}else{
			return $year .'-' . $month . '-' . $day;
		}

		return $year .'-' . $month . '-' . $day .' '.$time;
	}

気をつけよう。