PHP Conference Japan 2024

DateInterval::__construct

(PHP 5 >= 5.3.0, PHP 7, PHP 8)

DateInterval::__construct建立新的 DateInterval 物件

說明

public DateInterval::__construct(字串 $duration)

建立新的 DateInterval 物件。

參數

duration

區間規格。

格式以字母 P 開頭,代表「期間」。每個持續時間段由一個整數值加上一個期間指示符表示。如果持續時間包含時間元素,則該部分的規格前面會加上字母 T

duration 期間指示符
期間指示符 說明
Y
M
D
W 週。會轉換成天數。在 PHP 8.0.0 之前,不能與 D 結合使用。
H 小時
M 分鐘

以下是一些簡單的例子。兩天是 P2D。兩秒是 PT2S。六年五分鐘是 P6YT5M

注意事項:

單位類型必須從左邊最大刻度的單位輸入到右邊最小刻度的單位。因此,年在月之前,月在日之前,日在分鐘之前,依此類推。因此,一年零四天必須表示為 P1Y4D,而不是 P4D1Y

規格也可以表示為日期時間。一年零四天的範例為 P0001-00-04T00:00:00。但此格式中的值不能超過給定期間的滾動點(例如,25 小時無效)。

這些格式基於 » ISO 8601 持續時間規範

錯誤/例外

duration 無法解析為間隔時,會擲出 DateMalformedIntervalStringException。在 PHP 8.3 之前,這是 Exception

更新日誌

版本 說明
8.3.0 現在擲出 DateMalformedIntervalStringException 而不是 Exception
8.2.0 只有 yfinvertdays 會顯示,包含一個新的布林屬性 from_string
8.0.0 W 可以與 D 組合。

範例

範例 #1 建構和使用 DateInterval 物件

<?php
// 建立特定日期
$someDate = \DateTime::createFromFormat("Y-m-d H:i", "2022-08-25 14:18");

// 建立間隔
$interval = new \DateInterval("P7D");

// 加入間隔
$someDate->add($interval);

// 將間隔轉換為字串
echo $interval->format("%d");

以上範例將輸出


7

範例 #2 DateInterval 範例

<?php

$interval
= new DateInterval('P1W2D');
var_dump($interval);

?>

以上範例在 PHP 8.2 中的輸出

object(DateInterval)#1 (10) {
  ["y"]=>
  int(0)
  ["m"]=>
  int(0)
  ["d"]=>
  int(9)
  ["h"]=>
  int(0)
  ["i"]=>
  int(0)
  ["s"]=>
  int(0)
  ["f"]=>
  float(0)
  ["invert"]=>
  int(0)
  ["days"]=>
  bool(false)
  ["from_string"]=>
  bool(false)
}

以上範例在 PHP 8 中的輸出

object(DateInterval)#1 (16) {
  ["y"]=>
  int(0)
  ["m"]=>
  int(0)
  ["d"]=>
  int(9)
  ["h"]=>
  int(0)
  ["i"]=>
  int(0)
  ["s"]=>
  int(0)
  ["f"]=>
  float(0)
  ["weekday"]=>
  int(0)
  ["weekday_behavior"]=>
  int(0)
  ["first_last_day_of"]=>
  int(0)
  ["invert"]=>
  int(0)
  ["days"]=>
  bool(false)
  ["special_type"]=>
  int(0)
  ["special_amount"]=>
  int(0)
  ["have_weekday_relative"]=>
  int(0)
  ["have_special_relative"]=>
  int(0)
}

以上範例在 PHP 7 中的輸出

object(DateInterval)#1 (16) {
  ["y"]=>
  int(0)
  ["m"]=>
  int(0)
  ["d"]=>
  int(2)
  ["h"]=>
  int(0)
  ["i"]=>
  int(0)
  ["s"]=>
  int(0)
  ["f"]=>
  float(0)
  ["weekday"]=>
  int(0)
  ["weekday_behavior"]=>
  int(0)
  ["first_last_day_of"]=>
  int(0)
  ["invert"]=>
  int(0)
  ["days"]=>
  bool(false)
  ["special_type"]=>
  int(0)
  ["special_amount"]=>
  int(0)
  ["have_weekday_relative"]=>
  int(0)
  ["have_special_relative"]=>
  int(0)
}

另請參閱

新增註解

使用者貢獻的註解 14 則註解

owen at beliefs.com
11 年前
M 用於表示月份和分鐘。

如參考的 ISO 6801 維基百科頁面所述 http://en.wikipedia.org/wiki/Iso8601#Durations

為了解決歧義,「P1M」是一個月的期間,而「PT1M」是一分鐘的期間(請注意時間值前面的時間指示符 T)。

使用:PHP 5.3.2-1ubuntu4.19

// 3 個月
$dateTime = new DateTime;echo $dateTime->format( DateTime::ISO8601 ), PHP_EOL;
$dateTime->add(new DateInterval("P3M"));
echo $dateTime->format( DateTime::ISO8601 ), PHP_EOL;
結果為
2013-07-11T11:12:26-0400
2013-10-11T11:12:26-0400

// 3 分鐘
$dateTime = new DateTime;echo $dateTime->format( DateTime::ISO8601 ), PHP_EOL;
$dateTime->add(new DateInterval("PT3M"));
echo $dateTime->format( DateTime::ISO8601 ), PHP_EOL;
結果為
2013-07-11T11:12:42-0400
2013-07-11T11:15:42-0400

在區間的 P 後插入 T 以新增 3 分鐘而不是 3 個月。
Hernanibus
7 年前
文件中沒有說明,但您不能直接建立負的區間,也就是說,您不能像這樣建立「-2 天」的區間

<?
$interval = new DateInterval("P-2D");//或
$interval = new DateInterval("-P2D");
?>

相反地,您必須先建立區間,然後將其「invert」屬性設定為 1,如下所示

<?
$interval = new DateInterval("P2D");
$interval->invert = 1;
?>

然後您應該記住,這個區間的作用類似於負數,因此要從給定日期減去區間,您必須「新增」它

<?
$interval = new DateInterval("P2D");
$interval->invert = 1;
$date = new DateTime ("1978-01-23 17:46:00");
$date->add($interval)->format("Y-m-d H:i:s");//結果是 "1978-01-21 17:46:00"
?>
kuzb
13 年前
應該注意的是,這個類別不會根據單一時間單位的值來計算天/小時/分鐘/秒等。例如

<?php
$di
= new DateInterval('PT3600S');
echo
$di->format('%H:%i:%s');

?>

將產生 0:0:3600 而不是預期的 1:0:0
admin at torntech dot com
9 年前
警告 - 儘管 $interval_spec 接受 ISO 8601 規格格式,但它不接受規格中所述的帶有句點或逗號的小數部分值。

https://bugs.php.net/bug.php?id=53831

<?php
/* 來自 ISO 8601 文件的範例 */
$interval = new DateInterval('P0.5Y');
?>

會導致
致命錯誤:未捕獲的例外 'Exception',訊息為 'DateInterval::__construct(): Unknown or bad format (P0.5Y)'
buvinghausen at gmail dot com
12 年前
我認為最簡單的方法是使用 DateTime 類別的 sub 方法。

<?php
$date
= new DateTime();
$date->sub(new DateInterval("P89D"));
匿名
3 年前
請注意,要新增時間,即使期間為空,也必須輸入 P。

要新增 1 小時

<?php

$plusOneHour
= (new DateTime('now'))->add(new DateInterval("PT1H"));

var_dump($plusOneHour);

?>
kevinpeno at gmail dot com
13 年前
請注意,雖然 DateInterval 物件具有 $invert 屬性,但您不能像在 XSD 中指定負值 ("-P1Y") 那樣直接向建構函式提供負值。如果您這樣做,將會收到例外。

您需要使用正區間 ("P1Y") 進行建構,然後指定 $invert 屬性 === 1。
daniellehr at gmx dot de
12 年前
或者,您可以使用 DateInterval::createFromDateString() 處理負區間

<?php
$date
= new DateTime();
$date->add(DateInterval::createFromDateString('-89 days'));
userexamplecom at mailinator dot com
8 年前
請注意,如果您有一個 DateTime 物件在 1 月 31 日,並新增一個月的 DateInterval,那麼您會在 3 月而不是 2 月。

例如
---
// 假設今天的日期是 2017-01-31
$today = new DateTime('now', $timeZoneObject);
$today->add(new DateInterval('P1M'));
echo $today->format('m');
// 輸出:03
---
jawzx01 at gmail dot com
12 年前
如前所述,要建立負的 DateInterval 物件,您可以這樣編碼

<?php
$date1
= new DateTime();
$eightynine_days_ago = new DateInterval( "P89D" );
$eightynine_days_ago->invert = 1; //使其變為負數。
$date1->add( $eightynine_days_ago );
?>

然後 $date1 現在是 89 天前。
sloanlance+php.net gmail com
6 年前
⚠️ 請務必注意先前由 "admin at torntech dot com" 在評論中提出的關於 DateInterval 的警告(https://php.dev.org.tw/manual/en/dateinterval.construct.php#116750)。重申一下:

某些版本的 PHP(例如 5.6.31)有一個錯誤,不允許在提供給 DateInterval 建構函式的 ISO 8601 持續時間字串中使用小數部分。也就是說,以下範例將會失敗:

<?php
// 'P0.5Y' 根據 ISO 8601 是有效的
$interval = new DateInterval('P0.5Y'); // 拋出例外
?>

<?php
// 'PT585.829S' 根據 ISO 8601 是有效的
$interval = new DateInterval('PT585.829S'); // 拋出例外
?>

如果這個錯誤影響到您,請前往 PHP 錯誤追蹤系統中關於此錯誤的報告,並投下您受影響的票數:https://bugs.php.net/bug.php?id=53831
lsloan-php dot net at umich dot edu
8 年前
雖然 PHP 將時間段稱為「間隔 (intervals)」,但 ISO 8601 將其稱為「持續時間 (durations)」。在 ISO 8601 中,「間隔」是不同的概念。

雖然 ISO 8601 允許持續時間所有部分都使用小數(例如「P0.5Y」),但 DateInterval 不允許。計算持續時間時請小心。如果持續時間包含小數部分,則在將其儲存到 DateInterval 物件時可能會遺失。
Ray.Paseur sometimes uses Gmail
8 年前
要恢復間隔規格字串

<?php
function get_interval_spec(DateTime $alpha, DateTime $omega)
{
$intvl = $alpha->diff($omega);

$date = NULL;
if (
$intvl->y) $date .= $intvl->y . 'Y';
if (
$intvl->m) $date .= $intvl->m . 'M';
if (
$intvl->d) $date .= $intvl->d . 'D';

$time = NULL;
if (
$intvl->h) $time .= $intvl->h . 'H';
if (
$intvl->i) $time .= $intvl->i . 'M';
if (
$intvl->s) $time .= $intvl->s . 'S';
if (
$time) $time = 'T' . $time;

$text ='P' . $date . $time;
if (
$text == 'P') return 'PT0S';
return
$text;
}
grzeniufication
4 年前
如果您想要將一個時間間隔物件儲存在資料庫中,實作 __toString() 方法會很方便。 與 serialize 的輸出相比,格式化後的時間間隔值更容易被人類讀取。 以下是一個範例:

<?php

namespace App;

class
DateInterval extends \DateInterval
{
public function
__toString()
{
return
$this->format('P%yY%mM%dDT%hH%iM%sS');
}
}

$interval1 = new DateInterval('P1Y');
$interval2 = new DateInterval(strval($interval1));
assert($interval1 == $interval2);
To Top