PHPで日付(日時)差の計算(日数、週数、月数、年数)
必要になる機会が発生したので、「エイヤー!」ではありますが作りました。
ググってみましたが、同様の記事が無さそうだったので、せっかくなので晒します。
とはいえ、まだまだ若輩者のプログラマーが作成したルーチンです。
自分自身、速度的・論理的無駄を内包しかねない事を認識しています。
なので、ご指摘・ご教授大歓迎です。お気づきあれば、ぜひ一言よろしくお願いいたします。
ルーチンの説明
- 「開始日」x「終了日」の差を算出するルーチンです。
入力値は、「開始日」 < 「終了日」 となることを想定しています。開始日=2009/6/15, 終了日=2009/6/16 はOK開始日=2009/6/17, 終了日=2009/6/16 はNG
- 指定した単位に基づいて差を返します。
- 月を指定した場合、差の月数
- 日を指定した場合、差の日数
- デフォルトは日数です。
- 指定した単位に満たない場合は、0を返します。
- 例えば、2008/4/1 と 2009/3/30 との差の年数を求めた場合、0となります。
考え方・実装にあたって
- 日数、週数
- うるう年を考慮するのが面倒だったので、タイムスタンプの差から算出
- 月数、年数
- 年、月、日を個別に比較し、差を算出
PHPのソース
<?php define('TERM_UNIT_YEAR', 'year'); define('TERM_UNIT_MONTH', 'month'); define('TERM_UNIT_WEEK', 'week'); define('TERM_UNIT_DAY', 'day'); define('TIMESTAMP_UNIT_DAY', 24 * 60 * 60); /** * Calculation date distance between two date. * * @param string $dateStart Date of start point. * @param string $dateEnd Date of end point. * @param string $termUnit Unit string of terms (ex. day, month...) * @return integer Distance between twon date depend on assigned term unit. */ function _calcDateDistance($dateStart, $dateEnd, $termUnit = null) { // Check args if (empty($dateStart) || empty($dateEnd)) { return false; } // Change to timestamp $timestampStart = strtotime($dateStart); $timestampEnd = strtotime($dateEnd); // Check & Compare dates if (empty($timestampStart) || empty($timestampEnd)) { return false; } else { if ($timestampStart > $timestampEnd) { $tmpTimestamp = $timestampStart; $timestampStart = $timestampEnd; $timestampEnd = $tmpTimestamp; } } // Set vars $timestampDistance = $timestampEnd - $timestampStart; $datesStart = getdate($timestampStart); $datesEnd = getdate($timestampEnd); // Calc distance $distance = 0; switch ($termUnit) { case TERM_UNIT_YEAR: case TERM_UNIT_MONTH: // Set vars $lessThanTerm = false; $distanceYear = $datesEnd['year'] - $datesStart['year']; $distanceMonth = $datesEnd['mon'] - $datesStart['mon']; $distanceDay = $datesEnd['mday'] - $datesStart['mday']; // Check day & moving down if ($distanceDay < 0) { if ($distanceMonth > 0) { $distanceMonth = $distanceMonth - 1; } else { if ($distanceYear > 0) { $distanceYear = $distanceYear - 1; $distanceMonth = $distanceMonth + 12 - 1; } else { $lessThanTerm = true; } } } // Check month & moving down if ($distanceMonth < 0) { if ($distanceYear > 0) { $distanceYear = $distanceYear - 1; $distanceMonth = $distanceMonth + 12; } else { $lessThanTerm = true; } } // Check year //if ($distanceYear < 0) {} // Check calc result & sum result. switch ($termUnit) { case TERM_UNIT_YEAR: if ($lessThanTerm) { $distance = 0; } else { $distance = abs($distanceYear); } break; case TERM_UNIT_MONTH: if ($lessThanTerm) { $distance += abs($distanceMonth); } else { // Sum year & month if (!empty($distanceYear)) { $distance += abs($distanceYear) * 12; } if (!empty($distanceMonth)) { $distance += abs($distanceMonth); } } break; } break; case TERM_UNIT_WEEK: $distance = $timestampDistance / (TIMESTAMP_UNIT_DAY * 7); $distance = abs(floor($distance)); break; case TERM_UNIT_DAY: default: $distance = $timestampDistance / TIMESTAMP_UNIT_DAY; $distance = abs(floor($distance)); break; } return $distance; } ?>
実行サンプル
<?php echo _calcDateDistance('2009-6-17', '2009-6-18', TERM_UNIT_DAY); 1 echo _calcDateDistance('2008-6-17', '2009-6-17', TERM_UNIT_DAY); 365 echo _calcDateDistance('2009-6-17', '2009-6-18', TERM_UNIT_WEEK); 0 echo _calcDateDistance('2008-6-17', '2009-6-17', TERM_UNIT_WEEK); 52 echo _calcDateDistance('2008-6-17', '2009-6-16', TERM_UNIT_MONTH); 11 echo _calcDateDistance('2008-6-17', '2009-6-17', TERM_UNIT_MONTH); 12 echo _calcDateDistance('2008-6-17', '2009-6-16', TERM_UNIT_YEAR); 0 echo _calcDateDistance('2008-6-17', '2009-6-17', TERM_UNIT_YEAR); 1 ?>
日時の差は「??年?月?日」です。的な答えがほしい場合は
次の形で出来ると想像してます。(未検証)
1) 年の差分を計算
2) (1)の答え分を引数$dateStartに反映して、再帰的に呼ぶ
3) (2)の答え分を引数$dateStartに反映して、再帰的に呼ぶ
4) (1)と(2)と(3)の答えを合体
以上です。
更新履歴
- 2009/06/22
- 「開始日」 < 「終了日」というアホな仕様を取り除きました。最初からこうしとけば良かった。。。