PHPで2つの日付の差を計算

こんにちは、さるまりんです。

誕生日から何日?とか今日は今年度何日目?とか調べてみたい時ないですか?

それを調べるにはどうしたらいいかPHPでやってみました。

2つの日付の差を日数で取得

date_diff.php

// コマンドプロンプトで渡された文字列が3未満なら処理を停止します。
if(count($argv) < 3) exit;

// 受け取った文字列を日時の値に変換します。
$timestamp1 = strtotime($argv[1]);
$timestamp2 = strtotime($argv[2]);

// どちらが大きいか(後か)を判断して、その差分を計算します。
$diff = ($timestamp1 > $timestamp2) ? $timestamp1 - $timestamp2 : $timestamp2 - $timestamp1;

// 差分を日数に
$num_of_days = $diff / (60 * 60 * 24);

// 結果を表示
echo "2つの日付: {$argv[1]}, {$argv[2]}\n";
echo "差は? {$num_of_days}日\n";

呼び出し方は

php date_diff.php yyyy/mm/dd yyyy/mm/dd

です。

試しにやってみますね。

お手伝いさせてもらっているさくらいろさん(@sakuradecafe)の「さくらdeカフェ」の一番最初の記事が公開された日は2017年7月1日です。
その日からこの記事の公開日(2018年7月18日)まで何日かを調べてみます。

php date_diff.php 2017/07/01 2017/07/18

実行結果

2つの日付: 2017/07/01, 2018/07/18
差は? 382日

結果は382日でした。1年とちょっと。積み重ねですね♪

中身はどうなっているの?

簡単ですがプログラムの内容を追っていきますね。

if(count($argv) < 3) exit;

コマンドプロンプとで渡された引数は$argvという配列に格納されてプログラムに渡されます。
1番目(0番目)はプログラム名、その後に続くものが順番に格納されています。

count()でいくつ格納されているかを調べています。

計算には日付の文字列が2つ必要なので、$argv[0]にプログラム名(date_diff.php)、$argv[1]$argv[2]に日付の文字列と言ったように、全部で最低でも3つの値が必要です。

なので3未満だと処理ができないのでexitで処理を終了しています。

$timestamp1 = strtotime($argv[1]);
$timestamp2 = strtotime($argv[2]);

次は変換です。
strtotime()は文字列を日時の値に変換してくれます。この日時の値はUTC(協定世界時)で1970年1月1日の00:00:00からの秒数で表します。
$argv[1]$argv[2]にそれぞれコマンドプロンプトで渡された日付が入っています。

$diff = ($timestamp1 > $timestamp2) ? $timestamp1 - $timestamp2 : $timestamp2 - $timestamp1;

差分の計算です。ここでは秒を求めています。
求めた秒数が正の数になるように$timestamp1$timestamp2の値を比較して大きい方から小さい方を引くようにしています。
$timestamp1の方が大きければ$timestamp1から$timestamp2を、そうでなければ$timestamp2から$timestamp1を引く、ですね。

$num_of_days = $diff / (60 * 60 * 24);

そして秒数を日数に変換です。
$diffには差の秒数が入っているので、それを1日分の秒数(60秒×60分×24時間)で割ると日数で結果が出ることになります。

echo "2つの日付: {$argv[1]}, {$argv[2]}\n";
echo "差は? {$num_of_days}日\n";

最後は結果表示です。

いかがでしょう?

このプログラムのダメなところ

strtotime()で変換できる文字列には決められた形式があります。
プログラムに渡された文字列が変換可能な形式できているかをチェックして処理を進めないと途中でエラーとなってしまい、お見苦しいことがおきます。お見苦しいだけならまだしも、想定されていない入力のために処理が不正に止まることはよくないですよね。
一番最初に引数が3つあるか?をチェックしているところと同様、渡されたものの正当性をチェックすることが必要です。これをバリデーションと呼ぶのですが、この話はまた今度させてくださいね。

もう一点、日付の部分は日時でも渡せます。

例えばこんな感じ。

php date_diff.php "2017/07/01 00:00:00" "2018/07/18 23:59:59"

これの実行結果は

2つの日付: 2017/07/01 00:00:00, 2018/07/18 23:59:59
差は? 382.99998842593日

では、中途半端な時間ではどうでしょう?

php date_diff.php "2017/07/01 11:00:00" "2018/07/18 09:00:00"
2つの日付: 2017/07/01 11:00:00, 2018/07/18 09:00:00
差は? 381.91666666667日

となります。

どうでしょう?正解なのですがどうも考慮漏れのように感じます。
日数は整数で求めたい?時間が24時間に満たないときは切り上げる?切り下げる?四捨五入?
そもそも時分秒の部分は受け取ってもいい?

考慮が足りないかなって感じます。利用用途によって変わってくるので、しっかりと設計しないといけないですね。

単純な日数はこれで計算できるかな。なのでこれでよしです。
いずれ改良版を書きたいと思います。

読んでくださってありがとうございます。

ではまた!