Show the next half hour time point in Postgres function - sql

I am trying to create a function that shows the next half hour time.
So when the current time is 13:40, I want it to show 14:00 and not 13:30.
What I have created, gets the job done but on the nearest half hour time, not the future nearest:
CREATE OR REPLACE FUNCTION round_timestamp(
ts timestamptz
,round_secs int
) RETURNS timestamptz AS $$
DECLARE
_mystamp timestamp;
_round_secs decimal;
BEGIN
_round_secs := round_secs::decimal;
_mystamp := timestamptz 'epoch'
+ ROUND((EXTRACT(EPOCH FROM ts))::int / _round_secs) * _round_secs
* INTERVAL '1 second';
RETURN _mystamp;
END; $$ LANGUAGE plpgsql IMMUTABLE;
Any ideas on how to make this work to display the future nearest half hour interval?

To avoid tripping over on using epoch and floating point arithmetics, you can rely on date arithmetics, with the additional benefit of making it clearer what is going on:
create or replace function round_tstz(ts timestamptz)
returns timestamptz
as $$
select date_trunc('hour', $1) +
-- what hour will it be in 30 min?
case date_trunc('hour', $1 + interval '30 min')
-- the same: round to next half hour
when date_trunc('hour', $1) then interval '30 min'
-- not the same: round to next hour
else interval '1 hour'
end;
$$ language sql stable;
# select now()::timestamptz(0);
now
------------------------
2014-12-05 14:34:30+01
(1 row)
# select round_tstz(now()), round_tstz(now() + interval '30 min');
round_tstz | round_tstz
------------------------+------------------------
2014-12-05 15:00:00+01 | 2014-12-05 15:30:00+01
(1 row)

Trivially, add 1 to the rounded down epoch before scaling it back up to a timestamp:
CREATE OR REPLACE FUNCTION round_timestamp(ts timestamptz, round_secs int)
RETURNS timestamptz AS $$
BEGIN
RETURN timestamptz 'epoch'
+ (ROUND((EXTRACT(EPOCH FROM ts))::int / round_secs) + 1) * round_secs
* INTERVAL '1 second';
END; $$ LANGUAGE plpgsql IMMUTABLE;
There is no need for the local variables.

You can use ceil() (or ceiling()) and floor() to round up and down, respectively.
If your function is that simple, you can write it in LANGUAGE SQL too, which makes it more simple/readable (and plannable too by the parser):
CREATE OR REPLACE FUNCTION round_timestamp(ts timestamptz, round_secs int)
RETURNS timestamptz
LANGUAGE SQL
IMMUTABLE
AS $func$
SELECT timestamptz 'epoch'
+ ceiling(EXTRACT(EPOCH FROM ts) / round_secs)
* round_secs
* INTERVAL '1 second'
$func$;
SQLFiddle

You need to add X minutes to the current amount of minutes M in the timestamp, where:
X = 30 - M % 30 - 30 * ((M % 30)=0)::int
You subtract the remainder of the division to 30 from 30, and then only if that remainder is 0, subtract another 30, so that :00 and :30 values are kept and not rounded up as well.
For example, if the time is 14:11, then M = 11, you need to add 19 minutes to reach 14:30 (30 - 11 % 30 = 19), for 14:47, M = 47, you need to add 13 minutes to reach 15:00 (30 - 47 % 30 = 13). The only exception to that rule is the case when the remainder is 0, i.e. hours such as 14:30, 15:00, etc. - and that's where the last term in the formula comes into play - subtracting the product of 30 * (0 or 1, depending on the remainder of the division to 30).
CREATE FUNCTION round_up(timestamptz) RETURNS timestamptz AS $$
SELECT
$1 + '1 minute'::interval * (
30 - (EXTRACT('minute' FROM $1)::int % 30)
- 30 * ((EXTRACT('minute' FROM $1)::int % 30)=0)::int
);
$$ LANGUAGE sql IMMUTABLE;

Related

Calculate Difference between time in Teradata

I want to take difference of 2 date fields but both are varchar field
SyntaxEditor Code Snippet :
start_time- 2018-03-02 06:31:22
end_time - 2018-03-02 06:33:32.478000
I want the result in integer as 2 in min always and it should be an integer always
Result :- 2
It would be very great if anyone can help to achieve my case.
Thanks
You can utilize interval calculations like cast((cast(end_time as timestamp) - cast(start_time as timestamp) minute(4)) as int), but it will fail for > 9999 minutes.
This is SQL UDF for calculating the difference of timestamps in seconds without limitations:
REPLACE FUNCTION TimeStamp_Diff_Seconds
(
ts1 TIMESTAMP(6)
,ts2 TIMESTAMP(6)
)
RETURNS DECIMAL(18,6)
LANGUAGE SQL
CONTAINS SQL
RETURNS NULL ON NULL INPUT
DETERMINISTIC
SQL SECURITY DEFINER
COLLATION INVOKER
INLINE TYPE 1
RETURN
(CAST((CAST(ts2 AS DATE)- CAST(ts1 AS DATE)) AS DECIMAL(18,6)) * 60*60*24)
+ ((EXTRACT( HOUR FROM ts2) - EXTRACT( HOUR FROM ts1)) * 60*60)
+ ((EXTRACT(MINUTE FROM ts2) - EXTRACT(MINUTE FROM ts1)) * 60)
+ (EXTRACT(SECOND FROM ts2) - EXTRACT(SECOND FROM ts1))
;
If you can't create UDFs you can copy the source and apply a final / 60 and cast it as integer.

Insert UTC timestamp (millis) into Oracle timestamp column

Is there a way how to directly convert value in milliseconds (e.g. 1480515430991) to Oracle TIMESTAMP(6) column? Like some pattern I'm missing for the TO_TIMESTAMP or TO_DATE functions?
All I could find so far are some calculations with intervals and to_date('1970-01-01','YYYY-MM-DD') or other crazy "manual" calculations.
Thanks
EDIT:
Thanks guys. I didn't ask how to do the conversion though. I asked if there is a direct (native, more straightforward) way to achieve it and avoid these calculations for a given input. I am just a curious person and there are many undocumented features out there (Oracle not excluded). I guess NO is my answer then.
Correct function, i.e. include time zone consideration and milliseconds would be this one (using literals):
create or replace function epoch2timestamp(epoch number) return timestamp as
begin
return (TIMESTAMP '1970-01-01 00:00:00 UTC' + epoch/1000 * INTERVAL '1' SECOND) AT LOCAL;
end;
/
This is how to get timestamp from epoch.:
select to_timestamp('1970-01-01','yyyy-mm-dd') + ( 1 / 24 / 60 / 60 / 1000) * epoch from dual;
So in insert please insert to_timestamp('1970-01-01','yyyy-mm-dd') + ( 1 / 24 / 60 / 60 / 1000) * epoch instead of epoch. You can also create function for that:
create or replace function epoch2timestamp(epoch number) return timestamp as
begin
return to_timestamp('1970-01-01','yyyy-mm-dd') + ( 1 / 24 / 60 / 60 / 1000) * epoch;
end;
/
And then operate on function. These are not "crazy manual calculations" just a legal way of conversion.
If you want to express the unix time, the time since epoch, you need seconds, not milliseconds. See Unixtime
Oracle's datatype TIMESTAMP is in fractional seconds, as you can read in the Oracle documentation. Link zu 11g documentation
Year, month, and day values of date, as well as hour, minute, and second values of time, where fractional_seconds_precision is the number of digits in the fractional part of the SECOND datetime field. Accepted values of fractional_seconds_precision are 0 to 9.
And to answer your question: there is a TO_TIMESTAMP function. See 11g documentation
The TO_TIMESTAMP function converts text data to a value of TIMESTAMP data type.
You can use it like this
TO_TIMESTAMP('2016/11/30 15:53:18', 'YYYY/MM/DD HH:MI:SS')
and would get '30-NOV-16 15.53.18.000000000 AM'
If, for some reason, you really need to display the seconds sind epoch, you can use the noncrazy calculation
select (SYSDATE - to_date('1970-01-01', 'yyyy-MM-dd')) * 24 * 60 * 60 from dual;

Postgresql current datetime for past year

Is there a function on postgresql that will let me get the current datetime for the past year or x number of past years?
I know i can do this select now() - interval '1 year'; but in a function how can i put the number of years in a variable
x := '2 year'
Is it possible to do this select now() - interval x;
I tried but it give me error
If you want to use variable you can do this:
CREATE OR REPLACE FUNCTION func(input integer)
RETURNS TIMESTAMP WITHOUT TIME ZONE AS
$BODY$
declare
result TIMESTAMP WITHOUT TIME ZONE;
begin
select now() - (input || ' years')::interval into result;
return result;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
For the date, you would use:
select current_date - interval '1 year'
For the date/time:
select now() - interval '1 year'

Number of seconds between two dates Teradata

SELECT cast(current_date as timestamp(2));
SELECT ('1970-01-01 00:00:00' (timestamp(2)));
I Need to get the number of seconds between the current_date ,1970-01-01 00:00:00
with SQL.
These are some SQL UDFs, if you're not on TD13.10 you might just use the calculation instead:
/**********
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')
;
/**********
Difference between two Timestamps in seconds
20101211 initial version - Dieter Noeth
**********/
REPLACE FUNCTION TimeStamp_Diff_Seconds
(
ts1 TIMESTAMP(6)
,ts2 TIMESTAMP(6)
)
RETURNS DECIMAL(18,6)
LANGUAGE SQL
CONTAINS SQL
DETERMINISTIC
SQL SECURITY DEFINER
COLLATION INVOKER
INLINE TYPE 1
RETURN
(CAST((CAST(ts2 AS DATE AT 0)- CAST(ts1 AS DATE AT 0)) AS DECIMAL(18,6)) * 86400)
+ ((EXTRACT( HOUR FROM ts2) - EXTRACT( HOUR FROM ts1)) * 3600)
+ ((EXTRACT(MINUTE FROM ts2) - EXTRACT(MINUTE FROM ts1)) * 60)
+ (EXTRACT(SECOND FROM ts2) - EXTRACT(SECOND FROM ts1))
;
SELECT
TimeStamp_Diff_Seconds(TIMESTAMP '9999-12-31 23:59:59'
,TIMESTAMP '0001-01-01 00:00:00')
,TimeStamp_Diff_Seconds(CURRENT_TIMESTAMP
,TIMESTAMP '1970-01-01 00:00:00')
;

Any ways to calculate exact time between two timestamp with timezone

is there any way in oracle to calculate the difference between two time stamps value with time zones in oracle sql plus as it is not possible to use timestampdiff or datediff inside oracle.
Thanks
Just subtract them:
SQL> select (systimestamp + 1) - systimestamp from dual;
(SYSTIMESTAMP+1)-SYSTIMESTAMP
---------------------------------------------------------------------------
+000000000 23:59:59.884789
Consider the following in case you need the number of milliseconds between two timestamps:
create or replace Function msecBetween
(ts1 timestamp with time zone,
ts2 timestamp with time zone,
numDec number default 0
)
Return Number is
i INTERVAL DAY(3) TO SECOND(3) := ts2 - ts1;
Begin
return round (
+ extract( day from i )*24*60*60*1000
+ extract( hour from i )*60*60*1000
+ extract( minute from i )*60*1000
+ extract( second from i )*1000
, numDec);
End;