Манипуляции с метками времени в PostgreSQL - проблема с часами / часовым поясом - PullRequest
0 голосов
/ 11 декабря 2010

Мне нужно выполнить некоторые операции с датой и временем в моей базе данных, которые требуют, чтобы все created отметки времени имели один и тот же год.Я пытался с этим запросом:

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;

... но результат удовлетворяет лишь частично:

       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)

Как видите, все метки времени -1 час по сравнению с оригиналом created значений.Еще более странным является то, что предыдущий (2010-12-15 11:07:06) - нет.

created столбец имеет тип timestamp without time zone.

Есть идеи, что я сделал не так?

Ответы [ 3 ]

1 голос
/ 11 декабря 2010

Это упомянутое решение подстроки jmz:

select to_timestamp('2010'||substring(to_char(created, 'yyyy-mm-dd hh24:mi:ss.ms'), 5), 'yyyy-mm-dd hh24:mi:ss.ms')
1 голос
/ 11 декабря 2010

Проблема с вашим SQL состоит в том, что он не превращает дату в дату другого года.Он рассчитывает дельты для созданного и 2010-01-01 и преобразует его в дату.Таким образом, вы фактически не удаляете часть года, а вычисляете, как давно это было.

Вот еще один способ решения проблемы.Он просто заменит год, оставив остальную часть дня нетронутой.

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;

Вы можете сделать это и с подстрокой.TO_TIMESTAMP() будет разыгрывать день с 2010-02-29 по 2010-03-01, поэтому его можно безопасно использовать.

0 голосов
/ 12 декабря 2010

Спасибо, ребята, решения jmz и a_horse_with_no_name работают отлично.

Я также исправил свое решение. Проблема была с to_timestamp, которая возвращает timestamp with time zone, и я ожидал timestamp without time zone. Этого было достаточно, чтобы добавить Typecast:

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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...