How can postgres change from unix epoch time with miliseconds to timestamptz? - postgresql

I am using the below postgres sql to convert from unix epoch time to timestamp.
select to_timestamp(1608816600) at time zone 'UTC';
It works when the epoch time does not contain milliseconds but when it contains milliseconds, it does not work. The below query:
select to_timestamp(1611150788148) at time zone 'UTC';
returns:
However it should be Wed Jan 20 2021 13:53:08 with some milliseconds. Source: https://currentmillis.com/

As documented in the manual to_timestamp() expects a "seconds since 1970-01-01 00:00:00+00" - but it allows fractional values.
If you want to specify milliseconds you need to divide your value by 1000
select to_timestamp(1611150788148::double precision/1000) at time zone 'UTC';
select to_char(to_timestamp(1611150788148/1000.0) at time zone 'UTC', 'yyyy-mm-dd hh24:mi:ss.ff3');
to_char
-----------------------
2021-01-20 13:53:08.148

Related

How can change/convert timezone when I query in PostgreSQL

I need a query to convert timezone in PostgreSQL
I have already tried this query
Select users.last_update_time + interval '7 hours'
And it plus for my result 7 hours.
But I have a problem that if I choose results from 31/01/2022 to 06/02/2022. It will include the result on 07/02/2022. Example before I plus 7 hours, it's on around 17:00 06/02/2022 to 00:00 07/02/2022.
The correct result has to be after +7 hours. So it means that result after plus 7 hours from 17:00 06/02/2022 to 00:00 07/02/2022 shouldn't be in there.
Then you should include the time zone in the query like this:
SELECT ... FROM ...
WHERE tscol BETWEEN '2022-01-31 00:00:00 America/Vancouver'
AND '2022-02-07 00:00:00 America/Vancouver';
If you don't want to hard code the time zone, the best thing is to set the timezone database parameter to the correct time zone in your database session. Then you can use a simple type cast, which will respect the setting:
SELECT ... FROM ...
WHERE tscol BETWEEN CAST ('2022-01-31 00:00:00' AS timestamp with time zone)
AND CAST ('2022-02-07 00:00:00' AS timestamp with time zone);

Grafana/Postgresql: how to convert date stored in UTC to local timezone

I have a date stored in postgres db, e.g. 2019-09-03 15:30:03. Timezone of postgres is UTC.
When Grafana gets the date, it is 2020-09-03T15:30:03.000000Z. If I now run date_trunc('day', 2020-09-03T15:30:03.000000Z), I get 2020-09-03T00:00:00.000000Z. But, I want midnight in my local timezone.
How do I get the local timezone (offset) in postgres or grafana?
Could I get the timezone in military style, instead of "Z" for UTC "B"?
Or can I somehow subtract the offset of the local timezone to get a UTC date corresponding to midnight local time?
Thanks in advance
Michael
Get the local timezone (offset):
select to_char(now(), 'OF');
-- result '+03' for EEST
Get UTC time corresponding to midnight local time:
select date_trunc('DAY', now()) at time zone 'UTC';
-- result '2020-06-05 21:00:00.0' for 13:30 EEST on 2020-06-06
Convert UTC time to local timezone time:
select now();
-- Local time is 2020-06-06 13:43:27.482463
select (now() at time zone 'UTC');
-- UTC time is 2020-06-06 10:43:27.482463
select '2020-06-06 10:43:27.482463UTC'::timestamp with time zone;
-- UTC time converted to local time is 2020-06-06 13:43:27.482463
Hope that this helps.

Postgres 9.6, timezones: why are those two queries giving me different times

Ok so I've always been fuzzy with the timezones. I'm getting better, but not there yet. Can you people enlighten me?
Context: I receive a UTC time from the frontend. For example, to denote the date 1 September 2019, I'll get 2019-08-31 22:00:00Z (we're in Brussels DST, hence the 2 hours difference).
From that date, I need to generate a series of 6 months before that. So that's March April May June July August.
I managed to find a solution, somewhat out of luck to be honest. I'm still not sure I understand the details of what happens below:
database=> show timezone;
TimeZone
----------
UTC
(1 row)
database=> select generate_series(
('2019-08-31 22:00:00Z'::timestamp at time zone 'Europe/Brussels')::date - '6 month'::interval,
('2019-08-31 22:00:00Z'::timestamp at time zone 'Europe/Brussels')::date - '1 month'::interval,
'1 month'::interval
);
generate_series
---------------------
2019-02-28 00:00:00
2019-03-28 00:00:00
2019-04-28 00:00:00
2019-05-28 00:00:00
2019-06-28 00:00:00
2019-07-28 00:00:00
(6 rows)
database=> select generate_series(
('2019-08-31 22:00:00Z' at time zone 'Europe/Brussels')::date - '6 month'::interval,
('2019-08-31 22:00:00Z' at time zone 'Europe/Brussels')::date - '1 month'::interval,
'1 month'::interval
);
generate_series
---------------------
2019-03-01 00:00:00
2019-04-01 00:00:00
2019-05-01 00:00:00
2019-06-01 00:00:00
2019-07-01 00:00:00
2019-08-01 00:00:00
Why do I get wrong results if I use ::timestamp?
There are actually two different &ldauo;operators” named AT TIME ZONE, one converting timestamp with time zone to timestamp without time zone and one the other way around.
If the first argument is a timestamp with time zone, the value is converted to a timestamp without time zone that shows what a wall clock in that time zone would.
If the first argument is a timestamp without time zone, it is interpreted in the session time zone (given by the value of the timezone parameter) and converted to an absolute time stamp.
Now timestamp with time zone is the preferred type of the date/time type category, so the string literal in your second query is interpreted as a timestamp with time zone in accordance with the documentation. In the first query it is a timestamp without time zone. Since there are different operators involved, it is not surprising that the results are different.
In your first query, the wall clock time 22:00 is interpreted as if the clock hung in Brussels, so it is actually 20:00 UTC. The first argument of generate_series, from which counting starts, is then Feb 28 2019, 20:00 UTC (before casting to date).

How to treat string as UTC timestamp?

I have to read strings like '20190608070000' as timestamps given in UTC. Is there an easy way to do that?
This one takes UTC but needs formatted input:
postgres=# show time zone;
TimeZone
----------
CET
(1 Zeile)
postgres=# select timestamp without time zone '2019-06-08 07:00:00' at time zone 'UTC';
timezone
------------------------
2019-06-08 09:00:00+02
(1 Zeile)
Whereas to_timestamp() invariably treats all input as local time as far as I see, so the output is shifted the wrong way:
postgres=# SELECT to_timestamp('20190608070000', 'YYYYMMDDHH24MISS') AT time zone 'UTC';
timezone
---------------------
2019-06-08 05:00:00
(1 Zeile)
Actually I'm using PostgreSQL 9.6.
The return type of TO_TIMESTAMP is timestamp with time zone. The time shown is in your current session's time zone(with the UTC offset).
SET SESSION timezone TO 'CET';
SET
knayak=# SELECT to_timestamp('20190608070000', 'YYYYMMDDHH24MISS');
to_timestamp
------------------------
2019-06-08 07:00:00+02
When you transform it with AT TIME ZONE, it will show the time in UTC when it's 07:00 hours in your current time zone.
SELECT to_timestamp('20190608070000', 'YYYYMMDDHH24MISS') AT time zone 'UTC';
timezone
---------------------
2019-06-08 05:00:00
(1 row)
So, If you wish to read your timestamp in a desired format and treat that as UTC, cast the output of to_timestamp explicitly to timestamp (without time zone) and then apply AT TIME ZONE.
SELECT to_timestamp('20190608070000', 'YYYYMMDDHH24MISS') :: timestamp
AT time zone 'UTC';
timezone
------------------------
2019-06-08 09:00:00+02
(1 row)

Postgresql select output date with missing timezone offset

I've got a hard time with postgresql and timezones.
The Postgresql server is in UTC time zone.
I want to perform a query that returns the date in another timezone with the timezone offset.
I can perform a query that returns the date in a timezone but I'm missing the timezone offset
base=# SET timezone to 'utc';
SET
base=# select now();
now
------------------------------
2018-04-20 14:58:22.68038+00
(1 row)
base=# SET timezone to 'Europe/Paris';
SET
base=# select now();
now
-------------------------------
2018-04-20 16:58:29.614383+02
(1 row)
base=# SET timezone to 'utc';
SET
base=# select now() AT TIME ZONE 'Europe/Paris';
timezone
----------------------------
2018-04-20 16:59:03.146917 -- missing timezone offset here
(1 row)
Expected result
base=# SET timezone to 'utc';
SET
base=# select now() AT TIME ZONE 'Europe/Paris'; --I'm missing something here, I guess
timezone
----------------------------
2018-04-20 16:59:03.146917+02 -- That's what I want
(1 row)
Do you have any idea how to do it?
Thanks
If you use AT TIME ZONE, PG returns a timestamp without time zone. If you cast it to back to a timestamp with time zone, you get your expected result:
SELECT (NOW() AT TIME ZONE 'Europe/Paris')::TIMESTAMPTZ;
Result:
2018-04-20 18:15:26.165+02
How do you get the +02 without setting the timezone? Here's the problem: NOW() AT TIME ZONE 'Europe/Paris' returns the current time in the specified time zone (without an offset), and casting it back to TIMESTAMPTZ gives you the offset of the current time zone (of your PG session) based on UTC. Since 'Europe/Paris' is +02 from UTC, if you've set your time zone to 'Europe/Paris', the offset you get in a TIMESTAMPTZ is +02. If your current time zone setting is UTC, your offset is +00.
How to get the offset no matter what your PG session's time zone setting, without explicitly setting the time zone? I would like to think there's a better way to get the offset, but without knowing one, here's one way: calculate the offset, format it, append it to the timestamp without time zone.
SELECT (NOW() AT TIME ZONE 'Europe/Paris')::TEXT || TO_CHAR(EXTRACT(hour FROM NOW() AT TIME ZONE 'Europe/Paris' - NOW() AT TIME ZONE 'UTC'), 'FMSG00')
Result: 2018-04-21 15:12:42.658+02, and I get the same result no matter the current timezone.
Some timezone have an offset in 30 or 45 minutes.
Using TO_CHAR(EXTRACT(hour FROM NOW() AT TIME ZONE 'Europe/Paris' - NOW() AT TIME ZONE 'UTC') exclude this use case.
Did you consider to use SET LOCAL TIME ZONE 'Europe/Paris'; in a dedicated function ? According to the documentation :
If SET LOCAL is used within a function that has a SET option for the same variable (see CREATE FUNCTION), the effects of the SET LOCAL command disappear at function exit
This other reply seem's fitting your requirement : How to convert timestamp field to ISO 8601 string in a given time zone?