《現代 PHP》學習筆記(十五):日期、時間及時區

前言

本文為《現代 PHP》一書的學習筆記。

環境

  • Windows 10
  • Wnmp 3.1.0

日期、時間和時區

處理日期和時間相關的問題是件棘手的事情,需要考量到日期格式、時區、日光節約時間、閏年和不同天數的月份。幸好,使用 PHP 5.2.0 中實作的 DateTimeDateIntervalDateTimeZone 類別,可以準確地建立和調整日期、時間和時區。

設定初始時區

如果沒有宣告初始時區,PHP 會顯示 E_WARNING 訊息。有兩種方式可以設定時區:

  1. php.ini 檔中設定。
1
date.timezone = 'America/New_York';
  1. 在執行時期使用 date_default_timezone_set() 宣告初始時區。

範例 5-9:設定初始時區

1
date_default_timezone_set('America/New_York');
  • 完整的 PHP 時區辨識碼列表,可以在 PHP Manual 找到。

DateTime 類別

DateTime 類別提供了物件導向介面來管理日期和時間。

範例 5-10:DateTime 類別

1
$datetime = new DateTime();

不使用參數的情況下,DateTime 類別建立了一個代表當前日期和時間的實體,可以傳入特定的字串參數到 DateTime 類別建構式,指定需要的日期和時間。

範例 5-11:帶有參數的 DateTime 類別

1
$datetime = new DateTime('2014-04-27 5:03 AM');

使用 DateTimeFromFormat() 靜態方法可以使用自訂格式的時間和日期建立 DateTime 實體。

範例 5-12:帶有靜態建構式的 DateTime 類別。

1
$datetime = DateTime::createFromFormat('M j, Y H:i:s', 'Jan 2, 2014 23:04:12');

DateInterval 類別

DateInterval 實體代表固定長度的時間(例如「兩天」)或相對長度的時間(例如「昨天」),DateInterval 實體可以修改 DateTime 實體。

區間規範是一個以 P 為開頭的字串,並接上一個整數,最後接上一個週期代號(period designator)修飾前一個整數,並以字母 T 分隔日期和時間部分,有效的週期代號為:

  • Y(年)
  • M(月)
  • D(日)
  • W(週)
  • H(時)
  • M(分)
  • S(秒)

例如週期代號 P2D 代表兩天、P2DT5H2M 代表兩天五時又兩分。

以下例子利用 add() 方法修改 DateTime 實體。

範例 5-13:DateInterval 類別

1
2
3
4
5
6
7
8
date_default_timezone_set('America/New_York');

$datetime = new DateTime('2014-01-01 14:00:00');
$interval = new DateInterval('P2W');

$datetime->add($interval);

echo $datetime->format('Y-m-d H:i:s');

也可以建立一個相反的 DateInterval 實體,用相反的順序走訪 DatePeriod 實體。

範例 5-14:相反的 DateInterval 類別

1
2
3
4
5
6
7
8
9
date_default_timezone_set('America/New_York');

$dateStart = new \DateTime();
$dateInterval = \DateInterval::createFromDateString('-1 day');
$datePeriod = new \DatePeriod($dateStart, $dateInterval, 3);

foreach ($datePeriod as $date) {
echo $date->format('Y-m-d'), PHP_EOL;
}

DateTimeZone 類別

傳入一個有效的時區辨識碼到 DateTimeZone 類別建構式。

1
$timezone = new DateTimeZone('America/New_York');

DateTime 實體建構式的第二個參數就是 DateTimeZone,如果忽略第二個參數,時區會被設定為初始時區。

1
2
$timezone = new DateTimeZone('America/New_York');
$datetime = new \DateTime('2014-08-20', $timezone);

也可以使用 setTimezone() 方法來改變 DateTime 實體的時區。

範例 5-15:DateTimeZone 類別

1
2
3
4
5
date_default_timezone_set('America/New_York');

$timezone = new DateTimeZone('America/New_York');
$datetime = new \DateTime('2014-08-20', $timezone);
$datetime->setTimezone(new DateTimeZone('Asia/Hong_Kong'));

DatePeriod 類別

有時候需要以固定的時間區間疊代一串日期時間,像是月曆中的重複事件。

DatePeriod 類別建構式需要三個參數:

  1. 第一個是 DateTime 實體,代表疊代的起始日期時間。
  2. 第二個是 DateInterval 實體,代表疊代日期時間的區間。
  3. 第三個是一個整數,代表疊代的總數。

範例 5-16:DatePeriod 類別

1
2
3
4
5
6
7
8
9
date_default_timezone_set('America/New_York');

$start = new DateTime();
$interval = new DateInterval('P2W');
$period = new DatePeriod($start, $interval, 3);

foreach ($period as $nextDateTime) {
echo $nextDateTime->format('Y-m-d H:i:s'), PHP_EOL;
}

如果想要排除疊代的初始日期,可以傳入 DatePeriod::EXCLUDE_START_DATE 常數作為最後的建構式參數。

範例 5-17:帶有自選參數的 DatePeriod 類別

1
2
3
4
5
6
7
8
9
10
11
12
13
14
date_default_timezone_set('America/New_York');

$start = new DateTime();
$interval = new DateInterval('P2W');
$period = new DatePeriod(
$start,
$interval,
3,
DatePeriod::EXCLUDE_START_DATE
);

foreach ($period as $nextDateTime) {
echo $nextDateTime->format('Y-m-d H:i:s'), PHP_EOL;
}

相關元件

Brian Besbitt 的 nesbot/carbon 元件提供簡單的使用者介面和許多好用的方法用來處理日期與時間。

參考資料

  • Josh Lockhart(2015)。現代 PHP。台北市:碁峯資訊。