hour() function of excel in postgres (equivalent) - postgresql

I am working recently with postgres and I have to make several calculations. However I have not been able to imitate the HOUR () function of Excel, I read the official information but it did not help me much.
The function receives a decimal and obtains the hour, minutes and seconds of the same, example the decimal 0,99988426 returns 11:59:50. Try doing this in postgres (i use PostgreSQL 10.4) with the to_timestamp function: select to_char (to_timestamp (0.99988426), 'HH24: MI: SS'); this return 19:00:00. Surely I am omitting something, some idea of how to solve this?

24:00:00 or 86400 seconds = 1
Half day(12:00 noon) or 43200 seconds = 43200/86400 = 0.5
11:59:50 or 86390 seconds = 86390/86400 = 0.99988426
So to convert your decimal value to time, all you have to do is multiply it with 86400 which will give you seconds and convert it to your format in following ways:
SELECT TO_CHAR((0.99988426 * 86400) * '1 second'::interval, 'HH24:MI:SS');
SELECT (0.99988426 * 86400) * interval '1 sec';

There are two major differences to handle:
Excel does not consider the time zone. The serial date 0 starts at 0h00, but Postgres uses the time zone so it becomes 19h. You would need to use UTC in Postgres result to have the same as in Excel.
select to_char (to_timestamp (0), 'HH24: MI: SS'),to_char (to_timestamp (0) AT TIME ZONE 'UTC', 'HH24: MI: SS');
to_char | to_char
------------+------------
19: 00: 00 | 00: 00: 00
Excel considers that 1 is one day, while Postgres considers 1 as 1 second. To get the same behavior, multiply your number by the 86400, i.e. the number of seconds in a day
select to_char (to_timestamp (0.99988426*86400) AT TIME ZONE 'UTC', 'HH24: MI: SS');
to_char
------------
23: 59: 50
(1 row)

Related

Postgres generate date series with exactly 100 steps

Lets say we have the dates
'2017-01-01'
and
'2017-01-15'
and I would like to get a series of exactly N timestamps in between these dates, in this case 7 dates:
SELECT * FROM
generate_series_n(
'2017-01-01'::timestamp,
'2017-01-04'::timestamp,
7
)
Which I would like to return something like this:
2017-01-01-00:00:00
2017-01-01-12:00:00
2017-01-02-00:00:00
2017-01-02-12:00:00
2017-01-03-00:00:00
2017-01-03-12:00:00
2017-01-04-00:00:00
How can I do this in postgres?
Possibly this can be useful, using the generate series, and doing the math in the select
select '2022-01-01'::date + generate_series *('2022-05-31'::date - '2022-01-01'::date)/15
FROM generate_series(1, 15)
;
output
?column?
------------
2022-01-11
2022-01-21
2022-01-31
2022-02-10
2022-02-20
2022-03-02
2022-03-12
2022-03-22
2022-04-01
2022-04-11
2022-04-21
2022-05-01
2022-05-11
2022-05-21
2022-05-31
(15 rows)
WITH seconds AS
(
SELECT EXTRACT(epoch FROM('2017-01-04'::timestamp - '2017-01-01'::timestamp))::integer AS sec
),
step_seconds AS
(
SELECT sec / 7 AS step FROM seconds
)
SELECT generate_series('2017-01-01'::timestamp, '2017-01-04'::timestamp, (step || 'S')::interval)
FROM step_seconds
Conversion to function is easy, let me know if have trouble with it.
One problem with this solution is that extract epoch always assumes 30-days months. If this is problem for your use case (long intervals), you can tweak the logic for getting seconds from interval.
You can divide the difference between the end and the start value by the number of values you want:
SELECT *
FROM generate_series('2017-01-01'::timestamp,
'2017-01-04'::timestamp,
('2017-01-04'::timestamp - '2017-01-01'::timestamp) / 7)
This could be wrapped into a function if you want to avoid repeating the start and end value.

PostgreSQL query for elapsed interval

I am trying to query PostgreSQL database for rows where interval has elapsed from the last run. Main columns for this purpose are processed_at as timestamptz and frequency (in minutes) as integer.
I am failing with operators, since not many of them can operate together timestamp & integer.
Can someone please propose a query that would solve this? Thank you very much for help
From here Date/time operators:
timestamp + interval → timestamp
Add an interval to a timestamp
timestamp '2001-09-28 01:00' + interval '23 hours' → 2001-09-29 00:00:00
select now() + (10::varchar || ' min')::interval;
?column?
-------------------------------
2021-10-15 09:05:37.927163-07
--Or in your case. If I'm following you are adding the interval.
select processed_at + (frequency::varchar || ' min')::interval;
The query takes the integer value of minutes and converts it to an interval of minutes that can be added to the timestamp.
Further explanation, || is the Postgres concatenation operator and ::varchar, ::interval are casting shorthand.
UPDATE
I keep forgetting about the make_*() functions for date/time/interval
--A shorter version
select processed_at + make_interval(mins => frequency);
Saves all the casting.

PostgreSQL: Date Difference with fractions

SELECT cu.user_id, cu.last_activity, cu.updated_time,
DATE_PART('day', cu.last_activity - cu.updated_time), to_char(end_date - start_date, 'DD.HH24')
FROM stats.core_users cu
WHERE cu.user_id = '117132014' or cu.user_id = '117132012';
Get the result like:
117132014 2017-12-11 10:34:51.349905 2017-12-09 12:00:38.503518 1 01.22
117132012 2017-12-11 05:18:20.312283 2017-12-08 15:46:51.914085 2 02.13
Is is feasible to get the day difference with fractions like 1.91 days in the first case, instead of 1 days and 22 hours, to be more precise and easier to fit in a machine learning model?
date_part() does what it's name says: it returns one part of several elements from a date, interval or timestamp. In your case it's one part of an interval (because timestamp - timestamp returns an interval).
If you want the result as a fraction, you need to extract the seconds of the interval and then divide that by 86400 (which is the number of seconds in a day)
extract(epoch from cu.last_activity - cu.updated_time) / 86400

PostgreSQL difference between two dates and return in hours and minutes

Hello I want to return in my PostgreSQL the difference between two dates:
START: 2016-06-01 00:00:00
END: 2016-06-06 08:35:33
Expected return value: 128:35:33, formatted like format [h]:mm:ss;# in Excel. Hours must be added up if there is more than 24 hours of difference.
Here's my SQL:
SELECT EXTRACT(EPOCH FROM dt_termino::timestamp - dt_inicio::timestamp)/3600 FROM crm.task_interacao WHERE id_task_tarefa = 1
UPDATE!!!
hello now i'm facing another problema I have a table like this:
my table in database like this
start;end
2013-06-01 09:29:33;2016-06-07 14:08:19
2016-06-07 14:22:09;2016-06-07 14:22:43
2016-06-07 14:22:51; null
i need to sum values ....i'm trying as you said (1st awnser).. I cant use function because i'm using inside a php code
SELECT SUM(COALESCE(end::timestamp, now()::timestamp) - start::timestamp) FROM crm.task_interacao WHERE id_task_tarefa = 1
but is returning
1102 days 26:07:54.864879
why 26 hours??? I was supose be te at maximum 24...
no problem now to return (Days HH:MM:SS) and not miliseconds
You can simply subtract timestamps to get interval:
select '2016-06-06 08:35:33'::timestamp- '2016-06-01 00:00:00' result
result
-----------------
5 days 08:35:33
(1 row)
There is no standard function to convert the result to the format you need but you can write one:
create or replace function interval_without_days(interval)
returns interval language sql as $$
select $1- date_part('day', $1)* '1d'::interval+ date_part('day', $1)* '24h'::interval;
$$;
select interval_without_days('2016-06-06 08:35:33'::timestamp- '2016-06-01 00:00:00');
interval_without_days
-----------------------
128:35:33
(1 row)
Question #2. Use the functions date_trunc(text, interval) and justify_hours(interval):
select date_trunc('sec', justify_hours('1102 days 26:07:54.864879'));
date_trunc
--------------------
1103 days 02:07:54
(1 row)

How to convert a column in seconds to dateformat in Teradata?

I have a column which is of bigint datatype(in seconds) which should be added to a date, so i need to convert this column into dateformat.
The arithmetic must be done against a timestamp data type in Teradata. The date data type does not have a time element associated with it. The following SQL should help point you in the right direction:
SELECT CAST(CAST(1234 AS BIGINT) AS INTERVAL SECOND(4)) AS Seconds_
, CURRENT_TIMESTAMP(0) AS CurrentTimestamp_
, CURRENT_TIMESTAMP + Seconds_ AS NewTimeStamp
If the number of seconds is less than 864000000 you can simply use interval arithmetic:
CAST(col AS TIMESTAMP) + (bigintcol * INTERVAL '0000 00:00:01' DAY TO SECOND)
Based on your other question your input is a Unixtime, those are two functions for converting them from/to Teradata timestamps:
/**********
Converting Unix/POSIX time to a Timestamp
Unix time: Number of seconds since 1970-01-01 00:00:00 UTC not counting leap seconds (currently 24 in 2011)
Also working for negative numbers.
The maximum range of Timestamps is based on the range of INTEGERs:
1901-12-13 20:45:52 (-2147483648) to 2038-01-19 03:14:07 (2147483647)
Can be changed to use BIGINT instead of INTEGER
20101211 initial version - Dieter Noeth
**********/
REPLACE FUNCTION UnixTime_to_TimeStamp (UnixTime INT)
RETURNS TimeStamp(0)
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC
SQL SECURITY DEFINER
COLLATION INVOKER
INLINE TYPE 1
RETURN
CAST(DATE '1970-01-01' + (UnixTime / 86400) AS TIMESTAMP(0))
+ ((UnixTime MOD 86400) * INTERVAL '00:00:01' HOUR TO SECOND)
;
SELECT
UnixTime_to_TimeStamp(-2147483648)
,UnixTime_to_TimeStamp(0)
,UnixTime_to_TimeStamp(2147483647)
;
/**********
Converting a Timestamp to Unix/POSIX time
Unix time: Number of seconds since 1970-01-01 00:00:00 UTC not counting leap seconds (currently 24 in 2011)
The maximum range of Timestamps is based on the range of INTEGERs:
1901-12-13 20:45:52 (-2147483648) to 2038-01-19 03:14:07 (2147483647)
Can be changed to use BIGINT instead of INTEGER
20101211 initial version - Dieter Noeth
**********/
REPLACE FUNCTION TimeStamp_to_UnixTime (ts TimeStamp(6))
RETURNS INTEGER
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC
SQL SECURITY DEFINER
COLLATION INVOKER
INLINE TYPE 1
RETURN
(CAST(ts AS DATE) - DATE '1970-01-01') * 86400
+ (EXTRACT(HOUR FROM ts) * 3600)
+ (EXTRACT(MINUTE FROM ts) * 60)
+ (EXTRACT(SECOND FROM ts))
;
SELECT
TimeStamp_to_UnixTime(TIMESTAMP '1901-12-13 20:45:52')
,TimeStamp_to_UnixTime(CURRENT_TIMESTAMP)
,TimeStamp_to_UnixTime(TIMESTAMP '2038-01-19 03:14:07')
;