Часовой пояс в postgeSQL - PullRequest
1 голос
/ 09 июля 2020

Я использую postge SQL 12.3. Часовой пояс по умолчанию - «US / Pacifi c». Когда я использую функцию Now(), postgres правильно возвращает текущее время и дату, но с часовым поясом, отличным от моего. Я изменил часовой пояс на «Африка / Каир» с помощью команды

SET TIMEZONE = 'Africa/Cairo';

После этого я снова вызвал функцию Now(). Он вернул неправильную дату и время, но с правильным часовым поясом. Как я могу исправить эту ошибку ?. Я хочу, чтобы новое время (время после изменения часового пояса) было таким же, как старое время (время до изменения часового пояса). Другими словами, я хочу изменить часовой пояс только с -7 на +02. Что мне делать?

Вот результат до изменения часового пояса

enter image description here

This is the output after changing the time zone to 'Africa/Cairo'

введите описание изображения здесь

Ответы [ 3 ]

1 голос
/ 10 июля 2020

Я нахожусь в «US / Pacifi c», поэтому:

select now();
              now               
--------------------------------
 07/09/2020 17:23:19.817048 PDT

test(5432)=> SET TIMEZONE = 'Africa/Cairo';
SET

test(5432)=> select now();
              now               
--------------------------------
 07/10/2020 02:24:02.617442 EET
(1 row)

test(5432)=> select now() at time zone  'US/Pacific';
          timezone          
----------------------------
 07/09/2020 17:24:21.577493
(1 row)


ОБНОВЛЕНИЕ. Пример временной метки, timestamptz:

ts_test 
                        Table "public.ts_test"
 Column |            Type             | Collation | Nullable | Default 
--------+-----------------------------+-----------+----------+---------
 ts_tz  | timestamp with time zone    |           |          | 
 ts     | timestamp without time zone |           |          | 
 ts_txt | character varying           |           |          | 

show timezone;
  TimeZone  
------------
 US/Pacific

test(5432)=# insert into ts_test values(localtimestamp, localtimestamp, localtimestamp);
INSERT 0 1
test(5432)=# select * from ts_test ;
             ts_tz              |             ts             |           ts_txt           
--------------------------------+----------------------------+----------------------------
 07/09/2020 17:57:26.005347 PDT | 07/09/2020 17:57:26.005347 | 07/09/2020 17:57:26.005347

test(5432)=# SET TIMEZONE = 'Africa/Cairo';
SET
test(5432)=# insert into ts_test values(localtimestamp, localtimestamp, localtimestamp);
INSERT 0 1
test(5432)=# select * from ts_test ;
             ts_tz              |             ts             |           ts_txt           
--------------------------------+----------------------------+----------------------------
 07/10/2020 02:57:26.005347 EET | 07/09/2020 17:57:26.005347 | 07/09/2020 17:57:26.005347
 07/10/2020 02:57:44.661465 EET | 07/10/2020 02:57:44.661465 | 07/10/2020 02:57:44.661465
(2 rows)

test(5432)=# insert into ts_test values('07/09/2020 5:45', '07/09/2020 5:45', '07/09/2020 5:45');
INSERT 0 1
test(5432)=# select * from ts_test ;
             ts_tz              |             ts             |           ts_txt           
--------------------------------+----------------------------+----------------------------
 07/10/2020 02:57:26.005347 EET | 07/09/2020 17:57:26.005347 | 07/09/2020 17:57:26.005347
 07/10/2020 02:57:44.661465 EET | 07/10/2020 02:57:44.661465 | 07/10/2020 02:57:44.661465
 07/09/2020 05:45:00 EET        | 07/09/2020 05:45:00        | 07/09/2020 5:45

test(5432)=# SET TIMEZONE = default;
SET
test(5432)=# show timezone;
  TimeZone  
------------
 US/Pacific
(1 row)

test(5432)=# insert into ts_test values('07/09/2020 5:45', '07/09/2020 5:45', '07/09/2020 5:45');
INSERT 0 1
test(5432)=# select * from ts_test ;
             ts_tz              |             ts             |           ts_txt           
--------------------------------+----------------------------+----------------------------
 07/09/2020 17:57:26.005347 PDT | 07/09/2020 17:57:26.005347 | 07/09/2020 17:57:26.005347
 07/09/2020 17:57:44.661465 PDT | 07/10/2020 02:57:44.661465 | 07/10/2020 02:57:44.661465
 07/08/2020 20:45:00 PDT        | 07/09/2020 05:45:00        | 07/09/2020 5:45
 07/09/2020 05:45:00 PDT        | 07/09/2020 05:45:00        | 07/09/2020 5:45
(4 rows)
0 голосов
/ 10 июля 2020

Не вдаваясь в подробности о работе часовых поясов в PostgreSQL (другие ответы при условии, что), вот решение. Вы берете местное время без часового пояса и используете AT TIME ZONE, чтобы интерпретировать его в другом часовом поясе:

SELECT localtime AT TIME ZONE 'Africa/Cairo';

Результат, конечно же, будет отображаться в соответствии с текущими настройками timezone.

0 голосов
/ 10 июля 2020

Используйте clock_timestamp() для текущего момента

now() - это традиционный PostgreSQL, эквивалентный transaction_timestamp(), который, в свою очередь, эквивалентен CURRENT_TIMESTAMP. Эти три команды возвращают момент начала транзакции. См. руководство .

Чтобы получить время начала текущего оператора, а точнее время получения последнего командного сообщения от клиента, наберите statement_timestamp().

Чтобы зафиксировать момент, когда функция выполняется, вызовите clock_timestamp().

Установка часового пояса по умолчанию

Вы можете установить часовой пояс по умолчанию одним из двух способов, как описано в здесь :

  • SQL -стандарт: SET TIME ZONE 'Africa/Cairo' ;
  • Postgres -specifi c: УСТАНОВИТЬ часовой пояс TO 'Africa / Cairo';

Пример

Вот скриншот, показывающий три вещи:

  • Текущий момент, как видно в UT C на веб-сайте Time.is.
  • Запрос, показывающий текущий часовой пояс по умолчанию и текущий момент.
  • Запрос (мгновение спустя, когда я переключил windows), показывающий изменение текущего часового пояса по умолчанию, а также запрос для текущей зоны и текущего момента.

Для этой демонстрации я использовал службу управляемой базы данных от DigitalOcea n.com для Postgres 12.

screenshot of Time.is web site showing current moment in UTC, a SQL query showing current default time zone and current moment, and another SQL query changing default time zone, then showing current default time zone and current moment

We can see in this shot that the current moment in UTC is 2:30 AM. The west coast time in US is 7:30 PM the prior day, seven hours behind UTC. The current default time zone in the first session is UTC (GMT), showing a correct time of 2:30 AM, in agreement with Time.is web site. The second session we switch to Africa/Cairo time zone, to find the current moment seen through that time zone is 4:30 AM, two hours ahead of UTC.

All this makes sense, and seems correct to me.

Based on other's comments, I suspect the system clock of your host computer is incorrect. I wonder if the time zone on the server is set to one time zone, but the actually time-of-day is set to the current time of a different time zone. This would only happen if manually set by a sysadmin, I expect, as the host OS should auto-correct if set to check a time server.

To verify this, I suggest you do something similar to what I did, to verify the database server’s clock:

  1. Open a browser window for Time.is, selecting UTC.
  2. Set current default time zone to UTC: SET TIME ZONE 'GMT' ;.
  3. Query database for current default time zone and the current moment. Use clock_timestamp rather than a transaction-start function like now to avoid confusion with a long-running txn.

➥If Time.is does not agree with your result from clock_timestamp, then we know your server time is set incorrectly.

Take a screenshot, post with your Question.

Tips:

  • Learn to think, work, log, and debug in UT C. Забудьте о своем ограниченном часовом поясе на работе. Думайте о UT C как о Едином Истинном Времени, а все остальные зоны - всего лишь вариации.
  • Как правило, лучше всего настроить ваши серверы на UT C (смещение нуля часов-минут-секунд).
  • Я рекомендую настроить ваши серверы так, чтобы они проверяли с помощью сервера времени автокоррекцию их часов, если у вас есть доступ к надежным серверам времени.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...