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
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|
*/
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|
*/
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.