LoginSignup
39
34

More than 5 years have passed since last update.

日付時刻関連で使われる書式の調査

Last updated at Posted at 2015-03-05

以下も併せてお読みください。

日付時刻の入力書式

以下の関数やメソッドで使われます。

書式について詳しく知りたい場合はサポートする日付と時刻の書式を参照してください。特に相対的な書式の注意事項には目を通しておくべきです。

ここではマニュアルを見ても分かりづらいであろう「変更される部分」「変更されない部分」を明らかにし、また具体例を中心にピックアップしていきたいと思います。

  • タイムゾーンはphp.iniで既定された値に従います。ここでは現在のタイムゾーンがUTCまたは+00:00に既定されていると仮定します。
  • 書式中にタイムゾーンが含まれていた場合、それに従います。
  • DateTimeZoneオブジェクトによりタイムゾーンが指定された場合、それに従います。
  • 書式中のタイムゾーンとDateTimeZoneオブジェクトが同時に競合した場合、書式中のタイムゾーンが優先されます。
  • 表中の*は現在値が使用されることを意味します。

絶対指定

指定対象 タイムゾーン 書式 注記
時刻 * * * 23 00 00 * 23:00:00
23.00.00
23:00:00.0000000
  • PHP5.3以降限定
  • マイクロ秒7桁以下
23.00.00.0000000
T23:00:00
230000 6桁
11 pm
11:00 PM
11.00 P.M.
年月日 2015 01 02 00 00 00 * 2015-01-02 年は4桁
15-1-2 非推奨
2-1-2015 年は4桁
2.1.2015 年は4桁
2.1.15 非推奨
2015/01/02 年は4桁
2015-1-2 年は4桁
1/2/2015 年は4桁
1/2/15 非推奨
2 January 2015
2 January 15 非推奨
January 2 2015
January 2 15 非推奨
2nd January 2015
2 Jan 2015
2-Jan 2015
2-Jan-2015
年月 2015 01 01 00 00 00 * 2015-01 年は4桁
January 2015
2015 January
Jan 2015
Jan-2015
月日 * 01 02 00 00 00 * 01/02
2 January
January 2
2nd January
2 Jan
2-Jan
Jan 2
Jan-2
2015 * * * * * * 2015 4桁
* 01 * 00 00 00 * January
Jan
年月日, 時刻 2015 02 03 23 03 04 * 2015-02-03 23:03:04 年は4桁
2015-02-03T23:03:04
年, 週番号, 曜日番号 2015 02 03 00 00 00 * 2015-W06-2
  • 年は4桁, 週は2桁, 曜日は1桁
  • 月曜日を1日曜日を7として番号付けをし, 月曜日を週の開始とする
  • 01前日として動作する
2015W062
年, 週番号 2015 02 01 00 00 00 * 2015-W06
2015W06
年, 通算日 2015 02 03 00 00 00 * 2015.034 年は4桁, 通算日は3桁
2015034
タイムスタンプ 2015 02 03 23 03 04 UTC @1422972184
  • DateTime::modifyで使うとタイムゾーン再設定が行われないバグがある
  • DateTime::setTimestampは整数を扱うため32ビット環境では2038年問題が発生するが、こちらは文字列で渡すためそれを回避することが出来る
タイムゾーン
(数値)
* * * * * * +09:00 +0900
  • 時刻に影響を及ぼさない
  • DateTime::modifyでは無視される
  • GMTは大文字
+09:00
GMT+09:00

相対指定

意味 タイムゾーン 書式 注記
現在 * * * * * * * now コンストラクタの規定値
時刻を00:00:00 * * * 00 00 00 * today
midnight
時刻を12:00:00 * * * 12 00 00 * today
時刻を前日の00:00:00 * * -1 00 00 00 * yesterday
時刻を翌日の00:00:00 * * +1 00 00 00 * tomorrow
時刻を18時15分前に * * * 17 45 00 * front of 18 タイムゾーン記述と併用すると12時間ずれるバグがある
front of 6 pm
時刻を18時15分後に * * * 18 15 00 * back of 18
back of 6 pm
時刻を1分前に * * * * -1 * * -1 min
-1 mins
-1 minutes
1 min ago
previous mins
first min ago
日付を2週間後に * * +14 * * * * +2 week
+2 weeks
2 weeks
next weeks next week
second weeks weeksは必ず複数形
(序数詞+週単位のケースが特例)
日付を月の初日に * * 1 * * * * first day of ofに月を続けると自然言語風らしくなる
日付を月の末日に * * 特殊 * * * * last day of
日付を月の2番目の木曜日に * * 特殊 00 00 00 * second Thursday of
日付を月の最後の水曜日に * * 特殊 00 00 00 * last Wednesday of
(今日を含む)
次の木曜日
* * 特殊 00 00 00 * Thursday
(今日を含まない)
次の火曜日
* * 特殊 00 00 00 * next Tuesday
(月曜を始まりとする)
来週の月曜日
* * 特殊 00 00 00 * Monday next week
(月曜を始まりとする)
先週の日曜日
* * 特殊 00 00 00 * Sunday previous week
タイムゾーン(名称)Asia/Tokyo * * * +9 * * Asia/Tokyo Asia/Tokyo
  • 時刻に影響を及ぼす
  • DateTime::modifyでは無視される

日付時刻の入力書式定義のための書式

以下のメソッドで使われます。

コンストラクタをそのまま使う際に問題であった解釈の曖昧性を、自分で書式定義することにより解消出来る有用なメソッドです。マニュアルに十分な説明があるので、具体例の紹介は割愛します。

日付時刻の出力書式

以下の関数やメソッドで使われます。

マニュアルに十分な説明があるので、具体例の紹介は割愛します。

時間の入力書式

以下のメソッドで使われます。この書式は他とは大きく見た目が異なりますが、非常にシンプルなので理解に困ることは無いでしょう。

マニュアルに十分な説明があるので、P <*Y><*M><*D|*W> T <*H><*I><*S>の形に従う通常の書式に関する具体例の紹介は簡便に済ませます。但し、このオブジェクトにはマニュアルに記載されていない隠しプロパティが存在しており、それはDateInterval::createFromDateStringを利用して生成することによってのみ設定することが可能なものです。

PHPバージョン 隠しプロパティを直接書き換えようとしたときの挙動
HHVM __set()メソッドがコールされ、Undefined property として例外が投げられる
5.3.27以降
5.4.17以降
5.5.0以降
全て 0 が設定される
5.3.26以前
5.4.16以前
意図通りの値が設定される

上記のとおりPHP言語の開発者サイドから「触るんじゃねーぞ!」みたいな圧力を受けている気がするので、もし可能なバージョンであったとしても自分で書き換えるのはやめておいたほうが良さそうです。

マニュアルに記載されているプロパティ

y m d h i s

書式 y m d h i s
P2D 0 0 2 0 0 0
P2W 0 0 14 0 0 0
PT2S 0 0 0 0 0 2
P6YT5M 6 0 0 0 5 0

この方法で直接負の値を設定することは出来ません。設定するには以下の何れかを採用してください。

オブジェクト生成後に個別にプロパティを設定する
$interval = new \DateInterval('P0D');
$interval->i = -1;
$interval->s = -30; 
DateInterval::createFromDateStringを利用してオブジェクトを生成する
$interval = \DateInterval::createFromDateString('-1 min -30 sec');

invert

0または1の値を取る、正負を逆転させるフラグです。以下のメソッドで結果が負になる演算を行った時、負の値をプロパティに代入する代わりにこのフラグがセットされた上で正の値が使われます。

これを手動で有効にすれば負の値を設定したときと同じ効果が得られます。

DateTimeImmutable::addでの利用
// 正を負に反転させたものを加算する
$interval = new \DateInterval('P1D');
$interval->invert = 1;
$date = (new \DateTimeImmutable('2015-03-05'))->add($interval);
echo $date->format('Y-m-d') . PHP_EOL; // 2015-03-04

// 負を正に反転させたものを加算する
$interval = \DateInterval::createFromDateString('-1 day');
$interval->invert = 1;
$date = (new \DateTimeImmutable('2015-03-05'))->add($interval);
echo $date->format('Y-m-d') . PHP_EOL; // 2015-03-06

但し、このフラグを正しく扱えるのは以下の加減算に直接関わるメソッドに限られます。

DateInterval::createFromDateString経由では単に負の値が設定されるだけで、このフラグには影響を及ぼさない
$interval = \DateInterval::createFromDateString('-1 day');
var_dump($interval->d); // int(-1)
var_dump($interval->invert); // int(0)
DatePeriodは負の間隔・invertフラグともに正しく取り扱えない
$a = new \DateTime('2015-02-15');
$b = new \DateTime('2015-02-20');
$negative_interval = \DateInterval::createFromDateString('-1 day');
$inverted_interval = new \DateInterval('P1D');
$inverted_interval->invert = 1;
$inverted_negative_interval = \DateInterval::createFromDateString('-1 day');
$inverted_negative_interval->invert = 1;

// 全て array(0) { }
var_dump(iterator_to_array(new \DatePeriod($b, $negative_interval, $a)));
var_dump(iterator_to_array(new \DatePeriod($b, $inverted_interval, $a))); 
var_dump(iterator_to_array(new \DatePeriod($b, $inverted_negative_interval, $a)));

// 全てメモリーリーク
var_dump(iterator_to_array(new \DatePeriod($a, $negative_interval, $b)));
var_dump(iterator_to_array(new \DatePeriod($a, $inverted_interval, $b)));
var_dump(iterator_to_array(new \DatePeriod($a, $inverted_negative_interval, $b)));

一貫性ガン無視な実装ですが、これもまたPHPならではの趣と言えるでしょう。

days

総日数を表します。以下のメソッドで演算を行った時にのみ設定される特別なプロパティとされます。

DateTime::diffで差を求める
$a = new \DateTime('2015-02-15');
$b = new \DateTime('2014-02-15');
$interval = $a->diff($b);
var_dump($interval->invert); // int(1)
var_dump($interval->y); // int(1)
var_dump($interval->m); // int(0)
var_dump($interval->d); // int(0)
var_dump($interval->days); // int(365)

マニュアルに記載されていないプロパティ

first_last_day_of

日数が月ごとに再計算されるかどうかを示すフラグです。
do_adjust_special_early関数によって処理されます。

first_last_day_of 意味 書式例
1 今月の初日 first day of
2 翌月の末日 last day of next month

weekday weekday_behavior have_weekday_relative

曜日を扱うフラグです。
do_adjust_relative関数によって処理されます。

weekday weekday_behavior have_weekday_relative 意味 書式
3 1 1 (今日を含む)
次の木曜日
Wednesday
2 1 1 (今日を含まない)
次の火曜日
next Tuesday
1 2 1 (月曜を始まりとする)
今週の月曜日
Monday this week
0 2 1 (月曜を始まりとする)
先週の日曜日
Sunday previous week

special_type special_amount have_special_relative

特別な処理を行うフラグです。have_weekday_relative と複合しているものもあります。
do_adjust_special関数によって処理されます。

special_type special_amount have_special_relative 意味 書式
1 2 1 2日間隔の平日 second weekday
2 0 1 今月の2番目の木曜日 second Thursday of
3 0 1 今月の最後の水曜日 last Wednesday of

時間の出力書式

以下のメソッドで使われます。この書式は他とはやや見た目が異なりますが、非常にシンプルなので理解に困ることは無いでしょう。PHPを含むさまざまな言語で利用されているprintfの書式に類似した形式です。

マニュアルに十分な説明があるので、具体例の紹介は割愛します。但し1点だけ注意があります。

自分でプロパティを設定すると、書式「%R%d」「%r%d」に従う出力が、マイナス2つが連なるものになり得る
$date = new \DateInterval('P0D');
$date->d = -1;
$date->invert = 1;
echo $date->format('%R%d') . PHP_EOL; // --1
echo $date->format('%r%d') . PHP_EOL; // --1

期間の入力書式

以下のメソッドで使われます。

3種類の引数の渡し方がありますが、このうち3番目の、以下に示される$isostrとして利用されます。

public DatePeriod::__construct ( string $isostr [, int $options ] )

ISO8601に従うとありますが、実際には更に以下の制約が付きます。

日付日時に対する制約

  • 日付と時刻を両方含む必要があり、デリミタとしてTが必要である。
  • タイムゾーンはUTC固定であり、それを意味するZがサフィックスとして必要である。

反復回数に対する制約

  • 回数にはプレフィックス R が必要である。

全体としての制約

以下の何れかのフォーマットに従う必要がある。

  • 開始日時/反復間隔/終了日時
  • 開始日時/終了日時/反復間隔
  • 開始日時/反復間隔/反復回数
  • 反復回数/開始日時/反復間隔
有効な例 (終了日時を採用)
$period = new \DatePeriod('2015-01-01T00:00:00Z/P1D/2016-01-01T00:00:00Z');
var_dump(count(iterator_to_array($period))); // int(365)
有効な例 (反復回数を採用)
$period = new \DatePeriod('2015-01-01T00:00:00Z/P1D/R364');
var_dump(count(iterator_to_array($period))); // int(365)

実際、3つの引数に分けて渡すこともできるので、無理に厳しい制約に従いつつ引数を1つにしなくても特に問題はないでしょう。

39
34
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
39
34