PostgreSQL 時間 timestamp & timestampTz
Categories:
欄位比較
類型 | 儲存空間 | 最小值 | 最大值 | 描述 |
---|---|---|---|---|
timestamp | 8 bytes | 4713 BC | 294276 AD | 沒有時區資料 |
timestampTz | 8 bytes | 4713 BC | 294276 AD | 含有時區資料 |
新增資料
在新增時間資料的時候,需要將該時間時區資料儲存進去,而不是單純儲存整個 Carbon 物件
或是 Y-m-d H:i:s
,應該至少要儲存 Y-m-d H:i:sP
,加入時區的資訊,這樣在撈取資料時,就可以使用指定時區的資料去做撈取
類型 | 儲存資料 |
---|---|
Carbon 物件 | 2020-12-25 14:31:00 |
時間格式 Y-m-d H:i:s | 2020-12-25 14:31:00 |
時間格式 Y-m-d H:i:sP | 2020-12-25 14:31:00+08:00 |
// 轉換資料為 Carbon 物件
$TimeAtCarbon = Carbon::parse($time_at);
// 設定新增資料庫資料格式
$timezone_data = [
'time_at_timezone' => $TimeAtCarbon->format('Y-m-d H:i:sP'),
];
// 新增資料
TimezoneTest::create($timezone_data);
若要用可讀性比較高的程式的話可以用 $TimeAtCarbon->toDateTimeString()
取得時間,用 $TimeAtCarbon->getTimezone()->toOffsetTimeZone()
取得時區
// 轉換資料為 Carbon 物件
$TimeAtCarbon = Carbon::parse($time_at);
// 設定新增資料庫資料格式
$timezone_data = [
'time_at_timezone' => $TimeAtCarbon->toDateTimeString() . $TimeAtCarbon->getTimezone()->toOffsetTimeZone(),
];
// 新增資料
TimezoneTest::create($timezone_data);
時間儲存至 PostgreSQL 預設會是 GMT+0
的時間,所以若是 2020-12-30 14:31:00+08:00
的時間,在儲存進去後會存成 2020-12-30 06:31:00+00:00
撈取資料
資料庫儲存 timestampTz
的時間預設是用 GMT+0
的時間,所以如果要撈取正確時間區間的資料,時間欄位務必要帶入 時區資訊
,否則會預設使用 GMT+0
的時間撈取資料
撈取資料的時間單位只要有指定正確的時區後,這樣就不管是要用哪個時區撈資料,都可以撈到正確的資料
所以 2020-12-30 14:31:00+08:00
與 2020-12-30 06:31:00+00:00
都可以撈取到相同的資料
// 時間設定
$time_start_at = '2020-12-30 14:31:00+08:00'; // 2020-12-30 06:31:00+00:00
$time_end_at = '2021-01-01 14:31:00+08:00'; // 2021-01-01 06:31:00+00:00
// 轉換時間成 Carbon 物件
$TimeStartAtCarbon = Carbon::parse($time_start_at);
$TimeEndAtCarbon = Carbon::parse($time_end_at);
// 設定時間區間包含時區
// 2020-12-30 14:31:00+08:00
$time_start_at_timezone = $TimeStartAtCarbon->toDateTimeString() . $TimeStartAtCarbon->getTimezone()->toOffsetTimeZone();
// 2020-01-01 14:31:00+08:00
$time_end_at_timezone = $TimeEndAtCarbon->toDateTimeString() . $TimeEndAtCarbon->getTimezone()->toOffsetTimeZone();
// select * from "timezone_test" where "time_at_timezone" >= '2020-12-30 14:31:00+08:00' and "time_at_timezone" <= '2020-01-01 14:31:00+08:00'
$TimezoneTestCollection = TimezoneTest::where('time_at_timezone', '>=', $time_start_at_timezone)
->where('time_at_timezone', '<=', $time_end_at_timezone)
->get();
Carbon 強制轉換時區
在使用 Carbon 的 setTimezone('UTC')
或 utc()
將時間轉換成 UTC 時間,在 Linux 系統如果有改成 Asia/Taipei
時轉換會出錯,無法正確的轉回去 UTC
原本 +0 的時間
// 轉換成 UTC 時間
$CarbonTime->setTimezone('UTC');
$CarbonTime->utc();
所以在轉換的時候建議用 setTimezone('GMT+0')
,直接指定時區 + 多少,這樣出來的時間就會是對的
$CarbonTime->setTimezone('GMT+0');
將 timestamp 時間的資料儲存至 timestampTz
儲存到 timestamp 的資料皆不會包含時區資訊,時區必須由程式或系統判斷
所以將 timestampTz
的 2020-12-25 14:31:00+08:00
資料儲存至 timestamp
,僅會儲存 2020-12-25 14:31:00
不包含時區資料,所以若程式或系統的時區是什麼,就會把時間視為是那個時區的時間
類型 | 儲存資料 |
---|---|
timestampTz | 2020-12-25 14:31:00+08:00 |
timestamp | 2020-12-25 14:31:00 |
timestampTz 優點
- 抓取資料可以使用指定時區的範圍去抓取
- 台北時間 2020-12-25 14:31:00+08:00
- 曼谷時間 2020-12-25 14:31:00+07:00
- 時間時區不需要特別綁定在程式系統上
- 使用沒有時區的 timestamp 時,在變更系統或程式的時區會是一個災難
- 顯示資料仍然可以顯示為對的時區資料
參考資料
- Understanding PostgreSQL Timestamp Data Types
- 8.5. 日期時間型別 - PostgreSQL 正體中文使用手冊
- Time zone list / Epoch to time zone converter
- PHP: DateTime::format - Manual
- Carbon, Postgres timestamp with timezone and Dates
- Laravel - What’s the difference between timestamp() and timestampTz()? - Stack Overflow
- Time zone list / Epoch to time zone converter
- Carbon - A simple PHP API extension for DateTime.