Be aware that your default timezone can sometimes alter the result of a diff so that the returned months/days are incorrect.
There is a bug report at: http://bugs.php.net/bug.php?id=52480
DateInterval::format
(PHP 5 >= 5.3.0)
DateInterval::format — 間隔をフォーマットする
説明
public string DateInterval::format
( string $format
)
間隔をフォーマットします。
パラメータ
- format
-
次の文字を、 format パラメータ文字列に使用することができます。 フォーマット文字は、パーセント記号 (%) で始めなければなりません。 format 文字 説明 値の例 % リテラルとしての % % Y 年、数値、先頭に 0 を含む 2 桁 01, 03 y 年、数値 1, 3 M 月、数値、先頭に 0 を含む 2 桁 01, 03, 12 m 月、数値 1, 3, 12 D 日、数値、先頭に 0 を含む 2 桁 01, 03, 31 d 日、数値 1, 3, 31 a 総日数 4, 18, 8123 H 時間、数値、先頭に 0 を含む 2 桁 01, 03, 23 h 時間、数値 1, 3, 23 I 分、数値、先頭に 0 を含む 2 桁 01, 03, 59 i 分、数値 1, 3, 59 S 秒、数値、先頭に 0 を含む 2 桁 01, 03, 57 s 秒、数値 1, 3, 57 R 負の値の場合は "-"、正の値の場合は "+" -, + r 負の値の場合は "-"、正の値の場合は空文字 -,
返り値
フォーマットされた間隔を返します。
注意
注意:
DateInterval::format() メソッドは、 時刻文字列や日付セグメントでの繰り越しを再計算しません。 これは意図的な仕様です。なぜなら "32 days" のようにオーバーフローした値は "1 month and 4 days" から "1 month and 1 day" までのどれとでも解釈可能だからです。
例
例1 DateInterval の例
<?php
$interval = new DateInterval('P2Y4DT6H8M');
echo $interval->format('%d days');
?>
上の例の出力は以下となります。
4 days
例2 DateInterval での繰り越しの例
<?php
$interval = new DateInterval('P32D');
echo $interval->format('%d days');
?>
上の例の出力は以下となります。
32 days
例3 DateInterval および DateTime::diff() での修飾子 %a および %d
<?php
$january = new DateTime('2010-01-01');
$february = new DateTime('2010-02-01');
$interval = $february->diff($january);
// %a は総日数を出力します
echo $interval->format('%a total days')."\n";
// 一方 %d は、月数に含まれない日数のみを出力します
echo $interval->format('%m month, %d days');
?>
上の例の出力は以下となります。
31 total days 1 month, 0 days
balaclark at gmail dot com
01-Jun-2011 09:58
pekka at gmx dot de
12-Feb-2011 08:20
Note that `%a` is broken on Windows on VC6 builds. http://bugs.php.net/bug.php?id=51184
kuzb
04-Feb-2011 10:15
Quick class to allow you to input a time in any unit, and have it recalculate in to different denominations (for example, seconds to hours, minutes and seconds):
<?php
class DateIntervalEnhanced extends DateInterval
{
/* Keep in mind that a year is seen in this class as 365 days, and a month is seen as 30 days.
It is not possible to calculate how many days are in a given year or month without a point of
reference in time.*/
public function to_seconds()
{
return ($this->y * 365 * 24 * 60 * 60) +
($this->m * 30 * 24 * 60 * 60) +
($this->d * 24 * 60 * 60) +
($this->h * 60 *60) +
$this->s;
}
public function recalculate()
{
$seconds = $this->to_seconds();
$this->y = floor($seconds/60/60/24/365);
$seconds -= $this->y * 31536000;
$this->m = floor($seconds/60/60/24/30);
$seconds -= $this->m * 2592000;
$this->d = floor($seconds/60/60/24);
$seconds -= $this->d * 86400;
$this->h = floor($seconds/60/60);
$seconds -= $this->h * 3600;
$this->i = floor($seconds/60);
$seconds -= $this->i * 60;
$this->s = $seconds;
}
}
// Example usage
$di = new DateIntervalEnhanced('PT3600S');
$di->recalculate();
// outputs 1:0:0 instead of 0:0:3600 now!
echo $di->format('%H:%i:%s');
?>
baptiste dot place at utopiaweb dot fr
15-Mar-2010 01:47
With php 5.3, DateTime is sweet !
Here is one quick example :
<?php
/**
* A sweet interval formatting, will use the two biggest interval parts.
* On small intervals, you get minutes and seconds.
* On big intervals, you get months and days.
* Only the two biggest parts are used.
*
* @param DateTime $start
* @param DateTime|null $end
* @return string
*/
public function formatDateDiff($start, $end=null) {
if(!($start instanceof DateTime)) {
$start = new DateTime($start);
}
if($end === null) {
$end = new DateTime();
}
if(!($end instanceof DateTime)) {
$end = new DateTime($start);
}
$interval = $end->diff($start);
$doPlural = function($nb,$str){return $nb>1?$str.'s':$str;}; // adds plurals
$format = array();
if($interval->y !== 0) {
$format[] = "%y ".$doPlural($interval->y, "year");
}
if($interval->m !== 0) {
$format[] = "%m ".$doPlural($interval->m, "month");
}
if($interval->d !== 0) {
$format[] = "%d ".$doPlural($interval->d, "day");
}
if($interval->h !== 0) {
$format[] = "%h ".$doPlural($interval->h, "hour");
}
if($interval->i !== 0) {
$format[] = "%i ".$doPlural($interval->i, "minute");
}
if($interval->s !== 0) {
if(!count($format)) {
return "less than a minute ago";
} else {
$format[] = "%s ".$doPlural($interval->s, "second");
}
}
// We use the two biggest parts
if(count($format) > 1) {
$format = array_shift($format)." and ".array_shift($format);
} else {
$format = array_pop($format);
}
// Prepend 'since ' or whatever you like
return $interval->format($format);
}
?>
