PHP中的日期相關函數(二) https://www.php.net/manual/zh/class.datetimeimmutable.php

上回文章中我們介紹了三個時間日期相關的對象,不過它們的出鏡頻率並不是特別地高。今天學習的對象雖說可能不少人使用過,但是它的出鏡頻率也是非常低的。它們其實就是我們非常常用的那些面向過程的日期函數的面向對象式的封裝。但,酒香不怕巷子深,好東西還是值得我們去深入的學習研究的,當然更好的情況是可以在面對不同的業務場景時靈活地使用這些對象纔是我們學習的根本目的。

DateTime 對象

沒錯,今天我們學習的就是 DateTime 對象。從名字就可以看出,它就是一個標準的日期時間類。

$date = new DateTime('now', new DateTimeZone('Asia/Tokyo'));
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-09-29 09:47:57+09:00

$date = new DateTime();
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-09-29 10:22:45+08:00

我們可以爲它指定時間,指定時區。在第一行的測試代碼中,我們指定了時間爲 now ,也就是當前時間,這裏還可以傳遞字符串的時間格式給這個參數。第二個參數就是指定時區,我們傳遞了日本的區域時區,所以它的 P 格式化後輸入的就是 +9:00 ,也就是東九區,比我們的北京時間東八區早 1 個小時。DateTime 實例化時不傳遞任何參數的話,默認情況就是當前的時間以及 php.ini 中指定的時區。

還可以通過其它的方式來創建 DateTime 對象。

$date = DateTime::createFromFormat('Y年m月j日 H時i分s秒', '2020年09月22日 22時13分35秒');
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-09-22 22:13:35+08:00

$date = DateTime::createFromImmutable(new DateTimeImmutable("2020-09-22 11:45"));
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-09-22 11:45:00+08:00

createFromFormat() 靜態方法是按照指定的格式來生成 DateTime 時間對象。在這裏我們指定的格式是我們中文常用的格式,後面緊跟着具體的日期。createFromImmutable() 則是通過 DateTimeImmutable 對象來創建 DateTime 對象。

DateTime 與 DateTimeImmutable

DateTimeImmutable 是日期表示對象,它與 DateTime 基本沒什麼區別,方法、屬性都和 DateTime 是一樣的,唯一的區別就是在後面介紹的操作方法中它不會修改自身,而是返回一個新的對象。在 DateTimeImmutable 對象中也有一個靜態方法 createFromMutable() 是從 DateTime 對象創建一個 DateTimeImmutable 對象。

$di = new DateTimeImmutable("2020-09-22 11:45");
var_dump($di);
// object(DateTimeImmutable)#1 (3) {
//     ["date"]=>
//     string(26) "2020-09-22 11:45:00.000000"
//     ["timezone_type"]=>
//     int(3)
//     ["timezone"]=>
//     string(13) "Asia/Shanghai"
//   }
var_dump($di->add(new DateInterval('P3D')));
// object(DateTimeImmutable)#4 (3) {
//     ["date"]=>
//     string(26) "2020-09-25 11:45:00.000000"
//     ["timezone_type"]=>
//     int(3)
//     ["timezone"]=>
//     string(13) "Asia/Shanghai"
//   }

$date = new DateTime("2020-09-22 11:45");
var_dump($date);
// object(DateTime)#4 (3) {
//     ["date"]=>
//     string(26) "2020-09-22 11:45:00.000000"
//     ["timezone_type"]=>
//     int(3)
//     ["timezone"]=>
//     string(13) "Asia/Shanghai"
//   }
var_dump($date->add(new DateInterval('P3D')));
// object(DateTime)#4 (3) {
//     ["date"]=>
//     string(26) "2020-09-25 11:45:00.000000"
//     ["timezone_type"]=>
//     int(3)
//     ["timezone"]=>
//     string(13) "Asia/Shanghai"
//   }

從上面的測試代碼就可以看出 DateTimeImmutable 在使用 add() 方法之後返回的對象是一個新的對象,object(DateTimeImmutable)#1 (3) 變成了 object(DateTimeImmutable)#4 (3) 。而 DateTime 則是在自身進行的修改,對象標識符並沒有發生改變。

DateTime 操作

上文中 add() 方法就是增加日期的方法,它需要一個 DateInterval 時間間隔對象作爲參數,然後就會給對應的日期增加指定的時間間隔。

$date->add(new DateInterval('P3D'));
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-09-29 09:22:45+08:00

這裏我們就是爲當前的時間增加了3天,關於 DateInterval 對象的內容可以查閱上篇文章中的介紹。當然,除了增加之外,還有減少以及修改的方法。

$date->sub(new DateInterval('P3D'));
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-10-02 09:22:45+08:00

$date->modify('+5 day');
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-10-04 09:22:45+08:00

$date->modify('-4 day -4 hours');
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-09-30 05:22:45+08:00

sub() 方法就是給一個時間對象減少指定的時間間隔,而 modify() 方法就是根據參數來直接修改日期,比如我們這裏測試了增加5天和減少4天4小時的操作。


$origin = new DateTime('now');
$target = new DateTime('2020-09-11');
$interval = $origin->diff($target);
echo $interval->format('%a days'), PHP_EOL;
echo $interval->format('%R%a days'), PHP_EOL;
// 18 days
// -18 days

diff() 方法就是返回兩個日期之間的差值,相信這個方法不少人使用過它的面向過程的函數,也就是 date_diff() 函數,相對於其它方法來說,它的出鏡率就非常高了。%R 返回的是符號位,如果是負號就是比指定的日期少了多少時間間隔。

設置日期時間

除了操作日期時間之外,我們在實例化 DateTime 對象之後,也可以爲它重新指定日期。

$date = new DateTime();
$date->setDate(2020, 9, 25);
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-09-25 09:22:45+08:00

$date->setISODate(2020, 9, 25);
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-03-19 09:22:45+08:00

$date->setTime(14, 55);
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-10-03 14:55:00+08:00

$date->setDate(2020, 9, 33);
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-10-03 09:22:45+08:00

$date->setTime(14, 63);
echo $date->format('Y-m-d H:i:sP'), PHP_EOL;
// 2020-10-03 15:03:00+08:00

setDate() 方法就是指定日期,setTime() 方法是指定時間,它們是分開的兩個方法哦。setISODate() 設置的是 ISO 標準時間,這又是另一套日期時間規範了,感興趣的朋友可以自行查閱下相關的知識,這裏就不多做贅述了。如果我們設置的日期不是一個正常的日期格式,比如我們在測試代碼中設置了 9月33號 這個日期,那麼它會自動向後延,輸出的結果就是 10月3號 這個日期,包括 setTime() 方法也是可以這樣順延的。其實所有日期相關的對象、方法、函數都有這樣的能力。

另外,我們還可以通過時間戳進行 DateTime 對象的日期時間設置。同理,時區也是可以單獨設置的。

$date->setTimestamp(time()-84400);
echo $date->format('U = Y-m-d H:i:s'), PHP_EOL;
// 1601258165 = 2020-09-28 09:56:05

$date->setTimezone(new DateTimeZone('Asia/Tokyo'));
echo $date->format('U = Y-m-d H:i:s'), PHP_EOL;
// 1601258165 = 2020-09-28 10:56:05

獲取屬性及錯誤信息

既然 DateTime 對象有這麼多設置的東西,那麼相對應的它也有一些屬性是可以讓我們獲取的。

echo $date->getOffset(), PHP_EOL;
// 32400

echo $date->getTimestamp(), PHP_EOL;
// 1601258070

var_dump($date->getTimezone());
// object(DateTimeZone)#6 (2) {
//     ["timezone_type"]=>
//     int(3)
//     ["timezone"]=>
//     string(10) "Asia/Tokyo"
//   }

getOffset() 方法就是獲取得我們與標準時區的差值,也就是對應的北京相差 8 個小時的信息,這個在之前的文章中與 DateTimeZone 對象的同名方法的作用是類似的。getTimestamp() 和 getTimezone() 方法相信也不用多解釋了,一個是返回當前 DateTime 對象對應的時間戳,一個是返回一個時區對象。

最後,我們再來看看 DateTime() 對象的錯誤處理。DateTime 對象其實也是可以用過程化的方式來寫的,所以它提供了一個 getLastErrors() 方法,不過我們在使用面向對象的方式時,DateTime 對象會以異常的形式進行拋出。

$date = date_create('asdfasdf');
print_r(DateTime::getLastErrors());
// Array
// (
//     [warning_count] => 1
//     [warnings] => Array
//         (
//             [6] => Double timezone specification
//         )

//     [error_count] => 1
//     [errors] => Array
//         (
//             [0] => The timezone could not be found in the database
//         )

// )

try {
    $date = new DateTime('asdfasdf');
} catch (Exception $e) {
    echo $e->getMessage(), PHP_EOL;
}
// DateTime::__construct(): Failed to parse time string (asdfasdf) at position 0 (a): The timezone could not be found in the database

第一段代碼就是以面向過程的函數方式來創建的一個 DateTime 對象,它不會拋出異常,這樣我們就可以通過 getLastErrors() 方法獲得錯誤信息。但是現在還是更推薦以面向對象的方式來操作 DateTime ,所以我們應該儘量使用第二段代碼的方式來處理錯誤信息。

總結

怎麼樣,DateTime 對象的是不是很有意思?思考一下,我們日常的很多日期操作是不是也可以通過它來實現了。關於 DateTimeImmutable 的內容就不會再單獨講解了,大家可以自己查閱一下相關的資料,因爲內容其實都是和 DateTime 一樣的,唯一的區別在上文中也已經說明了。

測試代碼:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/13.PHP中的日期相關函數(二).php

參考文檔:

https://www.php.net/manual/zh/class.datetime.php

https://www.php.net/manual/zh/class.datetimeimmutable.php

各自媒體平臺均可搜索【硬核項目經理】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章