2010-12-11 11 views
0

Ich muss einige Datum-Uhrzeit-Operationen auf meiner Datenbank, die alle created Zeitstempel benötigen, um das gleiche Jahr haben. Ich habe versucht, mit dieser Abfrage:Timestamp Manipulationen in PostgreSQL - Problem mit Stunden/Zeitzone

select created,cast (created - 
    to_timestamp(''||date_part('year', created), 'YYYY') + 
    timestamp '2010-01-01' as timestamp without time zone) 
    from table where created is not null limit 10; 

... aber das Ergebnis ist nur teilweise befriedigend:

 created  |  timestamp  
---------------------+--------------------- 
2010-08-29 12:44:05 | 2010-08-29 11:44:05 
2007-06-21 13:49:22 | 2010-06-21 12:49:22 
2007-06-21 15:02:33 | 2010-06-21 14:02:33 
2007-06-21 15:05:26 | 2010-06-21 14:05:26 
1999-09-30 13:00:00 | 2010-09-30 12:00:00 
1997-06-07 13:00:00 | 2010-06-07 12:00:00 
2010-06-15 20:51:01 | 2010-06-15 19:51:01 
2006-08-26 15:33:02 | 2010-08-26 14:33:02 
2009-12-15 11:07:06 | 2010-12-15 11:07:06 
1997-06-28 13:00:00 | 2010-06-28 12:00:00 
(10 rows) 

Wie Sie sehen können, sind alle Zeitstempel sind -1 Stunde ursprünglichen created Werte zu vergleichen. Was noch seltsamer ist, ist, dass der vorletzte (2010-12-15 11:07:06) nicht ist.

created Spalte ist timestamp without time zone Typ.

Irgendeine Idee, was ich falsch gemacht habe?

Antwort

1

Das Problem mit Ihrem SQL ist, dass es kein Datum in ein Datum in einem anderen Jahr verwandelt. Es berechnet Deltas für erstellt und 2010-01-01 und konvertiert das zu einem Datum. Sie entfernen also nicht den Jahresteil, sondern berechnen, wie lange es her ist.

Hier ist ein weiterer Weg, um das Problem anzugehen. Es wird nur das Jahr ersetzen und den Rest des Datums unberührt lassen.

SELECT TO_TIMESTAMP('2010-' || CAST(EXTRACT(MONTH FROM created) AS VARCHAR) || '-' || CAST(EXTRACT(DAY FROM created) AS VARCHAR) || ' ' || CAST(EXTRACT(HOUR FROM created) AS VARCHAR) ||':'||CAST(EXTRACT(MINUTE FROM created) AS VARCHAR) ||':'|| CAST(EXTRACT(SECONDS FROM created) AS VARCHAR), 'YYYY-MM-dd HH24:MI:SS') AS timestamp FROM table; 

Sie könnten dies auch mit Teilstrings tun. TO_TIMESTAMP() wird den Tag 2010-02-29 zu 2010-03-01, also ist es sicher zu bedienen.

1

Dies ist die Teillösung jmz erwähnt:

 
select to_timestamp('2010'||substring(to_char(created, 'yyyy-mm-dd hh24:mi:ss.ms'), 5), 'yyyy-mm-dd hh24:mi:ss.ms') 
0

Danke Jungs, beide jmz und a_horse_with_no_name Lösungen funktionieren.

Ich habe auch meine Lösung behoben. Das Problem war mit to_timestamp, die timestamp with time zone zurückgibt und ich erwartete timestamp without time zone. Es reichte, eine Typumwandlung hinzuzufügen:

select created,cast (created-to_timestamp(''|| 
    date_part('year', created), 'YYYY')::timestamp without time zone + 
    timestamp '2010-01-01' as timestamp without time zone) 
    from table;