Dans postgres, timestamp with time zone
peut être abrégé en timestamptz
, et timestamp without time zone
en timestamp
. Je vais utiliser les noms de types les plus courts pour plus de simplicité.
Obtenir le timestamp Unix depuis un postgres timestamptz
like now()
est simple, comme vous dites, simplement:
select extract(epoch from now());
C'est tout ce que vous devez savoir pour obtenir l'heure absolue de tout type timestamptz
, y compris now()
.
Les choses ne se compliquent que lorsque vous avez un timestamp
champ.
Lorsque vous placez des timestamptz
données comme now()
dans ce champ, elles sont d'abord converties dans un fuseau horaire particulier (explicitement avec at time zone
ou en convertissant dans le fuseau horaire de la session) et les informations relatives au fuseau horaire sont supprimées . Il ne fait plus référence à un temps absolu. C’est la raison pour laquelle vous ne souhaitez généralement pas stocker les horodatages de la manière timestamp
habituelle timestamptz
. Un film est peut-être diffusé à 18 heures à une date donnée, 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 tirer (mal) timestamp
. La conversion vers timestamptz
est suffisamment intelligente pour prendre en charge l'heure d'été, et les horodatages sont supposés, pour les besoins de la conversion, se trouver 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 des horodatages sans fuseau horaire. Pour vous assurer qu'un littéral est traité comme un horodatage avec fuseau horaire, donnez-lui le type explicite correct… Dans un littéral déterminé comme étant un horodatage sans fuseau horaire, PostgreSQL ™ ignorera en silence toute indication de fuseau horaire.
SELECT FLOOR(EXTRACT(epoch FROM NOW())*1000);
ne retourne pas l'horodatage correct car la conversion de fuseau horaire postgres supprime les informations de fuseau horaire du résultat:
Ensuite, extraire regarde l'horodatage sans fuseau horaire et considère qu'il s'agit d'une heure locale (bien que l'heure soit déjà utc).
La bonne façon serait:
Dans la dernière ligne, la première
at time zone
effectue la conversion, la seconde attribue un nouveau fuseau horaire au résultat.la source