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.