Number of seconds between two dates Teradata - sql

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')
;

Related

Timestamp conversion to EPOCH time in Oracle SQL

I have input date as a column in table "22/03/2022 06:59:59"
I need to convert into EPOCH time -
Expected output- "1647932399" timezone(jakarta, Indonesia)
reference link- https://www.epochconverter.com/
time zone of input data is - UTC +7:00(Jakarta)
Tried with this-SQL CODE
SELECT (CAST(SYS_EXTRACT_UTC(to_timestamp('22/03/2022 06:59:59','dd/mm/yyyy HH:MI:SS' )) AS DATE) - TO_DATE('01/01/1970','DD/MM/YYYY')) * 24 * 60 * 60 FROM DUAL;
Result displayed is 1647907199
But didn't get the expected output
1647932399 is the epoch for 2022-03-22 06:59:59 UTC. Your start time is 22-03-22 06:59:59 Asia/Jakarta, which is 22-03-21 23:59:59 UTC, and the epoch for that is 1647907199 - which is what you're getting. So your result is correct; but risky.
You are relying on implicit conversion.
to_timestamp('22/03/2022 06:59:59','dd/mm/yyyy HH:MI:SS') gives you a plain timestamp, with no time zone information. When you then do SYS_EXTRACT_UTC(...) the plain timestamp is implicitly converted to a timestamp with time zone using your session time zone - which happens to be Jakarta, it seems. So it works - for you, in this session. If you change your session time zone, or more likely if someone else runs the same code from a session with a different time zone, then the reslut will be different.
To be more explicit, you can convert your string to a plain timestamp, then declare that it represents a Jakarta time, and then convert that to UTC:
sys_extract_utc(from_tz(to_timestamp('22/03/2022 06:59:59', 'DD/MM/YYYY HH24:MI:SS'), 'Asia/Jakarta'))
21-MAR-22 23.59.59.000000000 UTC
There are then basically two ways to convert that to an epoch number; either cast it to a date, subtract 1970-01-01 as a date, and manipulate the resulting number of days (as in your question):
select
round(
(
cast(
sys_extract_utc(from_tz(to_timestamp('22/03/2022 06:59:59', 'DD/MM/YYYY HH24:MI:SS'), 'Asia/Jakarta'))
as date)
- date '1970-01-01'
) * 24 * 60 * 60
) as result
from dual;
1647907199
Or leave it as a timestamp, subtract 1970-01-01 as a timestamp, and manipulate the resulting interval:
select
(extract(day from diff) * 24 * 60 * 60)
+ (extract(hour from diff) * 60 * 60)
+ (extract(minute from diff) * 60)
+ extract(second from diff)
as result
from (
select sys_extract_utc(from_tz(to_timestamp('22/03/2022 06:59:59', 'DD/MM/YYYY HH24:MI:SS'), 'Asia/Jakarta'))
- timestamp '1970-01-01 00:00:00' as diff
from dual
);
1647907199
Note that either way you can easily get the short result that was the basis for your previous question, by truncating the number or extracting just the days, without explicitly subtracting the 23:59:59 part. Either gives you 19072.
db<>fiddle

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.

Show the next half hour time point in Postgres function

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;

Convert milliseconds to Timestamp

I know that to convert a Unix timestamp in milliseconds to an SQL timestamp I can use
SELECT TO_DATE('1970-01-01','YYYY-MM-DD HH24:MI:SS') +
(:timestamp / (1000*60*60*24)) FROM DUAL;
But I need a Timestamp, so I tried with
SELECT TO_TIMESTAMP('1970-01-01 00:00:00','YYYY-MM-DD HH24:MI:SSFF3') +
(:timestamp) from DUAL
Which gives me the error:
Error: ORA-01841: (full) year must be between -4713 and +9999, and not be 0
It seems that adding 1 to the timestamp always converts it to a day.
How can I do the same to get a real timestamp?
You will get a timestamp if you add an interval to a timestamp (see date/interval arithmetics).
As Benoit noticed, you can't specify an interval with seconds when there are more than about 2.1e9 of them:
SQL> SELECT numtodsinterval(2.2e9, 'SECOND'),
2 numtodsinterval(2.3e9, 'SECOND')
3 FROM dual;
NUMTODSINTERVAL(2.2E9,'SECOND' NUMTODSINTERVAL(2.3E9,'SECOND'
------------------------------- -------------------------------
+000024855 03:14:07.147483647 +000024855 03:14:07.147483647
This is why you should use minutes which do not lose precision. For example, assuming :TS is the unix timestamp (i.e. a number):
SQL> variable ts number;
SQL> -- determining unix timestamp with nanosecond precision
SQL> BEGIN
2 :ts := (to_date('2099-01-01 01:02:03', 'yyyy-mm-dd hh24:mi:ss')
3 - date '1970-01-01') * 1000*60*60*24
4 + 123.456789;
5 END;
6 /
ts
---------
4070912523123,456789
SQL> select timestamp '1970-01-01 00:00:00'
2 + numtodsinterval((:ts)/1000/60, 'MINUTE')
3 from dual;
TIMESTAMP'1970-01-0100:00:00'+NUMTODSINTERVAL((:TS)/1000/60,'MINUTE')
---------------------------------------------------------------------------
2099-01-01 01:02:03.123456789
There are two types:
Timestamps
Intervals
Intervals is what you get when you subtract timestamps, and it is nonsensical to add timestamps together.
If you need to get a millisecond interval, I would suggest to use a second interval and divide it by 1000:
I could suggest:
SELECT timestamp'1970-01-01 00:00:00' + (interval '1888' second(9) / 1000)
FROM dual
The problem here is that you cannot use more than 9 digits in a same timestamp literal.
If you need to ad 2,061,464,797,255 milliseconds to the epoch I can suggest:
SELECT TIMESTAMP'1970-01-01 00:00:00'
+ INTERVAL '2' SECOND(9) * 1000000000
+ INTERVAL '061464797' SECOND(9)
+ INTERVAL '255' SECOND(3) / 1000
FROM dual
You get 2035-04-29 13:06:37.255000000
It seems to be subject to the 2038 bug: TIMESTAMP'1970-01-01 00:00:00' + 3 billion seconds does not work, whereas it works with 2 billion.
I've posted here some methods to convert nanoseconds to timestamp and timestamp to nanoseconds. These methods are not affected by time zones and have a nanosecond precision.
You just need to adjust it to use milliseconds instead of nanoseconds.
SELECT TIMESTAMP '1970-01-01 00:00:00 UTC' + numtodsinterval(
1598434427263 --Replace line with desired milliseconds
/ 1000, 'SECOND') AS TIMESTAMP FROM dual;
TIMESTAMP
26/08/20 09:33:47,263000000 UTC
Use
SELECT TIMESTAMP '1970-01-01 00:00:00.1234' + INTERVAL '1 00:00:00' DAY TO SECOND
AS ts
FROM dual;

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;