php设置时区-Postgresql数据库时区(timezone)设置

timestamp和timestamptz都占用8个字节。 存储时间时没有本质区别,都不携带时区信息。 只是insert保存数据和select返回数据给数据库客户端时的处理方式不同。

下面通过一个具体的例子来解释这两种数据类型的区别,以及它们与数据库连接时区(会话对应的时区)和postgresql数据库时区的关系。 以下示例中使用的数据库时区为Etc/UTC(GMT+0),先创建表,然后执行相应操作:

test_db=> CREATE TABLE test_table (id SERIAL NOT NULL PRIMARY KEY,lable TEXT NOT NULL,
timestamp_col TIMESTAMPTZ NOT NULL,timestamptz_col TIMESTAMPTZ NOT NULL);
CREATE TABLE
test_db=> insert into test_table(lable, timestamp_col, timestamptz_col) values ('haha', 
'2022-04-13 01:15:55','2022-04-13 01:15:55');
INSERT 0 1
test_db=> select * from test_table;
 id | lable |    timestamp_col    |    timestamptz_col     
----+-------+---------------------+------------------------
  1 | haha  | 2022-04-13 01:15:55 | 2022-04-13 01:15:55+00
(1 row)
注:因为当前session时区和数据库时区都是Etc/UTC,所以数据库保存的时间,timestamp_col
和timestamptz_col都是一样的。select显示结果也是一样的。
test_db=> show timezone;
 TimeZone 
----------
 Etc/UTC
(1 row)
test_db=> SET TIMEZONE='Asia/Shanghai';
SET
test_db=> show timezone;
   TimeZone    
---------------
 Asia/Shanghai
(1 row)
test_db=> insert into test_table(lable, timestamp_col, timestamptz_col) values ('hello',
 '2022-04-13 01:15:55','2022-04-13 01:15:55');
INSERT 0 1
test_db=> select * from test_table;
 id | lable |    timestamp_col    |    timestamptz_col     
----+-------+---------------------+------------------------
  1 | haha  | 2022-04-13 01:15:55 | 2022-04-13 09:15:55+08
  2 | hello | 2022-04-13 01:15:55 | 2022-04-13 01:15:55+08
(2 rows)
注:因为当前session时区是Asia/Shanghai, 而数据库时区都是Etc/UTC,所以数据库保存的时间,timesttamp_col保存
的时间是2022-04-13 01:15:55,而timestamptz_col保存的时间是2022-04-12 17:15:55。当执行selects时,timestamp
类型字段不做任何转换,而timestamptz类型的字段,需要转换成当前session对应的时区的时间,所以针对第二行看起来
timesttamp_col和timestamptz_col的结果还是一样的,而第一行,结果就不一样了。
test_db=> SET TIMEZONE='Asia/Tokyo';
SET
test_db=> show timezone;
  TimeZone  
------------
 Asia/Tokyo
(1 row)
test_db=> select * from test_table;
 id | lable |    timestamp_col    |    timestamptz_col     
----+-------+---------------------+------------------------
  1 | haha  | 2022-04-13 01:15:55 | 2022-04-13 10:15:55+09
  2 | hello | 2022-04-13 01:15:55 | 2022-04-13 02:15:55+09
(2 rows)
注:因为当前session时区是Asia/Tokyo(GMT+9), 而数据库时区都是Etc/UTC,当执行selects时,
timestamp类型字段不做任何转换,而timestamptz类型的字段,需要转换成当前session对应的时区的时间,
所以看起来timesttamp_col和timestamptz_col的结果还是一样的。

从上面的输出可以看出,随着数据库连接的时区变化,相同的数据显示有所不同。 对于timestamptz_col列,它会随着数据库链接会话对应的时区的变化而变化。 timestamp_col列没有改变,但数据库中存储的原始数据原封不动地返回给数据库连接客户端。

在插入(保存)数据时,无论是timestamp还是timestamptz,都不会保存时区信息,这就是为什么这两类数据占用8个字节,而且保存的时间精度也是一样的。 而对于timestamp_col数组来说,只是将插入语句的时间原封不动的保存在数据库中,选择的时候原封不动的返回,不用考虑时区转换的问题。 还有timestamptz,插入的时候会转换为数据库对应的时区的时间,选择的时候会转换为session对应的时区的时间。

由于我们上面设置的时区是针对当前数据库链接(所谓的会话)的,所以当创建新的链接时php设置时区,我们之前设置的与上一个链接对应的会话信息将会丢失。

$ psql -h localhost -U test_user -p 6432 -d test_db;
Password for user test_user: 
psql (14.2, server 14.1 (Debian 14.1-1.pgdg110+1))
Type "help" for help.
test_db=> select * from test_table;
 id | lable |    timestamp_col    |    timestamptz_col     
----+-------+---------------------+------------------------
  1 | haha  | 2022-04-13 01:15:55 | 2022-04-13 01:15:55+00
  2 | hello | 2022-04-13 01:15:55 | 2022-04-12 17:15:55+00
(2 rows)
test_db=> show timezone;
 TimeZone 
----------
 Etc/UTC
(1 row)

如上图,创建新链接后,当前会话所在链接改回数据库默认时区。

时区设置中国是什么_php设置时区_时区设置+8

如果要更改数据库的时区而不是会话的时区,则需要更改 postgresql.conf 文件,

Find postgresql.conf file.
# find / -name postgresql.conf
  /var/lib/pgsql/12/data/postgresql.conf
Change timezone in the postgresql.conf file
# vi /var/lib/pgsql/12/data/postgresql.conf
  ...
  log_timezone = 'Asia/Shanghai'
  ...
  timezone = 'Asia/Shanghai'
  
  :wq

请注意php设置时区,不同版本的 postgresql 可能有不同的配置文件路径。 进行更改后,您需要重新启动。

总结:

1.timestamp和timestamptz数据似乎都没有保存时​​区信息,而timestamptz结合数据库设置的时区、session对应的时区以及timestamptz本身保存的数据,返回正确的时间给客户端。 也就是说,从宏观上看,timestamptz确实看起来像是保存时区信息的时间戳数据,但这个时区是整个数据库设置的时区。

2.什么时候使用timestamptz类型,什么时候使用timestamp?

简单来说,对于简单的应用程序,只有单个客户端(单个应用程序)或多个同类型的应用程序(例如多个微服务)访问数据库。 如果客户端应用程序保证数据库中保存的时间能够保证时区的正确性,那么可以使用时间戳。 因为此时,无论数据库的时区是Etc/UTC还是‘Asia/上海’,数据库都不会处理客户端传来的数据,而只是原封不动地保存下来。 选择时,原样返回。 对于应用程序的客户端,例如新闻网页应用的客户端是浏览器。 如果想要根据浏览器所在地区的时区正确显示从数据库返回的时间,这就需要新闻Web应用程序做转换,或者及时与时区信息一起返回给浏览器客户端,客户端进行时间转换。

而如果有多个不同类型的客户端需要访问同一个数据库,此时就可以考虑使用timestamptz,这样无论你是哪一个客户端,都可以根据当前的时区正确获取对应的时间会议。

以上只是我个人的理解,可能有不准确的地方,敬请谅解。

最后需要说明的是,对于整个数据库的时区设置,我个人感觉影响不大。 唯一的好处就是使用postgresql命令行客户端psql连接数据库时,将会话的默认时区设置为与整个数据库的时区一致,其他影响并不大。 因为如果你使用的是DBeaver这样的图形化数据库客户端工具,默认情况下它会帮你将会话的时区设置为DBeaver当前所在主机的时区,这样在使用的时候就完全没有问题了。显示timestamptz类型的数据。