Reputation: 1414
I need to do some date-time operations on my database which require all created
timestamps to have the same year. I tried with this query:
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;
... but the result is only partially satisfying:
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)
As you can see, all timestamps are -1 hour comparing to original created
values. What's even more strange is that the one before last one (2010-12-15 11:07:06
) is not.
created
column is timestamp without time zone
type.
Any idea what I did wrong?
Upvotes: 0
Views: 2249
Reputation: 1414
Thanks guys, both jmz and a_horse_with_no_name solutions work fine.
I also fixed my solution. The problem was with to_timestamp which returns timestamp with time zone
and I expected timestamp without time zone
. It was enough to add a 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;
Upvotes: 0
Reputation:
This is the substring solution jmz mentioned:
select to_timestamp('2010'||substring(to_char(created, 'yyyy-mm-dd hh24:mi:ss.ms'), 5), 'yyyy-mm-dd hh24:mi:ss.ms')
Upvotes: 1
Reputation: 5479
The problem with your SQL is that it does not turn a date into a date in another year. It calculates deltas for created and 2010-01-01 and converts that to a date. So you're not actually removing the year part, but calculating how long ago it was.
Here's another way to approach the problem. It will just replace the year, leaving the rest of the date untouched.
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;
You could do this with substrings too. TO_TIMESTAMP()
will cast the day 2010-02-29 to 2010-03-01, so it's safe to use.
Upvotes: 1