web-dev-qa-db-fra.com

Comment obtenir l'horodatage Unix actuel de PostgreSQL?

horodatage Unix est le nombre de secondes écoulées depuis le 1er janvier 1970 à minuit UTC.

Comment puis-je obtenir l'horodatage Unix correct de PostgreSQL?

En comparant avec currenttimestamp.com et timestamp.1e5b.de je n'obtiens pas l'heure prévue de PostgreSQL:

Cela renvoie l'horodatage correct:

SELECT extract(Epoch from now());

Bien que cela ne le fasse pas:

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

J'habite dans le fuseau horaire UTC +02. Quelle est la bonne façon d'obtenir l'horodatage Unix actuel de PostgreSQL?

Cela renvoie l'heure et le fuseau horaire corrects:

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

Une autre comparaison:

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
99
Jonas

En postgres, timestamp with time zone Peut être abrégé en timestamptz et timestamp without time zone En timestamp. J'utiliserai les noms de type plus courts pour plus de simplicité.

Obtenir l'horodatage Unix à partir d'un postgres timestamptz comme now() est simple, comme vous le dites, juste:

select extract(Epoch from now());

C'est vraiment tout ce que vous devez savoir pour obtenir l'heure absolue à partir de tout ce qui est de type timestamptz, y compris now().

Les choses ne se compliquent que lorsque vous avez un champ timestamp.

Lorsque vous mettez timestamptz des données comme now() dans ce champ, elles seront d'abord converties en un fuseau horaire particulier (soit explicitement avec at time zone Soit en les convertissant en fuseau horaire de session) et les informations de fuseau horaire sont supprimées . Il ne fait plus référence à un temps absolu. C'est pourquoi vous ne souhaitez généralement pas stocker les horodatages sous la forme timestamp et utilisez normalement timestamptz - peut-être qu'un film sort à 18 heures à une date particulière dans chaque fuseau horaire , c'est le genre de cas d'utilisation.

Si vous ne travaillez que dans un seul fuseau horaire, vous pouvez vous en sortir avec (mal) en utilisant timestamp. La conversion en timestamptz est suffisamment intelligente pour faire face à l'heure d'été et les horodatages sont supposés, à des fins de conversion, être dans le fuseau horaire actuel. Voici un exemple pour 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

Mais notez le comportement déroutant suivant:

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

C'est parce que :

PostgreSQL n'examine jamais le contenu d'une chaîne littérale avant de déterminer son type, et traitera donc les deux […] comme horodatage sans fuseau horaire. Pour garantir qu'un littéral est traité comme horodatage avec fuseau horaire, donnez-lui le type explicite correct… Dans un littéral qui a été déterminé comme étant un horodatage sans fuseau horaire, PostgreSQL ignorera silencieusement toute indication de fuseau horaire.

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

ne renvoie pas l'horodatage correct car la conversion du fuseau horaire postgres supprime les informations de fuseau horaire du résultat:

9.9.3. AT FUSEAU HORAIRE

Syntaxe: horodatage sans fuseau horaire AT Fuseau horaire
Renvoie: horodatage avec fuseau horaire
Traiter l'horodatage donné sans fuseau horaire comme situé dans le fuseau horaire spécifié

Syntaxe: horodatage avec fuseau horaire AT Fuseau horaire
Renvoie: horodatage sans fuseau horaire
Convertir l'horodatage donné avec le fuseau horaire au nouveau fuseau horaire, sans désignation de fuseau horaire

ensuite, extraire regarde l'horodatage sans fuseau horaire et le considère comme une heure locale (bien qu'il soit déjà utc en fait).

La bonne façon serait:

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)

Dans la dernière ligne, le premier at time zone effectue la conversion, le second attribue un nouveau fuseau horaire au résultat.

23
axil