Difference between timestamp variable and time variable - postgresql

I have the following table in postgresql (table1):
timestamp1 timestamp without time zone NOT NULL,
variable1 integer,
timestamp2 timestamp without time zone NOT NULL
I want calculate the timestamp2.
Note that variable 1 is of type integer in table 1, but in practice is a time variable defined in hours
The timestamp2 is defined by difference of timestamp1 and variable1
(timestamp2= timestamp1 – variable1)
For example,
2013-02-06 07:00:00 - 5 = 2013-02-06 02:00:00
2013-02-06 09:00:00 - 12 = 2013-02-05 21:00:00
2013-02-06 12:00:00 - 4.5 = 2013-02-06 07:30:00
How to do this calculation (of timestamp2) in postgresql?

select timestamp1 - interval '1 hour' * variable1
from table1

Postgres understands the number as time:
5 -> 05:00:00
12 -> 12:00:00
4.5 -> 04:30:00

Related

Postgresql extracting 'epoch' from timestamp cuts off last date in date range

My table has the column event_ts with column type numeric.
Here is my query:
select
min(to_timestamp(event_ts)), max(to_timestamp(event_ts))
from
table1
where
event_ts >= extract('epoch' from '2021-07-01'::timestamp) and
event_ts <= extract('epoch' from '2021-07-31'::timestamp)
However, the results are
min: 2021-06-30 20:00:00.000 -0400
max: 2021-07-30 20:00:00.000 -0400
I would think the where clause would include data from 2021-07-01 to 2021-07-31.
There is data for July 31st, 2021.
Why does this query start at 2021-06-30 and end 2021-07-30?
show timezone;
TimeZone
------------
US/Pacific
select extract('epoch' from '2021-07-01'::timestamp);
extract
-------------------
1625097600.000000
select to_timestamp(1625097600);;
to_timestamp
-------------------------
06/30/2021 17:00:00 PDT
select extract('epoch' from '2021-07-01'::timestamptz);
extract
-------------------
1625122800.000000
(1 row)
test(5432)=# select to_timestamp(1625122800);
to_timestamp
-------------------------
07/01/2021 00:00:00 PDT
So by using timestamp you are creating a local time offset by the timezone offset. Using timestamptz will return a timestamp at 0:00:00.
This is because from here:
https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-EXTRACT
epoch
For timestamp with time zone values, the number of seconds since 1970-01-01 00:00:00 UTC (negative for timestamps before that); for date and timestamp values, the nominal number of seconds since 1970-01-01 00:00:00, without regard to timezone or daylight-savings rules; for interval values, the total number of seconds in the interval
Epoch is based on UTC timezone.
Not sure why you are using epoch anyway?
Why not?:
...
where
event_ts between '2021-07-01'::timestamptz and '2021-07-31'::timestamptz

How to average hourly values over multiple days with SQL

I have a SQL table (postgreSQL/TimescaleDB) with hourly values, eg:
Timestamp Value
...
2021-02-17 13:00:00 2
2021-02-17 14:00:00 4
...
2021-02-18 13:00:00 3
2021-02-18 14:00:00 3
...
I want to get the average values for each hour mapped to today's date in a specific timespan, so something like that:
select avg(value)
from table
where Timestamp between '2021-02-10' and '2021-02-20'
group by *hourpart of timestamp*
result today (2021-10-08) should be:
...
Timestamp Value
2021-10-08 13:00:00 2.5
2021-10-08 14:00:00 3.5
...
If I do the same select tomorrow (2021-10-09) result should change to:
...
Timestamp Value
2021-10-09 13:00:00 2.5
2021-10-09 14:00:00 3.5
...
I resolved the problem by myself:
Solution:
SELECT EXTRACT(HOUR FROM table."Timestamp") as hour,
avg(table."Value") as average
from table
where Timestamp between '2021-02-10' and '2021-02-20'
group by hour
order by hour;
You have to write your query like this:
select avg(value)
from table
where Timestamp between '2021-02-10' and '2021-02-20'
group by substring(TimeStamp,1,10), substring(TimeStamp,11,9)

Convert military time integer to standard time Postgres without time zone

I have a time column in postgres called military_time that is an integer and in some cases needs to be padded Ex: 1400, 1300, 25, 0900. I need to convert to 2:00 pm,1:00 pm,12:25 am,9:00 am. I have read I need cast integer to time and then use the Postgres function to_char into the format I need but I am a little lost. I have found a bunch of syntax for other languages but nothing in Postgres sql.
This is going to be more complicated then that. You will need a way to distinguish between hour only 1400/hour and minutes 1425 and minutes only 25. The hour/hrs&minutes is simple enough:
select to_char(1400::text::time, 'HH:MI:SS AM'); 02:00:00 PM,
select to_char(1425::text::time, 'HH:MI:SS AM'); 02:25:00 PM.
Minutes only could be done as:
select to_char(('00:'|| 25::text)::time, 'HH:MI:SS AM'); 12:25:00 AM
To pull it together:
create table mil_time (time_fld integer);
insert into mil_time values (1400), (1425), (25), (700);
SELECT
time_fld,
CASE
WHEN time_fld >= 1000 THEN
to_char(time_fld::text::time, 'HH:MI:SS AM')
WHEN time_fld >= 100 THEN
to_char(('0'|| time_fld::text)::time, 'HH:MI:SS AM')
WHEN time_fld <= 60 THEN
to_char(('00:'|| time_fld::text)::time, 'HH:MI:SS AM')
ELSE
'00:00:00'
END
FROM
mil_time;
time_fld | case
----------+-------------
1400 | 02:00:00 PM
1425 | 02:25:00 PM
25 | 12:25:00 AM
700 | 07:00:00 AM
UPDATE
Explanation of time_fld::text::time. It is Postgres shorthand for cast to text then to time, so:
select pg_typeof(1400::text); text
select pg_typeof(1400::text::time); time without time zone

PostgreSQL grouping by day with timezone and DST

I'm working on an existing database which date+time values are stored in BIGINT column (milliseconds since EPOCH). For each entry I can get the corresponding time zone from another table. But to make things easier to understand I will explain my problem by simulating the problem.
The timestamp 1609534800000 is equal to 2021-01-01 21:00:00 at GMT (00-00)
Now if I run the following queries (with DBeaver)
set time zone 'America/Asuncion'; -- (UTC-3)
select
to_timestamp(1609534800000 / 1000) as "1"
, to_timestamp(1609534800000 / 1000) at TIME zone 'America/New_York' as "2"
, date_trunc('day', (to_timestamp(1609534800000 / 1000) at TIME zone 'America/New_York')) as "3"
, to_timestamp(1609534800000 / 1000) at TIME zone 'Pacific/Wake' as "4"
, date_trunc('day', (to_timestamp(1609534800000 / 1000) at TIME zone 'Pacific/Wake')) as "5"
, date_part('epoch', (to_timestamp(1609534800000 / 1000) at TIME zone 'Pacific/Wake')) as "6"
, date_part('epoch', (date_trunc('day', (to_timestamp(1609534800000 / 1000) at TIME zone 'Pacific/Wake') ) ) ) as "7"
I'm getting
1 |2 |3 |4 |5 |6 |7 |
-------------------|-------------------|-------------------|-------------------|-------------------|----------|----------|
2021-01-01 16:00:00|2021-01-01 16:00:00|2021-01-01 00:00:00|2021-01-02 09:00:00|2021-01-02 00:00:00|1609578000|1609545600|
I don't understand the result at all. According to the documentation, the function to_timestamp is supposed to return a timestamp with time zone ? In this case the time zone applied should be the one in my session America/Asuncion (UTC-3). If at GMT the time is 2021-01-01 21:00:00, I should get 2021-01-01 18:00:00. Because (21:00 - 3h = 18:00). Why 16h ?
From my understanding this result is OK as 2021-01-01 21:00:00 at UTC -5h for timezone America/New_York is equal to 2021-01-01 16:00.
Here I'm asking the same thing as the #2 but I want to discard the time of the day. So 2021-01-01 16:00:00 is 2021-01-01 00:00:00. The result is OK.
This result is still OK as 2021-01-01 21:00:00 at UTC + 12h for timezone Pacific/Wake is equal to 2021-01-02 09:00:00.
5 I'm asking the same thing as the #4 but I want to discard the time of the day. So 2021-01-02 09:00:00 is 2021-01-02 00:00:00. The result is OK.
I want to extract the unix EPOCH time in seconds of this timestamp. If I well understand, the timestamp pass to the date_part function is now a timestamp without time zone. Now if I use an online converter to convert the resulting value 1609578000 to GMT time then I'm getting 2021-01-02 9:00:00. Which is OK for me.
This is the same operation as the #6 but I want the unix epoch from the beginning of the day of that local time. The resulting value 1609545600 correspond to the GMT time 2021-01-02 00:00:00. Which is NOT correct as I should get 2021-01-02 12:00:00 as 'Pacific/Wake' is 12h past GMT.
(UPDATED)
Also why Montreal locale time is not correct here ? I'm supposed to have 2021-01-01 00:00:00-05
select ((to_timestamp(1609477200000 /1000) at time zone 'America/Asuncion') at time zone 'America/Asuncion') as asuncion
, ((to_timestamp(1609477200000 /1000) at time zone 'America/Montreal') at time zone 'America/Montreal') as montreal
asuncion | montreal
------------------------+------------------------
2021-01-01 02:00:00-03 | 2021-01-01 02:00:00-03
How could I get
asuncion | montreal
------------------------+------------------------
2021-01-01 02:00:00-03 | 2021-01-01 00:00:00-05
Is there a way to see the time WITHOUT the configured session timeszone ?
PS : My Windows OS timezone is set at America/New_York and I'm using PostgreSQL 10.
Best regards,
I can't replicate 1). I get:
set time zone 'America/Asuncion';
select to_timestamp(1609534800000 / 1000);
to_timestamp
------------------------
2021-01-01 18:00:00-03
As to 6), you did not account for the SET timezone:
select date_part('epoch', date_trunc('day', to_timestamp(1609534800000 / 1000) at TIME zone 'Pacific/Wake') at TIME zone 'Pacific/Wake');
date_part
------------
1609502400
select to_timestamp(1609502400);
to_timestamp
------------------------
2021-01-01 09:00:00-03
--What happened
select to_timestamp(1609534800000 / 1000) at TIME zone 'Pacific/Wake';
timezone
---------------------
2021-01-02 09:00:00
(1 row)
--- Note you lopped off 9 hours and the returned timestamp has no time zone offset
--- so it is now local time 'America/Asuncion'
select date_trunc('day', to_timestamp(1609534800000 / 1000) at TIME zone 'Pacific/Wake');
date_trunc
---------------------
2021-01-02 00:00:00
--- This gives it back a timezone offset.
--- Running the date_part on this then gets you the proper value.
select date_trunc('day', to_timestamp(1609534800000 / 1000) at TIME zone 'Pacific/Wake') at TIME zone 'Pacific/Wake';
timezone
------------------------
2021-01-01 09:00:00-03

How to do JOIN query on column having epoch value ignoring the time part in postgres

I have two tables lets say tableA and tableB , both the tables have a columnn creation_date having epoch value in it. I want to join these two tables on creation_date ignoring the time value in it.
Lets say if the epoch value is 1603385466134 which translates to Thu Oct 22 2020 22:21:06. Now the join should happen as Thu Oct 22 2020 00:00:00
I Tried this but not working
Select t.lr_transaction_id, t.unique_customer_id, t.transaction_id
from boidcrewardz.transaction_temp t
join boidcrewardz.transaction_dump d
on t.first_6_digit_card = d.first_6_digit_card
and t.transaction_amount = d.transaction_amount
and date_trunc('day',t.transaction_date) = date_trunc('day',d.transaction_date)
order by t.creation_date desc
Postgres 9 and later supports to_timestamp():
to_timestamp ( double precision ) → timestamp with time zone
Convert Unix epoch (seconds since 1970-01-01 00:00:00+00) to timestamp
with time zone
to_timestamp(1284352323) → 2010-09-13 04:32:03+00
Postgres 8 supports SELECT TIMESTAMP WITH TIME ZONE 'epoch' + 1603385466.134 * INTERVAL '1 second'
You just need to divide your epoch value by 1000.00 as your epoch is counting milliseconds while Postgres expects seconds.
One of the following should work:
select date_trunc('day',to_timestamp(1603385466134/1000.00));
SELECT date_trunc('day',TIMESTAMP WITH TIME ZONE 'epoch' + 1603385466134/1000.00 * INTERVAL '1 second');