PHP 的 date 函式轉換超過 2038 年的日期出錯問題解決 - Warning: date() expects parameter 2 to be integer


問題描述

先看一段原始碼:

<?php
$int_timestamp = 2147483648  ; //從資料庫取出的 Unix 時間戳數字資料
echo date("Y-m-d H:i:s", $int_timestamp);

結果出現錯誤:
Warning: date() expects parameter 2 to be integer, float given in C:\google\webgolds\time.php on line 3


此問題主要為 Y2K38 漏洞,也被稱為 Unix Millennium Bug。
此漏洞將會影響到所有 32 位元系統下用UNIX時間戳整數來記錄時間的 PHP 及其它編程語言。一個整型的變量所能保存的最大時間為 2038年01月19日 03:14:07 。超過這個時間後,整型數值將會溢出。
若你的 PHP程式是運作在 64 位元的伺服器將不受此影響。

讓我們看看 PHP 官網是如何描述 date function 的。
string date ( string $format [, int $timestamp = time() ] )
 

判斷你目前運作的 PHP 電腦環境是 32 位元還是 64 位元

如果你執行以下代碼:
<?php
echo PHP_INT_MAX;

得到的值若是 2147483647 (32 位元),則表示你系統有 2038 問題。

如果 PHP_INT_MAX 回傳的值是:
  • 2147483647,表示 PHP 是運作在 32 位元版本電腦
  • 9223372036854775807,表示 PHP 是運作在 64 位元版本電腦
 
 

解決方式

方式一

將運作 PHP 程式碼的伺服器更換系統為 64 位元。可以永久解決問題。

方式二


PHP 5.2 版本之後提供了一個函數 DateTime 可以解決一下問題。

通過以下 DateTime 類來操作日期不會受到 Y2K38 漏洞的影響,最大將可支持到 9999 年 12 月 31 日,對於多數系統已經夠用。

<?php
// DateTime 範例
date_default_timezone_set('Asia/Taipei');//設置台灣時區

// 1.試著把 2099/12/31 超大的日期轉成時間戳
$obj = new DateTime("2099-12-31 23:59:59");
echo $obj->format("U"); // 輸出:4102415999

// 2.把時間戳轉換成日期格式
//$obj = new DateTime('@4102415999' ); 
$obj = new DateTime('@' . $obj->format("U") );
//$timezone = timezone_open('Asia/Taipei'); // 設置webgolds時區 for Taipei (Taiwan)
//$obj->setTimezone($timezone);
echo $obj->format("Y-m-d H:i:s"); //輸出 2099-12-31 15:59:59

// 3.把日期格式轉換成日期格式
$obj = new DateTime("2099-12-31 15:59:59");
echo $obj->format("Y/m/d H:i:s"); //輸出一樣的 2099-12-31 15:59:59
注意時間戳前面要多一個@符號

使用 DateTime 取代原生 Date 函式 #

<?php
//2017/11/16

date_default_timezone_set('Asia/Taipei');
/*
 取代原生 date 函式,將時間戳轉換成日期格式
 string newdate ( string $format [, int $timestamp, string $timezone ] )
*/
function newDate($_format = 'Y-m-d H:i:s', $_timestamp = 0, $_timezone = 'Asia/Taipei'){
    $timezone = timezone_open($_timezone); // 設置webgolds時區 for Taipei (Taiwan)
    $obj = new DateTime('@' . (float)$_timestamp );
    $obj->setTimezone($timezone);
    return $obj->format($_format);
}

使用方式:
// 使用方式
$int_timestamp = 4102415999  ; // 從資料庫取出的 Unix 時間戳數字資料
echo newDate("Y-m-d H:i:s", $int_timestamp);
 

常見時間戳與實際日期

timestamp 值 轉換後日期
0 1970-01-01 08:00:00
100 1970-01-01 08:01:40
1510369871 2017-11-11 11:11:11
2147483647 2038-01-19 11:14:07
2147483648 2038-01-19 11:14:08
4102415999 2099-12-31 23:59:59
253402271999 9999-12-31 23:59:59
253402272000 10000-01-01 00:00:00
timestamp 轉 date YMD格式
 

相關 PHP 函式

strtotime()


[php + mysql] 如何儲存時間? 到底要用 int 還是 DATETIME / TIMESTAMP

 

回上一頁

相關文章:

喜歡這篇文章嗎?立即分享

Posted : / Views: 327
Last updated :2017-11-19