2016-03-15 115 views
1

我處於棘手的情況。客戶端的數據庫時區是爲America/Chicago而不是UTC配置的。Postgresql:將日期字符串'2016-01-01 00:00:00'轉換爲具有特定時區的日期時間

從應用程序中,我們要求客戶輸入有用的日期,可悲的是這些日期是'原樣'存儲的,所以如果他們在文本輸入中輸入'2001-01-01 00:00:00',那相同的值將被存儲在數據庫中,而我們忽略了客戶的時區。我們單獨保存該信息。

表格列是TIMEZONETZ類型。所以Postgresql會在最後添加America/Chicago時區偏移量:例如'2001-01-01 00:00:00-02'。當然,大多數顧客並不在芝加哥。

困難的部分是,即使知道客戶的時區,假定日期時間在將其存儲到數據庫之前沒有正確預處理,對數據庫運行真的很難。

我的嘗試解決方案是找到一種方法從列值中提取日期時間字符串,並將其重新轉換爲具有正確時區的日期。例如,(僞代碼):

// This is psuedo code 
SELECT DATETIME((SELECT date_string(mycolumn) FROM mytable), 
TIMEZONE('America/Managua')); 

Which would be equivalent in PHP: 
$customerInput = '2016-01-01 00:00:00'; 
$format = 'Y-m-d H:i:s'; 
$wrongDateStoredInDb = DateTime::createFromFormat($format, $customerInput, new DateTimezone('America/Chicago')); 

// In order to fix that date, I'd extract the dateString and create a new DateTime but passing the correct timezone info. 

$customerTimezone = new Timezone('America/Bogota'); 
$customerInput = $wrongDateStoredInDb->format($format); // Assuming we didn't have it already. 
$actualDateTime = DateTime::createFromFormat($format, $customerInput, $customerTimezone); 

有了這方面的信息,我可以運行在日期範圍計算,以正確的值,例如:

// Pseudo-code 
SELECT * FROM myTable WHERE fix_date_time(columnWithInvalidDate, `correctTimezone`)::timestamp > `sometimestamp`; 

我讀過Postgresql文檔,我盡我所能,但似乎沒有任何工作。

任何建議都比歡迎!

回答

0

所以你說你有一個timestamptz列。這不是作爲一個字符串存儲的,而是作爲從時代起數微秒的「即時」。但是,當你做一個INSERT並給出一個字符串時,Postgres會在你存儲它之前將你的字符串自動轉換爲一個時間值。假設你給它的字符串在芝加哥時間,因爲這是默認的時區。

現在您想要將這些時間重新解釋爲在用戶的時區中。要做到這一點,你可以將它們放回字符串(芝加哥時間),然後再解析它們,但是使用不同的時區。

假設你有數據是這樣的:

CREATE TABLE t (id int primary key, ts timestamptz, tz text); 

SET TIMEZONE='America/Chicago'; 
INSERT INTO t 
VALUES 
(1, '2015-01-01 12:00:00', 'America/Managua'), 
(2, '2015-01-01 12:00:00', 'America/Los_Angeles') 
; 

那麼這會給你新的時代是用戶真正的意思是:

SET TIMEZONE='America/Chicago'; 
SELECT ts::text::timestamp AT TIME ZONE tz FROM t; 

進行分解:ts::text stringifies值成芝加哥時間,然後我們重新解析它,但進入一個沒有時區信息的光禿禿的timestamp。然後我們附上一個時區---不是芝加哥時間,而是用戶自己的時區。

從這裏你應該能夠處理修復壞行(而不是新的,如果你已經改變了服務器的默認時區)。

一個警告是,如果用戶輸入時間,然後改變他們的時區,沒有辦法恢復,所以這將錯誤地解釋舊時間。

+0

哦,夥計。謝謝一堆。我希望我能給你一瓶啤酒:D出於某種原因,我曾嘗試過你前幾天提出的建議,但我錯過了解釋輸出。順便說一句,::文本修飾符似乎並不需要。沒有它我會得到同樣的結果。無論如何,我的問題解決了,謝謝! –

相關問題