How to truncate timestamp to minutes? - sql

I have to subtract 5 minutes from current timestamp and floor(truncate) it to nearest minute. Like '2016-02-23 06:10:39.0' should be '2016-02-23 06:05:00.0'.
I have found way to subtract 5 minutes as
systimestamp - interval '5' minute
EDIT 1:
I need timestamp in particular format,
TO_TIMESTAMP((systimestamp - interval '15' minute),'YYYY-MM-DD HH24:MI:SS.ff')
But this is giving
ORA-01830: date format picture ends before converting entire input string
But I am not able to floor it to nearest minute.
Please help. Thanks

You could use TRUNC() with the precision you want. To trunc only till minutes, use MI.
For example,
SQL> SELECT SYSTIMESTAMP, trunc(SYSTIMESTAMP - INTERVAL '5' MINUTE, 'MI') new_tmstmp
2 FROM dual;
SYSTIMESTAMP NEW_TMSTMP
----------------------------------- -------------------
16-MAR-16 04.44.02.379000 PM +05:30 03/16/2016 16:39:00
SQL>
Remember, the above output will be a DATE and not TIMESTAMP. You can explicitly CAST the date as timestamp:
SQL> SELECT SYSTIMESTAMP,CAST(trunc(SYSTIMESTAMP - INTERVAL '5' MINUTE,'MI') AS TIMESTAMP) tm
2 FROM dual;
SYSTIMESTAMP TM
----------------------------------- ------------------------------
16-MAR-16 04.53.25.802000 PM +05:30 2016-03-16 04:48:00.000000
SQL>

You can use trunc():
trunc(systimestamp - interval '5' minute, 'minute')

Related

Casting a specific hour and minute and getting the time difference

I have the following:
trunc(sysdate - to_timestamp(trunc(sysdate, 'YYYY-MM-DD') || ' 12:30', 'YYYY-MM-DD HH245:MI') * 1440,1)
What I'm trying to do is, using the date portion of sysdate and casting 12:30 to the time part. Then calculating the difference between sysdate#12:30 and the current sysdate.
I'm getting:
ORA-00932: inconsistent datatypes: expected NUMBER got TIMESTAMP
after the minus sign.
Any ideas?
You're getting that error because you're trying to multiply a timestamp by 1440, rather than the difference between the date and timestamp - multiplication has higher precedence than subtraction. You also have HH245 instead of HH24 in your format model; trunc(sysdate, 'YYYY-MM-DD') will throw "ORA-01898: too many precision specifiers"; and if you changed that to to_char(sysdate, 'YYYY-MM-DD') || ... you would be subtracting a timestamp from a date which gives you an interval, not a number, and would throw a different ORA-00932 error.
Fixing all of those issues, you would end up with:
trunc((sysdate - to_date(to_char(sysdate, 'YYYY-MM-DD') || ' 12:30', 'YYYY-MM-DD HH24:MI')) * 1440, 1)
which would evaluate to 354.2 for me at the moment.
You don't need to convert to or from string though. You can get 12:30 today with:
trunc(sysdate) + (12.5/24)
where trunc(sysdate) gives you midnight today, and 12.5/24 gives you the fraction of a day for 12.5 hours. You can then subtract that from the current time:
sysdate - (trunc(sysdate) + (12.5/24))
to get the difference in days, then multiple that result by 1440 for the number of minutes, and truncate to a single decimal place.
Quick demo with current date and 12:30 today plus the difference three ways:
select sysdate,
trunc(sysdate) + (12.5/24) as "12:30",
sysdate - (trunc(sysdate) + (12.5/24)) as diff_days,
(sysdate - (trunc(sysdate) + (12.5/24))) * 1440 as diff_mins,
trunc((sysdate - (trunc(sysdate) + (12.5/24))) * 1440, 1) as result
from dual;
SYSDATE 12:30 DIFF_DAYS DIFF_MINS RESULT
------------------- ------------------- ---------- ---------- ----------
2019-08-14 18:24:16 2019-08-14 12:30:00 .246018519 354.266667 354.2
As #GordonLinoff hinted, the today-at-12:30 part could be achieved with an interval instead of a fractional day, e.g.:
trunc(sysdate) + 12.5 * interval '1' hour
or more simply and explicitly:
trunc(sysdate) + interval '12:30' hour to minute
You seem to want your final result as the number of minutes, but you could also get it as an interval, either by converting the current number-of-days intermediate result (or number of minutes) with numtodsinterval():
numtodsinterval(sysdate - (trunc(sysdate) + interval '12:30' hour to minute), 'DAY')
which is a bit convoluted, or directly:
select systimestamp,
systimestamp - trunc(sysdate) - interval '12:30' hour to minute as result
from dual;
SYSTIMESTAMP RESULT
------------------------------------ -------------------
2019-08-14 18:24:16.830116000 +01:00 +00 05:54:16.830116
db<>fiddle

Last date with time of the month

Need your help to conclude the query to fetch last date time of the sysdate month.
select to_char(last_day(sysdate),'DD-Mon-YYYY HH24:MI:SS') from dual
it gives last date as expected, but I need time as 23:59:00 which is not possible thru above query.
You could use TRUNC on next day i.e. SYSDATE + 1, and then subtract 60 seconds i.e. 60/86400 to get the desired output.
SQL> SELECT to_char((trunc(last_day(sysdate)) +1) - 60/86400,'DD-Mon-YYYY HH24:MI:SS') dt
2 FROM dual;
DT
--------------------
29-Feb-2016 23:59:00
SQL>
You could also use interval '1' minute or interval '60' second instead of 60/86400.
If you just want it for display for some reason you can hard-code the time into the format mask:
select to_char(last_day(sysdate), 'DD-Mon-YYYY "23:59:00"') from dual;
But you probably really want it as a date object, in which case you can add 23 hours and 59 minutes to the truncated (midnight) date, wchi is 1439 of the 1440 minutes in a day:
select to_char(trunc(last_day(sysdate)) + 1439/1440, 'DD-Mon-YYYY HH24:MI:SS')
from dual;
Or you can go to the next day and remove a minute, either with fractional days or with intervals:
select to_char(trunc(last_day(sysdate)) + interval '1' day - interval '1' minute,
'DD-Mon-YYYY HH24:MI:SS') from dual;
Generally if you're working with time periods you want to include up to 23:59:59, which you can also do with any of those methods, but as Damien_The_Unbeliever said in a comment, it's easier to compare against the start of the next period (e.g. < add_months(trunc(sysdate, 'MM'), 1). It's easy to accidentally miss part of a day by not taking the time into account properly, particularly if you actually have a timestamp rather than a date.

Oracle database: getting time from total amount of minutes from the beginning of a day

Given - number of minutes (number oracle type) from the beginning of a day, e.g. 480. Need to get standard oracle time, e.g. - 08:00:00 AM. Is there any good functions to do such operation?
Better use INTERVAL 'minutes' MINUTE to add the number of minutes. Easy to understand.
your_date_time + INTERVAL '480' MINUTE
For example,
SQL> SELECT TRUNC(SYSDATE), TRUNC(SYSDATE) + INTERVAL '480' MINUTE tmstamp FROM dual;
TRUNC(SYSDATE) TMSTAMP
------------------- -------------------
11/19/2015 00:00:00 11/19/2015 08:00:00
In fact, another way which is independent of NLS settings when you have to pass the date as literal. Thus, instead of using TO_DATE, use the ANSI Date literal which uses a fixed format 'YYYY-MM-DD' and is NLS independent.
SQL> SELECT DATE '2015-11-19' curr_date, DATE '2015-11-19' + INTERVAL '480' MINUTE tmstamp
2 FROM dual;
CURR_DATE TMSTAMP
------------------- -------------------
11/19/2015 00:00:00 11/19/2015 08:00:00
UDPATE
Given - number of minutes (number oracle type) from the beginning of a day, e.g. 480
If the minutes value is not static in SQL to be hard-coded, but a PL/SQL variable, then as #AlexPoole mentioned you need to use NUMTODSINTERVAL.
For example,
NUMTODSINTERVAL(480, 'MINUTE')
Having said that,
The Oracle PL/SQL NUMTODSINTERVAL function converts an input number to its specified Interval Day to Second Unit equivalent. The allowed interval units can be DAY, HOUR, MINUTE, or SECOND.
The return type of the function is INTERVAL.
For example,
SQL> SELECT NUMTODSINTERVAL(480, 'MINUTE') intrvl FROM DUAL;
INTRVL
---------------------------------------------------------------------
+000000000 08:00:00.000000000
Just add minutes/1440 to the date, e.g.
select to_date('1.1.2015','dd.mm.yyyy')+480/1440 from dual;

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;

Oracle SQL - Column with unix timestamp, need dd-mm-yyyy timestamp

is there any way in Oracle, to get only the dd-mm-yyyy part from an unix timestamp in oracle?
Like:
select to_char(my_timestamp, 'ddmmyyyy') as my_new_timestamp from table
Given this data ...
SQL> alter session set nls_date_format='dd-mon-yyyy hh24:mi:ss'
2 /
Session altered.
SQL> select * from t23
2 /
MY_TIMESTAMP
--------------------
08-mar-2010 13:06:02
08-mar-2010 13:06:08
13-mar-1985 13:06:26
SQL>
.. it is simply a matter of converting the time elapsed since 01-JAN-1970 into seconds:
SQL> select my_timestamp
2 , (my_timestamp - date '1970-01-01') * 86400 as unix_ts
3 from t23
4 /
MY_TIMESTAMP UNIX_TS
-------------------- ----------
08-mar-2010 13:06:02 1268053562
08-mar-2010 13:06:08 1268053568
13-mar-1985 13:06:26 479567186
SQL>
As I understand it, A Unix timestamp is defined as a number of seconds since 1970-01-01, in which case:
select DATE '1970-01-01' + my_timestamp/86400 from table;
(There are 86400 seconds in a day.)
To ignore the hours, minutes and seconds:
select TRUNC(DATE '1970-01-01' + my_timestamp/86400) from table;
However, if what you want is a "truncated" Unix timestamp then try this:
select floor(my_timestamp/84600)*84600 from dual;
I believe it's:
select to_char(my_timestamp, 'dd-mm-yyyy') as my_new_timestamp from table
See also this reference on Oracle's date format specifiers.
Unix timestamp is seconds since Jan 01 1970. (UTC).
To get Unix timestamp of now, try the follwing sql:
select (CAST(SYS_EXTRACT_UTC(current_timestamp) AS date) - to_date('1970-01-01', 'YYYY-MM-DD')) * 86400 FROM dual;
You can replace current_timestamp with any timestamp-value.
BTW, some answers seem to return seconds since Jan 01, 1970 with local time zone. That's wrong.