Использование текущего времени в UTC в качестве значения по умолчанию в PostgreSQL

172

У меня есть столбец TIMESTAMP WITHOUT TIME ZONEтипа и хотел бы, чтобы по умолчанию текущее время в UTC. Узнать текущее время в UTC очень просто:

postgres=# select now() at time zone 'utc';
          timezone          
----------------------------
 2013-05-17 12:52:51.337466
(1 row)

Как использовать текущую метку времени для столбца:

postgres=# create temporary table test(id int, ts timestamp without time zone default current_timestamp);
CREATE TABLE
postgres=# insert into test values (1) returning ts;
             ts             
----------------------------
 2013-05-17 14:54:33.072725
(1 row)

Но это использует местное время. Попытка форсировать это в UTC приводит к синтаксической ошибке:

postgres=# create temporary table test(id int, ts timestamp without time zone default now() at time zone 'utc');
ERROR:  syntax error at or near "at"
LINE 1: ...int, ts timestamp without time zone default now() at time zo...
Вичерт Аккерман
источник

Ответы:

297

Функция даже не нужна. Просто поместите скобки вокруг выражения по умолчанию:

create temporary table test(
    id int, 
    ts timestamp without time zone default (now() at time zone 'utc')
);
Даниэль Верите
источник
2
Я могу видеть такую ​​функцию, как now_utc () действительно светится при написании запросов
misaxi
Это даже работает, когда время возвращается на час - now () возвращает метку времени, которая знает смещение от UTC.
Клей Ленхарт,
1
FWIW, работает этот запрос в PostgreSQL 11.5: ALTER TABLE testcase_result ADD COLUMN date_created TIMESTAMP WITHOUT TIME ZONE DEFAULT (NOW() AT TIME ZONE "UTC") NOT NULL;терпит неудачу с: ERROR: column "UTC" does not exist. Убедитесь, что 'utc'все строчные.
code_dredd
2
Исправление: 'utc'Строка также должна быть в одинарных, а не в двойных кавычках.
code_dredd
56

Еще одно решение:

timezone('utc', now())
Мартти
источник
26

Оберните это в функцию:

create function now_utc() returns timestamp as $$
  select now() at time zone 'utc';
$$ language sql;

create temporary table test(
  id int,
  ts timestamp without time zone default now_utc()
);
Дени де Бернарди
источник
16

Что о

now()::timestamp

Если ваша другая временная метка не имеет часового пояса, тогда это приведение даст соответствующий тип «временная метка без часового пояса» для текущего времени.

Я хотел бы прочитать, что другие думают об этом варианте, хотя. Я все еще не верю в мое понимание этого "с / без" материала о часовом поясе.

РЕДАКТИРОВАТЬ: Добавление комментария Майкла Экока здесь, потому что он проясняет важный момент:

Предостережение. Вопрос заключается в том, чтобы создать временную метку по умолчанию в UTC для столбца меток времени, в котором не хранится часовой пояс (возможно, потому что нет необходимости хранить часовой пояс, если вы знаете, что все ваши временные метки имеют одинаковые значения). Ваше решение состоит в том, чтобы сгенерировать локальную временную метку (которая для большинства людей не обязательно будет установлена ​​в UTC) и сохранить ее как наивную временную метку (та, которая не указывает свой часовой пояс).

Risadinha
источник
Это интересный трюк, но он может привести к путанице, если вы не знаете об этом поведении. Принятый ответ предельно ясен в отношении действия и желаемого результата. То же самое с функцией, но я
Фрэнк V
в моем варианте он генерирует локальную дату и время в БД
ВеликийНехочуха
Предостережение. Вопрос заключается в том, чтобы создать временную метку по умолчанию в UTC для столбца временной метки, в котором не хранится часовой пояс (возможно, потому, что нет необходимости хранить часовой пояс, если вы знаете, что все ваши временные метки имеют одинаковые значения). Ваше решение состоит в том, чтобы сгенерировать локальную временную метку (которая для большинства людей не обязательно будет установлена ​​в UTC) и сохранить ее как наивную временную метку (та, которая не указывает свой часовой пояс).
Майкл
@MichaelEkoka Я добавил ваш комментарий в ответ - пожалуйста, продолжайте и отредактируйте его, если хотите. Вы объясняете это очень четко. Спасибо!
Risadinha
Предупреждение : временная метка с полем часового пояса НЕ хранит часовой пояс, вопреки разумному предположению. Смотрите ссылку ниже и найдите на странице UTC. На входе, отметка времени с временной зоной преобразует входное значение в формате UTC и сохраняет это значение без часового пояса ИЛИ ИНФОРМАЦИЯ OFFSET . На выходе сохраненное значение utc преобразуется в местное время, используя часовой пояс клиента, если он доступен. Этот тип все о преобразовании значений во время запроса. Вы должны проверить это, сохранив один часовой пояс и выбрав другой. postgresql.org/docs/11/datatype-datetime.html
Том
7

Это 2 эквивалентных решения:

(в следующем коде, вы должны заменить 'UTC'на зоны и now()для временной метки )

  1. timestamp AT TIME ZONE zone - Соответствие стандарту SQL
  2. timezone(zone, timestamp) - возможно, более читаемый

Функция timezone (zone, timestamp) эквивалентна временной метке, соответствующей конструкции SQL, в зоне AT TIME ZONE.


Объяснение:

  • зона может быть указана либо как текстовая строка (например, 'UTC'), либо как интервал (например, INTERVAL '-08:00') - вот список всех доступных часовых поясов
  • отметка времени может быть любым значением типа отметка времени
  • now()возвращает значение типа timestamp (именно то, что нам нужно) с прикрепленным к вашей базе данных часовым поясом по умолчанию (например 2018-11-11T12:07:22.3+05:00).
  • timezone('UTC', now())превращает наше текущее время (типа отметка времени с часовым поясом ) в эквивалент времени без времени в UTC.
    Например, SELECT timestamp with time zone '2020-03-16 15:00:00-05' AT TIME ZONE 'UTC'вернусь 2020-03-16T20:00:00Z.

Документы: часовой пояс ()

lakesare
источник
1
Спасибо за обобщение этих вещей. Я использовал строчную версию, at timezone 'utc'и это не сработало с моей настройкой PostgreSQL. Использование заглавных букв решило проблему
Geradlus_RU
2

Функция уже существует: часовой пояс ('UTC' :: text, now ())

user10259440
источник