Convert timestamp to interval in postgresql - postgresql

I am trying to convert a timestamp to interval & expecting an out of hh:mm only.
My code is like below
SELECT to_timestamp('2020-01-10 08:00', 'YYYY-MM-DD hh24:mi')::timestamp without time zone
at time zone 'Asia/Calcutta'
at time zone 'Etc/UTC'
Actual purpose of the code is change the time zone into utc for a given date time value.

It seems you are trying to get the timedifference (interval) between two timezones at a specific time.
This can be done like this for example:
SELECT to_timestamp('2020-01-10 08:00', 'YYYY-MM-DD hh24:mi')::timestamp without time zone
at time zone 'Asia/Calcutta'
-
to_timestamp('2020-01-10 08:00', 'YYYY-MM-DD hh24:mi')::timestamp without time zone
at time zone 'Etc/UTC'
This returns an interval = -05:30:00
You can of course convert it to hours and minutes with the to_char function, but that returns string, not interval.
Best regards,
Bjarni

Related

What is difference between 4 ways convert timezone in postgresql

I don't know What is difference between 4 ways convert timezone in postgresql:
SELECT (timestamp '2018-01-20 00:00:00' at time zone 'Asia/Saigon') at time zone 'UTC';
SELECT CAST('2018-01-20 00:00:00' as timestamp without time zone) at time zone 'Asia/Saigon' at time zone 'UTC'
SELECT (TO_TIMESTAMP('2018-01-20 00:00:00', 'YYYY-MM-DD HH24:MI:SS') at time zone 'Asia/Saigon') at time zone 'UTC'
SELECT ('2018-01-20 00:00:00' at time zone 'Asia/Saigon') at time zone 'UTC';
The results are different. Why?
The first two statements do the same thing.
The difference is the way in which a constant of type timestamp without time zone is created, but the result is the same in both cases.
The third statement creates a timestamp with time zone using to_timestamp, where the string is interpreted in your session time zone. This is then converted to a timestamp without time zone as the wall clock in Saigon would show, and then converted to a timestamp with time zone imagining the wall clock were teleported to UTC.
The fourth statement does the same as the third, because the string is implicitly cast to timestamp with time zone. There is an ambiguity here because AT TIME ZONE can also be applied to timestamp without time zone, but in case of doubt the preferred type of its category is used, which is timestamp with time zone.
The SQL standard differentiates timestamp without time zone and timestamp with time zone literals by the presence of a "+" or "-" symbol and time zone offset after the time. Hence, according to the standard
Also you can see below articles:
Section 8.5.1.3. Time Stamps
Time zone

Timestamp format with offset in postgres

This is really stumping me and it doesn't seem like it should be that difficult, but in postgres 9.6, I'm trying to format a timestamp with the offset.
Here's the closest I've gotten:
SELECT to_char('2017-11-06 00:00:00'::TIMESTAMP WITH TIME ZONE AT TIME ZONE 'America/Vancouver', 'MM/DD/YYYY HH24:MI:SS (OF)');
The above example gets the right date, but the offset is +00, which is incorrect.
Any ideas?
EDIT:
Additionally, how do I set this in a function? The following doesn't work:
DECLARE
_tz text = 'PST8PDT';
BEGIN
SET LOCAL TIME ZONE _tz;
...
First you set the time zone of the session, then you set the timezone that the timestamp is in. Like so:
SET TIME ZONE 'America/Vancouver';
SELECT to_char('2017-11-06 00:00:00'::TIMESTAMP AT TIME ZONE 'UTC', 'MM/DD/YYYY HH24:MI:SS (OF)');

How to convert local timestamp (of a given time zone) to UTC?

I am working in a code where multiple time zones will be available. I need to create a function which takes the selected local timestamp as well as the local time zone. The return value of the function should the UTC time of the local time (local time for the given local time zone).
I am working on PostgreSQL 8.3
SELECT Now() AT TIME ZONE 'UTC';
This will return timestamp without time zone at specified time zone (UTC in my example) for given timestamp with time zone.
From PostgreSQL docs:
SELECT TIMESTAMP '2001-02-16 20:38:40' AT TIME ZONE 'MST';
Result: 2001-02-16 19:38:40-08
SELECT TIMESTAMP WITH TIME ZONE '2001-02-16 20:38:40-05' AT TIME ZONE 'MST';
Result: 2001-02-16 18:38:40
You can get list of time zones from pg_timezone_names:
select * from pg_timezone_names limit 5
name;abbrev;utc_offset;is_dst
----------------------
PRC;CST;08:00:00;f
Asia/Brunei;BNT;08:00:00;f
Asia/Ujung_Pandang;CIT;08:00:00;f
Asia/Ust-Nera;VLAT;11:00:00;f
Asia/Phnom_Penh;ICT;07:00:00;f

Postgres: get local timestamp with time zone of latest midnight

I'm in the Time Zone Europe/Berlin (+02), Postgresql is running at UTC (+00).
I need to get the timestamp with time zone at the latest local midnight date (The start of day date of the current day in my time zone).
So my end result would be something like this if we have 2013-03-03 14:00:00+02
2013-03-03 22:00:00+00
2013-03-04 00:00:00+02 // the same
I tried to get this date with
SELECT TIMESTAMP 'today' AT TIME ZONE 'Europe/Berlin'
Unfortunately this yields the wrong date (the previous day midnight) during 00:00 and 02:00 as the UTC time is stil at the previous day and today seems to use utc to calculate the rest.
If we have 2013-03-03 00:05 at Europe/Berlin this will return
2013-05-01 22:00:00+00
If I want to have the correct date I need to use
SELECT date_trunc('day', now() AT TIME ZONE 'Europe/Berlin') AT TIME ZONE 'Europe/Berlin';
2013-05-02 22:00:00+00
which is correct, but quite ugly.
Is there a cleaner variant of this command?
Use timestamptz. The tz at the end meaning with time zone:
SELECT TIMESTAMPTZ 'today' AT TIME ZONE 'Europe/Berlin'
Or if you like it more explicit:
SELECT TIMESTAMP with time zone 'today' AT TIME ZONE 'Europe/Berlin'
Wrap it in a function:
create function midnight() returns timestamptz as $$
select date_trunc('day', now() AT TIME ZONE 'Europe/Berlin') AT TIME ZONE 'Europe/Berlin';
$$ language sql;
Based on Erwin's answer to a related question, this was the simplest and fastest way I figured out how to do it:
SELECT timezone('Europe/Berlin', now()::date::timestamp) AS local_midnight_in_utc;
The key is the cast to a timestamp, which removes the time zone from the date.
You can test your sample time of '2013-03-03 00:05' with this:
SELECT timezone('Europe/Berlin', '2013-03-03 00:05'::date::timestamp) AS midnight;
and it returns
2013-03-02 23:00:00+00
According to explain analyze, this is about 3x as fast as the datetrunc version. A runtime of .017ms vs 0.006ms based on a best of 5 runs.

postgresql: timezone sensitive query on a timestamp without timezone

I have a table with a timestamp without time zone column (data entered is assumed to be in Australia/Sydney time zone).
Query on data for a time range (ie 8am-4pm) in America/New_York time zone.
Is there an easy way to achieve this?
thanks, p.
Figured it out.
You need to first convert the time to it's with time zone version ie my_ts at time zone 'Australia/Sydney' and then convert that to it's NY counterpart via at time zone 'America/New_York'
select
my_ts as "Default(syd)",
my_ts at time zone 'Australia/Sydney' as "SYD",
my_ts at time zone 'Australia/Sydney' at time zone 'America/New_York' as "NY",
date_part('hour', my_ts at time zone 'Australia/Sydney' at time zone 'America/New_York') as "NY-hr"
from my_table
where date_part('hour', my_ts at time zone 'Australia/Sydney' at time zone 'America/New_York')>=8
and date_part('hour', my_ts at time zone 'Australia/Sydney' at time zone 'America/New_York')<16
You can convert everything to the same time zone so you can compare them with (if the timezone was set):
select current_time, current_time at time zone 'gmt';
timetz | timezone
-------------------+-------------------
20:50:51.07742-07 | 03:50:51.07742+00
If the time zone is not set and you need to correct it some local time:
select now()::time, now()::time + '+8:00'::interval;
now | ?column?
-----------------+-----------------
20:57:49.420742 | 04:57:49.420742
Once you get the time the way you want, just the extract the hour and you can use a simple condition to select the proper times.
select *
from
(select extract(hour from now()::time + '+8:00'::interval) as hour) as t
where hour between 8 and 16;