php 學習筆記之關於時區的那點事

雪之夢技術驛站發表於2019-05-30

科普一下什麼是時區

眾所周知,地球繞著太陽轉的同時也會自轉,因此同一時刻不同地區所接收到太陽照射的情況不同,所以有的地區是日出,有的地區是日落,還有的地區可能是黑夜.

既然地球上的不同地區時間不同,那總要有統一的時間刻度才能方便文化科技交流吧,不然大家說的都是當地時間,這樣豈不是亂套了?

有問題就要解決問題,不同地區時間不同就要統一時間標準,而統一時間標準的前提就是要弄清楚全球的時間差異到底在哪以及各地的當地時間如何互相轉換.

原來的時間標準是格林尼治標準時間,隨著精確計時的發展需要,已被新的時間標準所取代,目前的時間標準是世界協調時.

現在有了統一的時間標準,不同地區的時間就可以統一換算成世界協調時再轉換成當地時間了,再也不會出現同一時刻不同時間了!

示例:

  • 北京時間(UTC+8) : 2019-05-30 13:30:00
  • 世界時間(UTC) : 2019-05-30 05:30:00
  • 東部時間(UTC-5) : 2019-05-30 00:30:00

格林尼治標準時間

格林尼治標準時間(又稱格林威治平均時間格林威治標準時間,英文是GreenwichMeanTime,簡稱GMT ),格林尼治標準時間的正午是指當太陽橫穿格林尼治子午線時(也就是在格林尼治時)的時間.

格林尼治是英國倫敦的一個小鎮,是地理經度的起點,本初子午線所在的經度是零度經度,所在的時區是零時區.

我們知道一天共有 24 小時,對應著全球 24 個時區,而地球自西向東自轉,零時區後依次是東一區到東十一區,然後是東十二區.緊接著是西十二區,西十一區到西一區,最後又回到零時區.

其中東十二區和西十二區是同一個時區,又被稱為東西十二區.

總的來說,時區分為東十二區和西十二區以及零時區,其中東西十二區是同一個時區,因此共有 24 個時區.

php-timezone-method-gmt-geo.jpg

示例:

由於北京位於東八區,比零時區多個 8 個時區,意味著北京時間比格林標準時間 8 個小時.

所以,北京時間中午 12 點整的時候,格林尼治才清早 4 點鐘,估計還在睡覺呢! ( GMT+8 就是北京時間)

格林尼治標準時間與地球自轉有關,不能滿足精確計時的需求,因此不再作為標準時間,取而代之的是協調世界時.

協調世界時

協調世界時(又稱世界統一時間世界標準時間國際協調時間,英文是Coordinated Universal Time,簡稱UTC ),協調世界時是以原子時秒長為基礎,在時刻上儘量接近於格林尼治標準時間的一種時間計量系統.

不需要精確到秒的情況下, GMTUTC 基本一致,但 UTC 是以更加精確的原子時為基礎,因此常用於科學計算領域,也是目前時間計量的統一標準.

示例:

北京時間 12:00 ,換算成 GMTUTC 時間都是 04:00 ( UTC+8 也是北京時間)

北京時間

北京時間(又稱中國標準時間),是首都北京所在的時區作為中國的標準時間,比格林尼治標準時間快8小時.

我國幅員遼闊,從西到東橫跨東五,東六,東七,東八和東九等五個時區.所以全國統一採用首都北京所在的東八時區的區時作為標準時間,也就是北京時間.

時區資訊資料庫

時區資訊資料庫,又稱 Olson資料庫,是一個主要應用於電腦程式以及作業系統的可協作編輯世界時區資訊的資料庫.

時區資訊資料庫採用按“區域/位置”命名規範,方便應用於計算機世界,其中英文地名中的空格用下劃線“_”代替,連詞符“-”只在英文地名本身包含時使用.

示例:

  • Asia/Hong_Kong : 亞洲/香港
  • Asia/Macau : 亞洲/澳門
  • Asia/Shanghai : 亞洲/上海
  • Asia/Taipei : 亞洲/臺北
  • Asia/Urumqi : 亞洲/烏魯木齊

上述時區主要是 php 中所支援的中國時區,參考 亞洲所支援的時區列表

關於時區的程式設計實現

時區不僅僅是現實生活的問題,計算機程式設計世界也有時間,自然也離不開時區的概念.

在計算機世界中,一切都是資料,最好時區的概念也能體現在相關資料庫中,幸運的是已經有前輩為我們提供了時區資訊資料庫,而各類語言基本都會提供時區的工具類.

php 中的日期時間函式庫php 內建函式庫,我們可以方便地操作時間,設定時區等.

正常情況下, date 擴充套件預設是啟用的,我們可以輸入 phpinfo 列印出 php 的基本資訊,然後搜尋關鍵字 date 就可以找到關於 date 擴充套件的相關資訊.

  • 示例
<?php
// 獲取預設時區
echo "預設時區: ".ini_get("date.timezone")."<br/>";

// 獲取當前時區
echo "當前時區: ".date_default_timezone_get()."<br/>";

// 當前時間
echo "當前時間: ".date("Y-m-d H:i:s")."<br>";

// 列印 php 資訊
phpinfo();
?>
  • 結果

預設時區:
當前時區: UTC
當前時間: 2019-05-30 05:30:00

選項
date/time support(日期時間支援情況) enabled(已啟用)
timelib version(時間庫版本) 2016.05(2016.05)
"Olson" Timezone Database Version(Olson 時區資料庫版本) 2018.5(2018.5)
Timezone Database(時區資料庫) internal(內部的)
Default timezone(預設時區) UTC(協調世界時)

由此可見,假設不設定時區的話,預設時區是協調世界時,該時區和北京時間相比慢 8 個小時!

設定時區的三種姿勢

翻閱 php 開發文件中可以找到目前所有支援時區列表,下面整理出關於中國的主要時區.

  • Asia/Hong_Kong : 亞洲/香港
  • Asia/Macau : 亞洲/澳門
  • Asia/Shanghai : 亞洲/上海
  • Asia/Taipei : 亞洲/臺北
  • Asia/Urumqi : 亞洲/烏魯木齊

常用時區是上海,並沒有北京,當然也可以設定成 PRC (中華人民共和國)!

如果沒有設定時區的話,預設時區應該是協調世界時(UTC),雖說是通用的時間標準,但轉換成當地時間還是需要一定換算的,而且看起來也不太舒服.

所以最好還是修改一下時區的設定項,如果業務不考慮國際化需求,那麼永久性把時區固定就可以了,如果有國際化的業務場景,那麼最好能夠動態設定時區,這樣就能清楚知道當地時間了.

因此,下面主要提供兩種方式來設定時區,分別是靜態設定和動態設定,其中動態設定又提供了兩種方法.

靜態修改 php 配置

php 的配置檔案預設位於 : /private/etc/php.ini ,開啟檔案後修改 date.timezone 選項.

由於這種方法是直接修改配置檔案,因此時區設定後適用於所有指令碼,只不過需要重啟伺服器方可生效.

  • 示例
[Date]
; Defines the default timezone used by the date functions
; http://php.net/date.timezone
;date.timezone =

; http://php.net/date.default-latitude
;date.default_latitude = 31.7667

; http://php.net/date.default-longitude
;date.default_longitude = 35.2333

; http://php.net/date.sunrise-zenith
;date.sunrise_zenith = 90.583333

; http://php.net/date.sunset-zenith
;date.sunset_zenith = 90.583333
  • 結果
# 去掉;並設定時區,取值可以是PRC,也可以是Asia/Shanghai等時區
date.timezone = PRC

詳情請參考: http://php.net/date.timezone

動態設定 php 配置

ini_set 支援設定當前指令碼的預設時區選項.

靜態設定時區僅僅適合時區固定的情況,如果需要動態切換時區,修改配置檔案就不能滿足這種情況了.

因此,php 中還提供了動態修改 php.ini 配置檔案的方法,ini_set() 方法剛好支援動態設定時區.

不用重啟伺服器,但僅僅針對當前指令碼生效,其中 ini_set 方法支援的 php.ini 配置選項列表

  • 示例
// 設定當前時區
ini_set("date.timezone", "Asia/Tokyo");

// 獲取預設時區
echo "當前時區: ".ini_get("date.timezone")."<br/>";

// 當前時間
echo "當前時間: ".date("Y-m-d H:i:s")."<br>";
  • 結果

當前時區: Asia/Tokyo
當前時間: 2019-05-30 14:30:00

動態設定 php 時區

date_default_timezone_set 方法用於設定當前指令碼的預設時區.

ini_set 雖然支援設定時區選項,但畢竟不是專業設定時區的方法,date_default_timezone_set 才是專門設定時區的方法.

這兩個方法都屬於動態設定時區,也都是針對當前指令碼生效,也都不用重啟伺服器就能立馬生效.

  • 示例
// 獲取當前時區
echo "當前時區: ".date_default_timezone_get()."<br/>";

// 設定當前時區
date_default_timezone_set("UTC");

// 獲取當前時區
echo "當前時區: ".date_default_timezone_get()."<br/>";

// 當前時間
echo "當前時間: ".date("Y-m-d H:i:s")."<br>";
  • 結果

當前時區: Asia/Tokyo
當前時區: UTC
當前時間: 2019-05-30 05:30:00

關於時區的一些總結

時區和時間密切相關,統一時間說的其實是統一時間的標準,這樣一個地區的當地時間就可以輕易轉換成另一個地區的當地時間了.

目前世界上統一的時間標準是協調時間時(UTC),中國的時間標準是北京時間,北京時間比協調時間時快 8 個小時.

現實世界的時區也要反映到計算機世界,其中時區資訊資料庫就是用於表示現實世界的時區概念.

由此可見,時區是一個通用概念,不僅 php 有時區,javajs 等語言也有時區概念,可以說只要有時間的地方都離不開時區.

關於時區的小技能,你 get 到了嗎?

  • 美劇<>當地時間是星期二晚上八點開播,請問北京時間何時開播?
  • 英劇<>北京時間凌晨四點半開播,請問當地時間是何時開播?
  • 泰劇<>當地時間是晚上九點二十開播,請問北京時間是何時?

參考資料

相關文章