在任何編程語言中處理日期和時間通常是一項簡單瑣碎的任務,直到需要支持時區。幸運的是,PHP擁有一套強大的日期/時間工具,可以幫助您處理各種時間相關問題:Unix時間戳、格式化日期以供人類閱讀、顯示帶有時區的日期、計算現在到下個月第二個星期二之間的時間差等等。本文將介紹PHP的時間函數(time()
、mktime()
和date()
)及其面向對像對應項的基礎知識,然後了解MySQL日期,並向您展示如何使它們與PHP完美配合。
主要收穫
time()
、mktime()
和date()
,有效處理Unix時間戳和格式化日期。 DateTime
和DateTimeZone
對象進行面向對象的日期和時間操作,包括處理不同的時區。 PHP日期和時間函數
本文的大部分內容將使用Unix時間,也稱為POSIX時間或紀元時間。時間表示為自1970年1月1日午夜UTC以來經過的秒數。如果您對Unix時間的完整歷史感興趣,請查看維基百科上的Unix時間文章。 UTC(協調世界時),也稱為GMT,有時也稱為Zulu時間,是0度經線的時間。世界上所有其他時區都表示為相對於此時間的正或負偏移量。使用UTC和Unix時間處理時間,在需要處理時區時會讓您的生活更輕鬆。稍後我會詳細介紹這一點,但現在讓我們忽略時區問題,並查看一些時間函數。
獲取當前Unix時間
time()
不接受任何參數,並返回自Unix紀元以來的秒數。為了說明這一點,我將使用PHP交互式CLI shell。
<code class="language-bash">sean@beerhaus:~$ php -a php > print time(); 1324402770</code>
如果您需要Unix時間的數組表示,請使用getdate()
函數。它接受一個可選的Unix時間戳參數,但如果沒有提供,則默認為time()
的值。
<code class="language-php">php > $unixTime = time(); php > print_r(getdate($unixTime)); Array ( [seconds] => 48 [minutes] => 54 [hours] => 12 [mday] => 20 [wday] => 2 [mon] => 12 [year] => 2011 [yday] => 353 [weekday] => Tuesday [month] => December [0] => 1324403688 )</code>
格式化Unix時間
Unix時間可以輕鬆格式化為人類希望閱讀的任何字符串。 date()
用於將Unix時間戳格式化為人類可讀的字符串,並接受一個格式化參數和一個可選的時間參數。如果沒有提供可選的時間戳,則使用time()
的值。
<code class="language-bash">sean@beerhaus:~$ php -a php > print time(); 1324402770</code>
“r”格式化字符串返回由RFC 2822指定的格式化時間。當然,您可以使用其他說明符來定義您自己的自定義格式。
<code class="language-php">php > $unixTime = time(); php > print_r(getdate($unixTime)); Array ( [seconds] => 48 [minutes] => 54 [hours] => 12 [mday] => 20 [wday] => 2 [mon] => 12 [year] => 2011 [yday] => 353 [weekday] => Tuesday [month] => December [0] => 1324403688 )</code>
有關可接受的格式化字符的完整列表,請參閱PHP文檔中date()
的頁面。但是,當與mktime()
和strtotime()
函數結合使用時,該函數變得更有用,正如您將在接下來的示例中看到的。
根據給定時間創建Unix時間
mktime()
用於根據與日期的每個部分相對應的值列表(秒、分、小時、年等)創建Unix時間戳。它接受許多整數參數,以以下順序設置日期的每個部分:
<code class="language-php">php > print date("r", $unixTime); Tue, 20 Dec 2011 12:54:48 -0500</code>
如果啟用了夏令時,則將isDST
設置為1;如果沒有啟用,則設置為0;如果未知,則設置為-1(默認值)。
<code class="language-php">php > print date("m/d/y h:i:s a", $unixTime); 12/20/11 12:54:48 pm php > print date("m/d/y h:i:s a"); 12/20/11 01:12:11 pm php > print date("jS of F Y", $unixTime); 20th of December 2011</code>
您可以看到,在處理使用用戶自定義日期範圍的數據庫查詢時,mktime()
非常有用。例如,如果您在MySQL中將時間戳存儲為整數(Unix時間)(預示著任何人嗎?),則很容易設置一個常見的年至今查詢範圍。
<code>mktime(hour, minute, second, month, day, year, isDST)</code>
將英文日期解析為Unix時間
幾乎神奇的函數strtotime()
將日期/時間格式的字符串作為其第一個參數,以及用作轉換基礎的Unix時間戳。請參閱文檔以了解可接受的日期格式。
<code class="language-php">php > print date("r", mktime(12, 0, 0, 1, 20, 1987)); Tue, 20 Jan 1987 12:00:00 -0500 php > print date("r", mktime(0, 0, 0, date("n"), date("j"), date("Y"))); Tue, 20 Dec 2011 00:00:00 -0500 php > print date("r", mktime(23, 59, 59, date("n"), date("j"), date("Y"))); Tue, 20 Dec 2011 23:59:59 -0500</code>
PHP的DateTime和DateTimeZone對象
PHP的DateTime
對像是處理日期和時區的面向對象方法。構造方法接受時間的字符串表示,非常類似於上面的strtotime()
,有些人可能會覺得這更容易使用。如果沒有提供參數,則默認值為“now”。
<code class="language-php"><?php $startTime = mktime(0, 0, 0, 1, 1, date("y")); $endTime = mktime(0, 0, 0, date("m"), date("d"), date("y"));</code>
DateTime
的format()
方法與上面的date()
函數的工作方式相同,並接受所有相同的格式化字符。 DateTime
對像還帶有一些有用的常量,可以將其饋送到format()
方法。
<code class="language-php">php > print strtotime("now"); 1324407707 php > print date("r", strtotime("now")); Tue, 20 Dec 2011 14:01:51 -0500 php > print strtotime("+1 week"); 1325012569 php > print date("r", strtotime("+1 week")); Tue, 27 Dec 2011 14:03:03 -0500 php > print date("r", strtotime("next month")); Fri, 20 Jan 2012 14:04:20 -0500 php > print date("r", strtotime("next month", mktime(0, 0, 0))); Fri, 20 Jan 2012 00:00:00 -0500 php > print date("r", strtotime("next month", mktime(0, 0, 0, 1, 31))); Thu, 03 Mar 2011 00:00:00 -0500</code>
可以在DateTime
文檔頁面上找到完整的常量列表。由於我們很快就會處理時區,讓我們為PHP提供一個默認時區。在您的php.ini配置文件(我有一個用於CLI,一個用於Apache)中,找到如下所示的部分:
<code class="language-php">php > $dt = new DateTime("now"); php > print $dt->format("r"); Tue, 20 Dec 2011 16:28:32 -0500 php > $dt = new DateTime("December 31 1999 12:12:12 EST"); php > print $dt->format("r"); Fri, 31 Dec 1999 12:12:12 -0500</code>
當沒有為date.timezone
賦予值時,PHP將盡力確定在服務器上設置的系統時區。您可以使用date_default_timezone_get()
檢查PHP正在使用哪個值。
<code class="language-bash">sean@beerhaus:~$ php -a php > print time(); 1324402770</code>
讓我們將服務器的時區設置為UTC時間(date.timezone = UTC
)並保存配置文件。您必須重新啟動Apache或CLI shell才能查看更改。 PHP DateTime
對象包括一個內部DateTimeZone
類實例來跟踪時區。當您創建DateTime
的新實例時,內部DateTimeZone
應設置為在php.ini中提供的默認值。
<code class="language-php">php > $unixTime = time(); php > print_r(getdate($unixTime)); Array ( [seconds] => 48 [minutes] => 54 [hours] => 12 [mday] => 20 [wday] => 2 [mon] => 12 [year] => 2011 [yday] => 353 [weekday] => Tuesday [month] => December [0] => 1324403688 )</code>
可以在時區文檔頁面上找到可接受的時區名稱的完整列表。您現在可以看到當兩個DateTime
對像被賦予不同的時區時,時間差異。例如,這是一個將UTC轉換為America/New_York(EST)時間的示例。
<code class="language-php">php > print date("r", $unixTime); Tue, 20 Dec 2011 12:54:48 -0500</code>
請注意12月份的-0500偏移量。如果您將時間值更改為夏季日期,例如7月1日,您會發現它知道夏令時(EDT)。
<code class="language-php">php > print date("m/d/y h:i:s a", $unixTime); 12/20/11 12:54:48 pm php > print date("m/d/y h:i:s a"); 12/20/11 01:12:11 pm php > print date("jS of F Y", $unixTime); 20th of December 2011</code>
將日期與MySQL和PHP一起使用
如果您在任何級別使用過MySQL,您可能已經註意到開箱即用的DATETIME類型。它看起來和聞起來像一個日期,如果您說它是一個日期,那麼您是對的。但是,一旦您將其從MySQL中SELECT到PHP中,您實際上擁有的只是一個看起來像日期的字符串。它沒有時區意識,並且在人類需要查看它之前就已經格式化好供人類使用了。 是的,我知道MySQL有很多日期格式化函數,但我們也已經在使用PHP了,正如您所看到的,PHP在處理日期格式方面非常出色。為什麼我們還要從數據庫中直接格式化它呢?我們可能需要應用一些不同的轉換和格式。最好只在人類即將看到日期時才格式化日期。
<code>mktime(hour, minute, second, month, day, year, isDST)</code>
運行這個簡單的腳本,您可以看到您從DATETIME字段獲得的只是一個格式化的字符串,沒有時區信息。
<code class="language-php">php > print date("r", mktime(12, 0, 0, 1, 20, 1987)); Tue, 20 Jan 1987 12:00:00 -0500 php > print date("r", mktime(0, 0, 0, date("n"), date("j"), date("Y"))); Tue, 20 Dec 2011 00:00:00 -0500 php > print date("r", mktime(23, 59, 59, date("n"), date("j"), date("Y"))); Tue, 20 Dec 2011 23:59:59 -0500</code>
DATETIME值是運行MySQL的服務器的本地時間,無論該服務器的時區是什麼。如果您所做的所有事情都只涉及一個時區中的一個服務器,那麼DATETIME可能適合您的大部分需求,而且我非常羨慕您。那麼,如何使用PHP和MySQL處理日期和時區呢?將日期存儲為Unix時間戳。您已經知道Unix時間是自1970年1月1日UTC以來的秒數,因此這為您提供了一個恆定的時區,並且您可能已經註意到PHP的許多日期/時間函數都是基於Unix時間戳的。在使用MySQL時,我通常創建將日期存儲為INTEGER UNSIGNED的表列。插入日期時,您可以使用PHP的time()
或MySQL的UNIX_TIMESTAMP()
。
<code class="language-php"><?php $startTime = mktime(0, 0, 0, 1, 1, date("y")); $endTime = mktime(0, 0, 0, date("m"), date("d"), date("y"));</code>
如果您希望MySQL格式化日期,您可以這樣做。但是時間將位於運行MySQL的服務器的時區中,我建議您在到達Web應用程序的模板/視圖級別並準備好讓人眼看到它之前,不要進行任何類型的格式化。
<code class="language-bash">sean@beerhaus:~$ php -a php > print time(); 1324402770</code>
在任何跨越時區的應用程序中,您通常都會有一個表來跟踪用戶的自定義時區設置,然後將其讀入$_SESSION
值。假設您有一個如下所示的會話條目:
<code class="language-php">php > $unixTime = time(); php > print_r(getdate($unixTime)); Array ( [seconds] => 48 [minutes] => 54 [hours] => 12 [mday] => 20 [wday] => 2 [mon] => 12 [year] => 2011 [yday] => 353 [weekday] => Tuesday [month] => December [0] => 1324403688 )</code>
您可以輕鬆地將存儲的Unix時間(以UTC為單位)轉換為特定用戶的時區中的任何日期。
<code class="language-php">php > print date("r", $unixTime); Tue, 20 Dec 2011 12:54:48 -0500</code>
這將導致日期“Mon, 16 Jan 2012 12:03:49 -0600”。 -0600告訴您它比UTC落後6小時,UTC的偏移量為0。如果我們將時區設置為America/Los_Angeles,則生成的日期將是:
<code class="language-php">php > print date("m/d/y h:i:s a", $unixTime); 12/20/11 12:54:48 pm php > print date("m/d/y h:i:s a"); 12/20/11 01:12:11 pm php > print date("jS of F Y", $unixTime); 20th of December 2011</code>
而America/New_York將產生:
<code>mktime(hour, minute, second, month, day, year, isDST)</code>
總結
處理日期和時區是許多程序員日常生活中的一部分,但是當您可以使用PHP強大且易於使用的日期庫時,無需擔心。您已經了解瞭如何獲取Unix時間戳、如何將日期格式化為任何可以想像的格式、如何將日期的英文表示解析為時間戳、如何將一段時間添加到時間戳以及如何在時區之間進行轉換。如果本文有兩個主要要點,那就是1)堅持使用Unix時間,以及2)在使用PHP和MySQL時,堅持使用UTC作為所有日期的基礎時區。基於UTC的所有時間的想法不僅適用於PHP和MySQL;它在任何語言中都被認為是最佳實踐。如果您發現自己正在使用其他語言工作,那麼您很有可能會對自己說:“該死的,他們為什麼不能像PHP那樣做?”
圖片來自Yakobchuk Vasyl / Shutterstock
(此處應添加關於在PHP中處理日期和時間的常見問題的FAQ部分,類似於輸入文本中的FAQ部分。 由於篇幅限制,我沒有在此處添加。)
以上是在PHP和MySQL中與日期和時間合作的詳細內容。更多資訊請關注PHP中文網其他相關文章!