簡體   English   中英

需要時區調試幫助

[英]Need help for TimeZone debugging

我有一個 Ubuntu / Apache2 / PHP (Symfony2) / MySQL 日期問題。 我認為這是一個系統問題,因為我在 dev env 中沒有它,只有在 rec 和 prod envs 中。 當我發布包含日期時間的表單時,數據庫中的時間比我輸入的時間少 2 小時。 當我閱讀它時,我在屏幕上的日期時間與我在數據庫中的日期時間相同。 2 小時的差異符合我的時區(歐洲/巴黎)。

開發環境:

  • 本地機
  • Ubuntu 16.04 LTS 桌面
  • Apache/2.4.18 (Ubuntu)
  • 局域網上 Debian 8 虛擬主機上的 Mysql 5.5.43-0+deb8u1
  • PHP 7.0.8-0ubuntu0.16.04.2,Symfony 2.8.7

記錄/生產環境:

  • 都在同一台專用服務器上
  • Ubuntu 15.10 服務器
  • Apache/2.4.12
  • MySQL 5.6.28-0ubuntu0.15.10.1
  • PHP 5.6.11-1ubuntu3.1

當我在兩台機器上運行date -R時,我有一個匹配: Sat, 24 Sep 2016 19:39:53 +0200 ,多幾秒或更短,這是我輸入命令所花費的時間。

/etc/timezone在兩台機器上都包含“Europe/Paris”。

在兩台機器上,PHP 的(CGI 端)date.timezone 也是“Europe/Paris”。

在兩台機器上,SQL 查詢SELECT @@global.time_zone, @@session.time_zone; 返回“系統”和“系統”

我使用基於 moment.js 的引導日期時間選擇器來輸入這個日期和時間。 但是我通過檢查瀏覽器控制台中發布的數據將其從嫌疑人中排除,並確認日期沒有改變。

兩台機器上的應用程序代碼是相同的(相同的顛覆版本)。

你看別人要測試的東西嗎?

可能是因為這個PR 最近才合並。

嘗試改變這個

-            $dateTime = new \DateTime(sprintf('@%s', $timestamp), new \DateTimeZone($this->outputTimezone));
+            $dateTime = new \DateTime(sprintf('@%s', $timestamp));
+            // set timezone separately, as it would be ignored if set via the constructor,
+            // see http://php.net/manual/en/datetime.construct.php
+            $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));

DateTimeToLocalizedStringTransformerTest.php

看到這個

PHP 不使用系統時區。 它有自己的內部時區設置date.timezone可由 PHP 配置。 它還擁有自己依賴的內部時區數據庫,而不是您系統的/etc/timezone

您可以在 php.ini 中全局配置時區,也可以在本地代碼中配置時區(即使用date_default_timezone_set() ,使用 PHP 的時區標識符之一。例如,在DateTime構造函數中不指定時區,或在參數中不指定 GMT 偏移量傳遞給strtotime函數,PHP 使用默認配置的date.timezone設置來選擇時區。如果沒有配置,則回退到UTC

來自date_default_timezone_set()上的 PHP 手冊:

按照優先順序,此函數通過以下方式返回默認時區:

  • 使用date_default_timezone_set()函數(如果有)讀取時區設置

  • 僅在 PHP 5.4.0 之前:讀取TZ環境變量(如果非空)

  • 讀取date.timezone ini 選項的值(如果設置)

  • 僅在 PHP 5.4.0 之前:查詢主機操作系統(如果支持且 > 操作系統允許)。 這使用了一種必須猜測時區的算法。 這絕不是在每種情況下都能正常工作。 達到此階段時會顯示警告。 不要依賴它來正確猜測,而是將 date.timezone 設置為正確的時區。

如果上述方法均不成功,則date_default_timezone_get()將返回 UTC 的默認時區。

因此,由於您沒有使用 PHP < 5.4.0,PHP 將始終只查看date.timezone設置,如果未設置,則回退到UTC

以與時區無關的方式在客戶端和服務器之間傳輸時間的最佳方法是在傳輸期間僅使用 Unix 時間戳(即 UTC) 並且僅在遠程端進行轉換。 例如,將諸如time() * 1000發送到瀏覽器,並讓您的 Javascript 使用Date將其轉換為日期/時間格式,這意味着最終用戶會根據其本地時區信息看到正確的日期/時間,但無論時區如何,您的服務器仍然可以獲得正確的時間。

因此,作為一般做法,最好這樣做:

  • 將數據庫中的所有內容存儲為 UTC
  • 僅以 UTC 格式在 PHP 和數據庫之間傳輸時間戳
  • 從服務器到客戶端的 UTC 傳輸( strtotime()DateTime::getTimestamp()等...)
  • 從客戶端到服務器的 UTC 傳輸( Date.getTime()

這樣做可以確保時區之間的格式和轉換與存儲正確的時間是分開的,因為很容易將時區轉換應用於格式化的日期,然后意外忘記或將其存儲/傳輸到錯誤的時區。 這就是為什么總是以與時區無關的方式進行傳輸以防止損壞數據並且僅在該傳輸的終止端應用轉換(如果甚至有必要)。 然后 PHP 或 Javascript 可以按照他們的意願使用 Unix 時間戳,當他們需要再次相互交談時,他們可以轉換回 UTC/Unix 時間戳並發送。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM