start/end date and time in oracle sql query - sql

I need a query output like the below table;
This is a primary entry to a table and these records will be modified by a third party program which I have no control. Can anyone suggest a good sample?
ID | DATEIN | DATEOUT | STATUS
1 02.02.2014 00:00:00 02.02.2014 23:59:59 1
2 03.02.2014 00:00:00 03.02.2014 23:59:59 0
I tried
SELECT To_Char(To_Date(SYSDATE), 'dd-MM-yyyy hh:mm:ss PM'),
To_Char(date_add(To_Date(SYSDATE +1), INTERVAL -1 SECOND), 'dd-MM-yyyy hh:mm:ss PM')
FROM dual
but this query throws an error ORA-00907: missing right parenthesis.

There is no need for PM if you want it to be in 24-hour format. And pay attention to the mask for minutes, it is mi, not mm as in your query. Also as already mentioned no need to convert SYSDATE to date as it is already of that datatype:
SELECT to_char(to_date(SYSDATE), 'dd-mm-yyyy HH24:mi:ss') date_in,
to_char(to_date(SYSDATE + 1) - INTERVAL '1' SECOND, 'dd-mm-yyyy HH24:mi:ss') date_out
FROM dual;
DATE_IN DATE_OUT
------------------- -------------------
11-03-2014 00:00:00 11-03-2014 23:59:59

You can do away with DATE_ADD and TO_DATE functions (SYSDATE is already a DATE, no need of conversion ) , and also use mi to show minute instead of mm which is format specifier for month as in:
SELECT To_Char(SYSDATE, 'dd-MM-yyyy hh:mi:ss PM'),
To_Char((SYSDATE + 1) + INTERVAL '-1' SECOND, 'dd-MM-yyyy hh:mi:ss PM')
FROM dual

I am not clear what you are trying to achieve from the above query but if parenthesis is your only problem then you gotta hit the query:
SELECT To_Char(To_Date((SYSDATE), 'dd-MM-yyyy hh:mm:ss PM')),
To_Char(date_add(To_Date(SYSDATE +1), INTERVAL -1 SECOND), 'dd-MM-yyyy hh:mm:ss PM')
FROM dual

Related

sysdate range to whole value

Is it possible to turn the current time stamp to a whole number?
Example: If sysdate returns 1/19/2022 5:36:49 PM can I turn that to 1/19/2022 5PM since it falls in the 5PM range.
Here is my query
Select FACILITY, TRK_ID, LOT_DTTM, IN_QTY
from TRK_ID_LOT
WHERE facility in 'DP1DM5'
and trk_id like ('AE%')
and lot_dttm > sysdate - 1
EXAMPLE:
Truncate it to hours:
SQL> select trunc(to_date('1/19/2022 5:36:49 PM', 'mm/dd/yyyy hh:mi:ss pm'), 'hh') res
2 from dual;
RES
----------------------
01/19/2022 05:00:00 PM
SQL>
If you want to update rows, do so using the same function:
update your_table set
date_column = trunc(date_column, 'hh');

Oracle SQL time difference in HH:MM:SS

I am trying to get time difference in Oracle database. The time difference for all the rows is okay except for one row. Here is the query
SELECT MAX(REGEXP_SUBSTR (CAST(TO_DATE(call_end, 'YYYY/MM/DD HH24:MI:SS') AS TIMESTAMP) - CAST(TO_DATE(call_start, 'YYYY/MM/DD HH24:MI:SS') AS TIMESTAMP), '\d{2}:\d{2}:\d{2}')) AS call_time
FROM calls
The time difference occurs with the following row:
call_end: '2020-02-20 13:00:20'
call_start: '2020-02-20 12:56:03'
The returned result is '11:55:43' which is wrong. As the correct answer should be '00:04:17'
It looks like your table already stores the call start/end times as dates, and you're doing an implicit conversion from date to string, then converting back to a date. You can see that result if you have HH instead of HH24 in your NLS_DATE_FORMAT setting:
alter session set nls_date_format = 'YYYY-MM-DD HH:MI:SS';
with calls (call_end, call_start) as (
select cast(timestamp '2020-02-20 13:00:20' as date), cast(timestamp '2020-02-20 12:56:03' as date) from dual
)
SELECT MAX(REGEXP_SUBSTR (CAST(TO_DATE(call_end, 'YYYY/MM/DD HH24:MI:SS') AS TIMESTAMP) - CAST(TO_DATE(call_start, 'YYYY/MM/DD HH24:MI:SS') AS TIMESTAMP), '\d{2}:\d{2}:\d{2}')) AS call_time
FROM calls;
CALL_TIME
---------------------------
11:55:43
When you do
TO_DATE(call_end, 'YYYY/MM/DD HH24:MI:SS')
because it's already a date you're really doing:
TO_DATE(TO_CHAR(call_end, <NLS_DATE_FORMAT>), 'YYYY/MM/DD HH24:MI:SS')
so with my setting (and yours must be similar, maybe with slashes instead of dashes) that is:
TO_DATE(TO_CHAR(call_end, 'YYYY-MM-DD HH:MI:SS'), 'YYYY/MM/DD HH24:MI:SS')
and the mismatch between HH and HH24 becomes more obvious. So, you're actually converting the strings 2020-02-20 01:00:20 and 2020-02-20 12:56:03 back to dates, and the time difference between 01:00:20 and 12:56:03 is 11:55:43. Well - actually, it is minus 11 hours:
SELECT CAST(TO_DATE(call_end, 'YYYY/MM/DD HH24:MI:SS') AS TIMESTAMP) - CAST(TO_DATE(call_start, 'YYYY/MM/DD HH24:MI:SS') AS TIMESTAMP)
FROM calls;
CAST(TO_DATE(CALL_E
-------------------
-00 11:55:43.000000
but your regex isn't picking that up.
As they are dates skip that part of the conversion completely, and just cast directly to timestamps if you want intervals to work from:
SELECT MAX(REGEXP_SUBSTR (CAST(call_end AS TIMESTAMP) - CAST(call_start AS TIMESTAMP), '\d{2}:\d{2}:\d{2}')) AS call_time
FROM calls;
CALL_TIME
---------------------------
00:04:17
or use a substring instead of a regex, as #MTO showed.
You could also leave them as dates, get the difference as a fraction of a day, add that back to any nominal date at midnight, and then convert the resulting date to a string:
SELECT TO_CHAR(date '2000-01-01' + MAX(call_end - call_start), 'HH24:MI:SS') AS call_time
FROM calls;
CALL_TIM
--------
00:04:17
This won't work properly for a call that lasts more than 24 hours (used to see that a lot with modem calls, but can still happen); but neither will your interval approach. Both ignore any full days and just show the remainder. There are ways to handle that of course, but you'd need to decide how you want to display it - with separate day count (like interval does anyway), or with the 'hours' number allowed to go above 24... but then you may go above 99 hours...
Your question shows the call end time as 2020-02-20 13:00:20, which suggests that's how your client is displaying it when you query the table. Some clients (I think PL/SQL Developer, but not sure, it's been a while) use their own preferences/settings instead of honouring the session's NLS settings. But that has no effect on how Oracle behaves internally when it has to do implicit conversions.
I'm not sure if you want the result as an interval or timestamp, but this should do what you want:
select t.*, call_end - call_start,
substr(to_char(call_end - call_start, 'HH24:MI:SS'), 12, 8) as str from (select timestamp '2020-02-20 13:00:20.000' as call_end,
timestamp '2020-02-20 12:56:03.000' as call_start
from dual) t
Here is a db<>fiddle.
Assuming your data types are strings (you really should store them as DATE data types), you can use:
SELECT SUBSTR(
MAX(
( TO_DATE( call_end, 'YYYY-MM-DD HH24:MI:SS' )
- TO_DATE( call_start, 'YYYY-MM-DD HH24:MI:SS' )
) DAY(1) TO SECOND
),
4,
8
) AS call_time
FROM calls
If they are already DATE data types then, in the MAX aggregation, just use:
( call_end - call_start ) DAY(1) TO SECOND
So for your data:
CREATE TABLE calls ( call_end, call_start ) AS
SELECT '2020-02-20 13:00:20', '2020-02-20 12:56:03' FROM DUAL
This outputs:
| CALL_TIME |
| :-------- |
| 00:04:17 |
db<>fiddle here
Mr Gyl, You can as well do: db <> fiddle :This solution will also consider when the call has lapsed over days by adding those hours together:
WITH da AS (
SELECT
NUMTODSINTERVAL(TO_DATE('2020-02-20 13:00:20', 'yyyy-mm-dd hh24:mi:ss') - TO_DATE('2020-02-20 12:56:03', 'yyyy-mm-dd hh24:mi:ss'), 'DAY') AS call_diff
FROM
dual ) SELECT
EXTRACT( DAY FROM call_diff )*24 + EXTRACT( HOUR FROM call_diff )|| ':' || EXTRACT( MINUTE FROM call_diff ) || ':' || EXTRACT( SECOND FROM call_diff ) DIFFERENCE
FROM
da
DIFFERENCE|
----------|
0:4:17 |
So you can implement as
WITH da AS (
SELECT
NUMTODSINTERVAL(TO_DATE(call_end, 'yyyy-mm-dd hh24:mi:ss') - TO_DATE(call_start, 'yyyy-mm-dd hh24:mi:ss'), 'DAY') AS call_diff
FROM
calls
) SELECT
EXTRACT( DAY FROM call_diff )*24 + EXTRACT( HOUR FROM call_diff )|| ':' || EXTRACT( MINUTE FROM call_diff ) || ':' || EXTRACT( SECOND FROM call_diff ) TIMESTAMP
FROM
da
Please see below response but this will only work within 24hrs and returns both '00'
WITH sample_lt AS(
SELECT '2020-02-20 12:56:03' START_TIME, '2020-02-20 13:00:20' END_TIME FROM dual
)
SELECT start_time,
end_time,
TO_CHAR (TRUNC (SYSDATE) + (to_date(end_time, 'yyyy-mm-dd HH24:MI:SS') -
to_date(start_time, 'yyyy-mm-dd HH24:MI:SS')
) , 'hh24:mi:ss' ) duration
FROM sample_lt ;

How to compare date with time in oracle

Trying to compare two dates with time.But comparison is not working.
SELECT *
FROM attendance
WHERE TO_DATE (checktime, 'DD/MM/YYYY HH:MI:SS AM') >=
TO_DATE ('01/09/2019 04:30:00 PM', 'DD/MM/YYYY HH:MI:SS AM')
AND TO_DATE (checktime, 'DD/MM/YYYY HH:MI:SS AM') <=
TO_DATE ('30/09/2019 10:00:00 PM', 'DD/MM/YYYY HH:MI:SS AM')
AND userid = '3825'
AND SUBSTR (checktime, -2, 2) = 'PM'
ORDER BY TO_DATE (checktime, 'DD/MM/YYYY HH:MI:SS AM') ASC
I was expecting output equal or grater then 04:30 PM and less then or equal 10:00 PM.But this date comparison is not working.Here is the
Output of Code.I want my result includes date and time between mentioned periods.
Note:CHECKTIME datatype is varchar2.
I think you need data for all the days(01/09/2019 - 30/09/2019) and the time of the day should be between 04:30 PM and 10: PM.
You can achieve this using the following query:
SELECT
*
FROM
ATTENDANCE
WHERE
TRUNC(TO_DATE(CHECKTIME, 'DD/MM/YYYY HH:MI:SS AM'))
BETWEEN TO_DATE('01/09/2019', 'DD/MM/YYYY')
AND TO_DATE('30/09/2019', 'DD/MM/YYYY')
AND ( TO_DATE(CHECKTIME, 'DD/MM/YYYY HH:MI:SS AM') - TRUNC(TO_DATE(CHECKTIME, 'DD/MM/YYYY HH:MI:SS AM')) ) * 1440 -- converting difference into minutes
BETWEEN 990 -- 04:30 PM in minutes (16.5*60)
AND 1320 -- 10:00 PM in minutes (22*60)
AND USERID = '3825'
AND SUBSTR(CHECKTIME, - 2, 2) = 'PM'
ORDER BY
TO_DATE(CHECKTIME, 'DD/MM/YYYY HH:MI:SS AM') ASC;
Cheers!!
You can fix your format by using such a format containing TO_TIMESTAMP conversion
SELECT *
FROM attendance
WHERE checktime
BETWEEN TO_TIMESTAMP('01/09/2019 16:30:00.000000','dd/mm/yyyy hh24:mi:ss.ff')
AND TO_TIMESTAMP('30/09/2019 22:30:00.000000','dd/mm/yyyy hh24:mi:ss.ff')
AND userid = 3825
ORDER BY checktime;
Demo
EDIT : you had better to add a new column with timestamp datatype, and update your new column's data by using TO_TIMESTAMP conversion such as below :
UPDATE attendance
SET checktime2 = TO_TIMESTAMP('3/09/2019 5:38:36 PM','dd/mm/yyyy hh:mi:ss AM')
WHERE id = 3825
AND checktime = '3/09/2019 5:38:36 PM'

Calculate time difference ignorning non-work hours

I am trying to calculate the difference between 2 datetime values where non-work hours are ignored. Originally it just looked at the difference and calculated it as minutes however It needs to count only hours between 9am and 8pm Monday to Friday and 9am - 1pm Saturday, ignoring all other times. I am on an oracle 10g system.
my code as it currently stands is as follows:
begin
debug.debug('sp_access');
update cl_case b
set time_to_sp_access =
(
select (x.date_created-e.date_created)*1440
from cl_case c, eventlog e, eventlog x
where c.id=e.case_id
and x.case_id=e.case_id
and b.id=e.case_id
and e.id=
( select min(id) from eventlog mini
where mini.case_id=e.case_id
and mini.cl_code in ('AAAA','BBBB','CCCC','DDDD')
)
and x.id=
( select min(id) from eventlog minix
where minix.case_id=e.case_id
and minix.cl_code in ('EEEE','FFF','GGG','HHHH','JJJJ','KKKK','LLLL')
)
)
where id in
( select unique case_id
from eventlog elog
where elog.sptime_needs_setting ='Y'
);
commit;
end sp_access;
How can I get this to count time between specified hours?
thanks
You could use a CASE expression in the WHERE clause. Since there are two datetime values, you need to use two case expressions.
For example, the CASE expression would evaluate as:
SQL> SELECT
2 CASE
3 WHEN TO_CHAR(SYSDATE, 'DY') BETWEEN '1' AND '5'
4 THEN TO_DATE(TO_CHAR(TRUNC(SYSDATE), 'MM/DD/YYYY')
5 ||' 08:00:00 PM', 'MM/DD/YYYY HH:MI:SS PM')
6 ELSE TO_DATE(TO_CHAR(TRUNC(SYSDATE), 'MM/DD/YYYY')
7 ||' 01:00:00 PM', 'MM/DD/YYYY HH:MI:SS PM')
8 END my_time
9 FROM dual;
MY_TIME
----------------------
11/24/2015 01:00:00 pm
The above example check the DAY for SYSDATE, and depending on it returns a datetime value.
using the above example, since you have two different datetime values to be compared as a date range condition, you will need two CASE expressions in your WHERE clause.
WHERE date_column
BETWEEN
CASE
WHEN TO_CHAR(date_column, 'DY') BETWEEN '1' AND '5'
THEN
TO_DATE(TO_CHAR(
TRUNC(date_column), 'MM/DD/YYYY')
||' 09:00:00 AM', 'MM/DD/YYYY HH:MI:SS PM')
ELSE
TO_DATE(TO_CHAR(
TRUNC(date_column), 'MM/DD/YYYY')
||' 09:00:00 AM', 'MM/DD/YYYY HH:MI:SS PM')
END
AND
CASE
WHEN TO_CHAR(date_column, 'DY') BETWEEN '1' AND '5'
THEN
TO_DATE(TO_CHAR(
TRUNC(date_column), 'MM/DD/YYYY')
||' 08:00:00 PM', 'MM/DD/YYYY HH:MI:SS PM')
ELSE
TO_DATE(TO_CHAR(
TRUNC(date_column), 'MM/DD/YYYY')
||' 01:00:00 PM', 'MM/DD/YYYY HH:MI:SS PM')
END

Oracle Timestamp Conversion with Dates

Assuming this has a simple solution, but I can't find it.
I'm trying to do some logic on a DATE field in Oracle. My desire is to take a DATE field and subtract X hours from it.
For instance: SELECT A.MyDATE - 100 Hours from dual;
however, I need a result in a timestamp format 'YYYY-MM-DD hh:mm'.
I've tried CAST(A.MyDATE as TIMESTAMP) - NUMTODSINTERVAL(100/24,'day') however it didn't work.
I found out that the issue is that the MyDATE field when cast to a timestamp still contained some residual time elements. How can I reset these??
Thanks!
You can just do this with subtraction:
select a.MyDate - 100.0/24
To convert to varchar:
select to_char(a.MyDate - 100.0/24, 'YYYY-MM-DD')
And, if you want to get rid of that pesky time on the date:
select trunc(a.MyDate - 100.0/24) as JustTheDate
The formats and dates in my example can be changed to any other formats and dates:
SELECT To_Timestamp(To_Char(Sysdate - INTERVAL '100' HOUR, 'MM/DD/YYYY HH24:MI'), 'MM/DD/YYYY HH24:MI')
FROM dual
/
Output:
2/4/2013 10:18:00.000000000 AM
To remove time element add Trunc() to any of your dates...:
SELECT Trunc(To_Timestamp(To_Char(Sysdate - INTERVAL '100' HOUR, 'MM/DD/YYYY HH24:MI'), 'MM/DD/YYYY HH24:MI'))
FROM dual
/
Output: 2/4/2013
Conversion/Casting - when using other dates in place of sysdate then add formats as in my other examples:
SELECT CAST(SYSDATE AS TIMESTAMP) - INTERVAL '100' HOUR FROM dual
/
Output: 2/4/2013 10:26:35.000000000 AM
SELECT start_date tstamp_to_date, CAST(start_date AS timestamp) date_to_tstamp FROM
(
SELECT to_date(to_char(to_timestamp ('2013-02-07 10:07:47.000' , 'YYYY-MM-DD HH24:MI:SS.FF'),'DD-MON-YYYY HH24:MI:SS'), 'DD-MON-YYYY HH24:MI:SS') start_date
FROM dual
)
/
Output:
tstamp_to_date date_to_tstamp
-------------------------------------------------------
2/7/2013 10:07:47 AM 2/7/2013 10:07:47.000000 AM
In Oracle, a DATE always has a day and a time component. Depending on the tool you are using and your session's NLS_DATE_FORMAT, it is entirely possible that the tool may not display the time component when you look at the data. But that is simply a display question, it has no impact on the actual data.
If you want to subtract 100 hours from midnight on the day that MyDate represents
SELECT TRUNC(MyDate) - interval '100' hour
FROM dual
This will return a DATE. If you want to return a string in a particular format
SELECT TO_CHAR( TRUNC(MyDate) - interval '100' hour, 'YYYY-MM-DD hh:mi am' )
FROM dual
Note that I'm assuming that there was a typo in your question. I assume that you want to display the minutes after the hour (mi) rather than the month (mm).
I am trying to fetch the records which is older than 30 days (from Mod_date) and I am using the below query and it is returning all the data and I want only 30 days old data.
Sample :- Mod_date 03-NOV-12 12.00.00.000000000 AM
Query :-
select Mod_date from fil_cnfact where Mod_date <= sysdate -30 order by Mod_date asc ;