Як отримати поточну мітку часу Unix від PostgreSQL?


91

Часова мітка Unix - це кількість секунд з півночі UTC 1 січня 1970 року.

Як отримати правильну часову позначку Unix від PostgreSQL?

Якщо порівнювати з currenttimestamp.com та timestamp.1e5b.de, я не отримую очікуваного часу від PostgreSQL:

Це повертає правильну часову позначку:

SELECT extract(epoch from now());

Хоча цього немає:

SELECT extract(epoch from now() at time zone 'utc');

Я живу в часовому поясі UTC +02. Який правильний спосіб отримати поточну позначку часу Unix від PostgreSQL?

Це повертає правильний час та часовий пояс:

SELECT now();
              now
-------------------------------
 2011-05-18 10:34:10.820464+02

Ще одне порівняння:

select now(), 
extract(epoch from now()), 
extract(epoch from now() at time zone 'utc');
              now              |    date_part     |    date_part
-------------------------------+------------------+------------------
 2011-05-18 10:38:16.439332+02 | 1305707896.43933 | 1305700696.43933
(1 row)

Unix timestamp from the web sites:
1305707967

Відповіді:


82

У постгресах timestamp with time zoneможна скоротити як timestamptzі, timestamp without time zoneяк timestamp. Я буду використовувати короткі назви типів для простоти.

Отримати часову позначку Unix з постгресів, timestamptzяк now(), як ви кажете, просто:

select extract(epoch from now());

Це дійсно все, що потрібно знати про отримання абсолютного часу від будь-якого типу timestamptz, в тому числі now().

Речі ускладнюються лише тоді, коли у вас є timestampполе.

Коли ви вводите timestamptzтакі дані, як now()це поле, спочатку вони будуть перетворені на певний часовий пояс (або явно з at time zoneперетворенням в часовий пояс сеансу), і інформація про часовий пояс буде відкинута . Це вже не стосується абсолютного часу. Ось чому ви, як правило, не хочете зберігати часові позначки як timestampі зазвичай використовуєте timestamptz- можливо, фільм виходить о 18:00 у певну дату в кожному часовому поясі , це такий вигляд використання.

Якщо ви коли-небудь працюєте в одному часовому поясі, ви можете уникнути (неправильно) використання timestamp. Перетворення назад в timestamptzдостатньо розумне, щоб впоратися з DST, і часові позначки для цілей перетворення передбачаються у поточному часовому поясі. Ось приклад для GMT / BST:

select '2011-03-27 00:59:00.0+00'::timestamptz::timestamp::timestamptz
     , '2011-03-27 01:00:00.0+00'::timestamptz::timestamp::timestamptz;

/*
|timestamptz           |timestamptz           |
|:---------------------|:---------------------|
|2011-03-27 00:59:00+00|2011-03-27 02:00:00+01|
*/

DBFiddle

Але зверніть увагу на таке заплутане поведінку:

set timezone to 0;

values(1, '1970-01-01 00:00:00+00'::timestamp::timestamptz)
    , (2, '1970-01-01 00:00:00+02'::timestamp::timestamptz);

/*
|column1|column2               |
|------:|:---------------------|
|      1|1970-01-01 00:00:00+00|
|      2|1970-01-01 00:00:00+00|
*/

DBFiddle

Це тому, що :

PostgreSQL ніколи не вивчає вміст прямої рядка перед визначенням її типу, і тому буде трактувати обидві […] як часові позначки без часового поясу. Щоб переконатися, що літерал трактується як часова марка з часовим поясом, надайте йому правильний явний тип… У буквальному сенсі, визначеному як часова мітка без часового поясу, PostgreSQL мовчки ігнорує будь-яку вказівку часового поясу


Будь-яка ідея, як перетворити отримане десяткове в ціле число без десяткових знаків (я маю на увазі злиття числа і десяткової як одне велике ціле число). Дякую.
WM

Як це, але я впевнений, що ти насправді не хочеш цього робити. Можливо, ви хочете помножити на десять потужностей і позбавити будь-яких десятків десятки?
Джек Дуглас

2
@WM Можливо, так? SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
Joe23

21
SELECT extract(epoch from now() at time zone 'utc');

не повертає правильну часову позначку, тому що після перетворення часових поясів постгреси викидає інформацію про часовий пояс із результату:

9.9.3. В ЧАСУ ЗОНИ

Синтаксис: часова марка без часового поясу НА ЗВОРОТНІЙ ЗОНИ
Повернення: часова
марка з часовим поясом Обробляти задану часову марку без часового поясу відповідно до вказаного часового поясу

Синтаксис: часова марка з часовим поясом В зоні часу TIME ZONE
Повертає: часова
марка без часового поясу Перетворить задану часову марку з часовим поясом у новий часовий пояс, без позначення часового поясу

після цього, витяг дивиться на часову позначку без часового поясу і вважає, що це місцевий час (хоча це вже є фактично).

Правильним було б:

select now(),
       extract(epoch from now()),                                          -- correct
       extract(epoch from now() at time zone 'utc'),                       -- incorrect
       extract(epoch from now() at time zone 'utc' at time zone 'utc');    -- correct

          now                  |    date_part     |    date_part     |    date_part
-------------------------------+------------------+------------------+------------------
 2014-10-14 10:19:23.726908+02 | 1413274763.72691 | 1413267563.72691 | 1413274763.72691
(1 row)

В останньому рядку перший at time zoneвиконує перетворення, другий присвоює новому часовому поясу результат.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.