web-dev-qa-db-fra.com

Champ de date / heure postgresQL hors de portée à la seconde depuis l'époque

J'importe un fichier csv dans une base de données PostgreSQL. La plupart des fichiers sont importés sans problème jusqu'à ce que je reçoive ce message

ERROR:  date/time field value out of range: "1421088300"
HINT:  Perhaps you need a different "datestyle" setting.
CONTEXT:  COPY accidents, line 6356158, column datetime: "1421088300"

Mais cela semble être un horodatage valide pour le 01/12/2015 à 18h45 (UTC) selon https://www.unixtimestamp.com/index.php

Alors pourquoi est-il hors de portée?

4
falcs

Secondes depuis les horodatages Epoch

Votre "horodatage" est en secondes depuis l'époque. Par dezso, utilisez to_timestamp(). Cela m'a manqué quand j'ai vérifié \dfS+

Mauvaise idée complexe et dragons.

Vérifiez les formats d'entrée . Ils couvrent les moulages des cordes. C'est ce que COPY fait sous le capot. La seule méthode qui ressemble même à distance à un nombre long est ISO 8601. Si vous regardez cet exemple, vous verrez que ce n'est pas une seconde depuis l'époque

Example    | Description
19990108   | ISO 8601; January 8, 1999 in any mode

C'est fondamentalement la même chose qu'un autre exemple sur ce graphique.

Example    | Description
1999-01-08 | ISO 8601; January 8, 1999 in any mode

Conversion en timestamp avec abstime comme format intermédiaire

Donc, si vous souhaitez convertir à partir de secondes depuis l'Epoch, vous pouvez tricher en utilisant le abstime interne car il n'y a pas de transtypage disponible directement en horodatage à partir d'une chaîne de secondes depuis l'Epoch.

SELECT 1421088300::abstime::timestamp;
      timestamp      
---------------------
 2015-01-12 12:45:00
(1 row)

Ce qui se passe ici, c'est que abstime est coercable binaire avec integer. Vous pouvez le voir dans \dC+. J'ai vérifié \dfS+ pour que les fonctions passent d'un entier à un horodatage et n'en trouvent aucune. Il y a un transtypage de l'entier en abstime (qui est stocké sous forme d'entier) et de abstime en timestamp.

S'il s'agit d'une nouvelle table, vous pouvez réellement taper cette colonne comme abstime. Il devrait se charger parfaitement bien. Et puis vous pouvez ALTER TABLE. voici un exemple, sauf que je n'exécute pas COPY (mais ça devrait quand même fonctionner).

CREATE TABLE foo(bar)
AS VALUES
  (1421088300::abstime);

TABLE foo;
          bar           
------------------------
 2015-01-12 12:45:00-06
(1 row)

ALTER TABLE foo
  ALTER bar
  TYPE timestamp;

TABLE foo;
         bar         
---------------------
 2015-01-12 12:45:00
(1 row)

\d foo;
                Table "public.foo"
 Column |            Type             | Modifiers 
--------+-----------------------------+-----------
 bar    | timestamp without time zone | 
4
Evan Carroll