Compare date + time with timestamp - sql

I have a table with two temporal columns. First (name is DATE) is storing the date (not including the time part) and therefor the datatype is DATE. Second column (name is TIME) is for storing the time in seconds and therefor the datatype is NUMBER.
I need to compare this two dates with a timestamp from another table. How can I calculate the date of the two columns (DATE and TIME) and compare to the timestamp of the other table?
I have tried to calculate the hours out of the time column and add it to the date column, but the output seems not correct:
SELECT to_date(date + (time/3600), 'dd-mm-yy hh24:mi:ss') FROM mytable;
The output is just the date, but not the time component.

You can use the INTERVAL DAY TO SECOND type:
SELECT your_date + NUMTODSINTERVAL(your_time_in_seconds, 'SECOND') FROM dual;
Example:
SELECT TRUNC(SYSDATE) + NUMTODSINTERVAL(39687, 'SECOND') FROM dual;
The calculated date with time is: 10-11-2013 11:01:27
This is a better idea than dividing your value by 3600 in my opinion, as you have an interval in seconds, so it feels natural to use an interval to represent your time, which can then be easily added to a column of DATE datatype.
Oracle Interval in Documentation
NUMTODSINTERVAL Function in documentation

date + (time/3600) is already a DATE, so you don't need to do to_date(). It does have the time part you added though, you just aren't displaying it. If you want to output that as a string in the format you've shown, use to_char() instead:
SELECT to_char(date + (time/3600), 'dd-mm-yy hh24:mi:ss') FROM mytable;
... except that if time is actually in seconds, you need to divide by 86400 (24x60x60), not 3600. At the moment you're relying on your client's default date format, probably NLS_DATE_FORMAT, which doesn't include the time portion from what you've said. That doesn't mean the time isn't there, it just isn't displayed.
But that is just for display. Leave it as a date, by just adding the two values, when comparing against you timestamp, e.g.
WHERE date + (time/86400) < systimestamp

Try like this,
SELECT TO_DATE('11/11/2013','dd/mm/yyyy') + 3600/60/60/24 FROM DUAL;
Your query,
SELECT date + time/60/60/24 FROM mytable;

try using to_timestamp instead of to_date

Related

How to add minutes to a DATE type using only to_char and to_date?

As mentioned in title, I am looking for way to add minutes onto a DATE type attribute without converting it to another data type.
( SELECT to_char(event_starttime, 'HH:MI:SS') + to_char('00:06:44', 'HH:MI:SS')
FROM
event
WHERE
event_id = (
SELECT
event_id
FROM
event
WHERE
carn_date = to_date((
SELECT
carn_date
FROM
carnival
WHERE
carn_name = 'RM Autumn Series Caulfield 2022'
), 'DD/MM/YYYY')
AND eventtype_code = '21K'
)
);
But it does not seem to be working. Converting to other data type is not possible and I can only use to_char and to_date to do it.
Once again, thank you for your help
To add, for example, 15 minutes to a date just do this:
select event_starttime + (1/1440*15) from event;
Converting to other data type is not possible
I can only use to_char and to_date to do it
Those two statements are contradictory. to_date() converts from a string data type to to a date data type; to_char() does the reverse.
But lets assume the second one is your actual requirement, and the assignment is not to use other functions like to_dsinterval() or other data types like intervals - however arbitrary a restriction that is.
If the starting date has its time set to midnight then you can convert just the date portion to a string, append the new time also still as a string, and convert the result to a date:
to_date(to_char(event_starttime, 'YYYY-MM-DD ') || '00:06:44', 'YYYY-MM-DD HH24:MI:SS')
Whether the starting date has its time as midnight or not, you can convert your time to a fraction of a day and add that; but that involves sysdate and trunc() as well as the two functions you mentioned:
event_starttime + (to_date('00:06:44', 'HH24:MI:SS') - trunc(sysdate, 'MM'))
That works because if you omit the date elements, to_date() gives you the specified time on the first day of the current month. And trunc(sysdate, 'MM') gives you midnight on that same day. Subtracting them gives you the fraction of a day that your time represents, which can then just be added to the original date, whatever time it already has.
db<>fiddle showing both, with the intermediate values so you can see what's happening.
Do not use TO_DATE and TO_CHAR as that is converting it to another data-type (TO_CHAR converts the date to a string and TO_DATE converts a string to a date). Instead, add an INTERVAL to the DATE which will result in another DATE value (and an unchanged data-type):
SELECT event_starttime + INTERVAL '00:06:44' HOUR TO SECOND
FROM event
WHERE event_id = ( SELECT event_id
FROM event
WHERE carn_date = SELECT TRUNC(carn_date)
FROM carnival
WHERE carn_name = 'RM Autumn Series Caulfield 2022'
)
AND eventtype_code = '21K'
)
If you do not see a difference then change the preferences for how SQL Developer displays dates using:
ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS';

how to select all entries having date 25-11-20 in oracle 11g?

sql table
here in the table above named carpooling contains a column name start_on which has date time as timestamp i have to write a query to select all the rows having date as 25-11-20 using to_char and to_date.
You write a timestamp literal like this:
timestamp '2020-11-25 00:00:00'
so the full filtering condition will be
where start_on >= timestamp '2020-11-25 00:00:00'
and start_on < timestamp '2020-11-26 00:00:00'
Note that dates and timestamps are different in Oracle, and dates include times down to the second (this is for historical reasons - originally there was only the date type, and timestamp was added much later).
Use the TRUNC function, along with date and interval literals:
SELECT *
FROM CARPOOLING
WHERE START_ON BETWEEN DATE '2020-11-25'
AND (DATE '2020-11-26' - INTERVAL '0.000001' SECOND)
You can simply use to_date, but it's recommended to remove the time when comparing the dates. Otherwise, rows having the same date, but a different time will not be selected. Removing the time can be done using TRUNC.
So you can do something like this:
SELECT * FROM carpooling
WHERE TRUNC(start_on) = TO_DATE('2020-11-25','yyyy.mm.dd');
If you don't want to check the 25th of November 2020, but another data, change the date to match your goal.

How to substract 2 varchar dates in oracle?

I have these varchar : 20211026231735.
So I would like a query to substract actual sysdate to that date and convert the substraction to DAY HOURS AND SECONDS.
select TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS') - start_time from TABLEA where job_name='jOB_AA_BB';
I get 4220.
Any help please? Thanks
When you do datetime arithmetic with the DATE datatype, you get back a NUMBER of days. To get an INTERVAL you can subtract two TIMESTAMPs. You don't say what the data type is for start_time, but you might get away with this:
select localtimestamp - start_time
from tablea where job_name='jOB_AA_BB';
LOCALTIMESTAMP gives you a TIMESTAMP value in the current session time zone. There's also CURRENT_TIMESTAMP, which give you the same thing in a TIMESTAMP WITH TIME ZONE and SYSTIMESTAMP that gives you the database time in TIMESTAMP WITH TIME ZONE. You may need to convert your start_time to avoid time zone differences, if any.
You can us the function numtodsinterval to convert the results of date arithmetic to an interval. If necessary then use extract to pull out the needed components.
with tablea(job_name, start_time) as
(select 'jOB_AA_BB','20211026231735' from dual)
select numtodsinterval((SYSDATE - to_date( start_time,'yyyymmddhh24miss')),'hour') date_diff
from tablea where job_name='jOB_AA_BB' ;
with tablea(job_name, start_time) as
(select 'jOB_AA_BB','20211026231735' from dual)
select extract (hour from date_diff) || ':' || extract (minute from date_diff)
from (
select numtodsinterval((sysdate - to_date( start_time,'yyyymmddhh24miss')),'day') date_diff
from tablea where job_name='jOB_AA_BB'
);
NOTE: I am not sure how you got any result, other than an error, as your query winds up as a string - a string. You should not convert sysdate to a string but your string to a date (better yet store it as the proper data type - date).
You can convert the value to a date (rather than converting SYSDATE to a string) and then subtract and explicitly return the value as an INTERVAL DAY TO SECOND type:
SELECT (SYSDATE - TO_DATE('20211026231735', 'YYYYMMDDHH24MISS')) DAY TO SECOND
FROM DUAL;
Or, for your table:
SELECT (SYSDATE - TO_DATE(start_time,'YYYYMMDDHH24MISS')) DAY(5) TO SECOND
FROM TABLEA
WHERE job_name='jOB_AA_BB';
db<>fiddle here

how to add dates with keep their formats?

I have a start_time which is already formatted as date type and have duration as number like 449. It means 449 seconds. So i need end_time. Of course i can obviously convert duration to date format and add duration on start_time using below simply queries
select to_char(to_date(USE_SEC,'sssss'),'hh24miss')
from ABA_RM_INB_USAGE;
USE_SEC column is containing integer(number in oracle) like 1167
and above query is returning date formatted result like 001927 that is okay.
This is query that add duration on start_time
select to_char(USE_STRT_DTTM, 'hh24miss') + to_char(to_date(USE_SEC, 'sssss'), 'hh24miss') as duration
from ABA_RM_INB_USAGE;
This is returning that result which is problem that convert to date format
95980.
It means 09:59:80 oops 80 seconds is absolutely wrong. Can i add dates with keep their formats. How can i ?
You can use +. This is the traditional method:
select start_time + duration / 24*60*60
You can write this now as:
select start_time + duration * interval '1' second
Your first query is converting your number-of-second value to a string. In your second query you are converting the start time to another string. Both represent HHMISS. Then you add them together, effectively:
'094053' + '001927'
For the addition operator to work they are implicitly converted to numbers, so it becomes:
94053 + 1927
which gives you your (numeric) result of 95980.
As soon as you convert to strings you are losing the ability to treat them as dates and honour the mod-60 behaviour for minutes and seconds, which is my you appear to end up with 80 seconds - but they aren't really seconds at all, it's just a number. You also lose the mod-24 behaviour for hours, so if your start time is just before midnight and the duration pushes you over midnight, your result wouldn't reflect that either.
As #GordonLinoff suggested, keep your date as a date, and add the number of seconds as a number, or a number converted to an interval:
USE_STRT_DTTM + USE_SEC / (24*60*60)
or:
USE_STRT_DTTM + USE_SEC * interval '1' second
Demo:
-- CTE for sample data
with ABA_RM_INB_USAGE (USE_STRT_DTTM, USE_SEC) as (
select to_date('09:40:53', 'HH24:MI:SS'), 1167 from dual
union all
select to_date('23:54:55', 'HH24:MI:SS'), 449 from dual
)
-- query showing working
select USE_STRT_DTTM,
USE_SEC,
to_char(to_date(USE_SEC, 'sssss'), 'hh24:mi:ss') as use_sec_hhmiss,
USE_SEC * interval '1' second as use_sec_interval,
USE_STRT_DTTM + USE_SEC / (24*60*60) as result1,
USE_STRT_DTTM + USE_SEC * interval '1' second as result2
from ABA_RM_INB_USAGE;
USE_STRT_DTTM USE_SEC USE_SEC_HHMISS USE_SEC_INTERVAL RESULT1 RESULT2
------------------- ------- -------------- ------------------- ------------------- -------------------
2019-08-01 09:40:53 1167 00:19:27 +00 00:19:27.000000 2019-08-01 10:00:20 2019-08-01 10:00:20
2019-08-01 23:54:55 449 00:07:29 +00 00:07:29.000000 2019-08-02 00:02:24 2019-08-02 00:02:24
Read more about Datetime/Interval Arithmetic.
I have a start_time which is already formatted as date type
Your column is (I hope, and seems to be the case from your query) a date. Dates do not have intrinsic human-readable formats. When you query your table your client will format the date to something readable, using either its own preferences or your session's NLS_DATE_FORMAT.
Of course i can obviously convert duration to date format and add duration on start_time
You originally converted your duration to a date data type (via to_date()), at 00:19:27 on the first day of the current month (which is what if defaults to if not day, month or year components are supplied; my CTE above is doing the same). You cannot add a date to another date. That even has its own error, "ORA-00975: date + date not allowed". So you then converted both your date values (start time and converted duration) to strings. You can't add strings together either, as that makes no sense; but if you try Oracle will implicitly try to convert both strings to numbers. In this case that implicit conversion works for both strings, but it usually won't; the superficially-similar '09:40:53' + '00:19:27' would get "ORA-01722: invalid number".
In Oracle DATE values do not have a format - you use the TO_CHAR function to format them when you need to output them.
In this case it looks like you need to use an interval. You have a field which contains a number of seconds that you want to convert to an interval - for this you can use the TO_DSINTERVAL function, although amusingly enough you have to convert the number to a string in order to use the function to convert it to an interval:
-- Version using TO_DSINTERVAL
WITH cteData AS (SELECT USE_STRT_DTTM + TO_DSINTERVAL('PT' || TO_CHAR(USE_SEC) || 'S') AS DT_TIME
FROM ABA_RM_INB_USAGE)
SELECT TO_CHAR(DT_TIME, 'YYYY-MM-DD HH24:MI:SS') FORMATTED_DATE_TIME
FROM cteData;
Docs for TO_DSINTERVAL here
dbfiddle demonstrating this in use here
EDIT
As #AlexPoole points out, the better function to use here is NUMTODSINTERVAL:
-- Version using NUMTODSINTERVAL
WITH cteData AS (SELECT USE_STRT_DTTM + NUMTODSINTERVAL(USE_SEC, 'SECOND') AS DT_TIME
FROM ABA_RM_INB_USAGE)
SELECT TO_CHAR(DT_TIME, 'YYYY-MM-DD HH24:MI:SS') FORMATTED_DATE_TIME
FROM cteData;
Docs for NUMTODSINTERVAL here
updated dbfiddle here

How to Round up timestamp to number of Days?

PreparedStatement psnmt=con.prepareStatement("SELECT (?)-(?) as DiffDate FROM dual");
psnmt.setTimestamp(1,ctenderdate);
psnmt.setTimestamp(2,btenderdate);
ResultSet resrt=psnmt.executeQuery();
if(!resrt.next())
{
out.println("No Records Found");
}
else
{
do
{
datediff=resrt.getString("DiffDate");
}
while(resrt.next());
System.out.println("the no of days Difference"+datediff);
}
ctenderdate=2015-06-27 00:00:00.0
btenderdate=2015-06-29 00:00:00.0
datediff=1 10:18:51.940000000
Expected datediff=2
How to round it off datediff to number of days
EDIT
Subtract TIMESTAMP values
If we really want to subtract two TIMESTAMP values, then we have to work with the INTERVAL DAY TO SECOND datatype that's returned. The easiest way to work with that is to use the EXTRACT function.
If want to return integer number of days (emulating the CEIL function) then we could test whether any part of the time (HOUR, MINUTE, SECOND) was non-zero. If they are all zero, we can use just the DAY portion. Otherwise, we have to add 1 to the DAY portion, and return that.
For example:
SELECT EXTRACT(DAY FROM diff.idts)
+ CASE
WHEN EXTRACT(HOUR FROM diff.idts) > 0
OR EXTRACT(MINUTE FROM diff.idts) > 0
OR EXTRACT(SECOND FROM diff.idts) > 0
THEN 1
ELSE 0
END
AS days_diff
FROM ( SELECT ? - ? AS idts FROM dual ) diff
ORIGINAL ANSWER
For Oracle database, you can perform this operation in the database:
SELECT CEIL(TO_DATE(?,'YYYY-MM-DD HH24:MI:SS.F')-TO_DATE(?,'YYYY-MM-DD HH24:MI:SS.F'))
FROM dual
This assumes the bind parameters are passed as strings, in format that matches the format model specified in the TO_DATE function, for example:
'2015-06-27 14:45:21.0'
(I'm assuming Oracle because of the use of the dual table, and because you are using subtraction operation between two dates. You would need a different statement for a different database.)
To unpack that expression a little bit...
The Oracle TO_DATE function converts a character string into an Oracle DATE value. The second argument is the format model, specifies that format of the first argument.
A subtraction operation between two DATE values returns the difference as a number of days (integer days plus fractional days.)
The CEIL function rounds a non-integer value up to the next higher integer.
FOLLOWUP
Q: how to use it with timestamp?
A: A subtraction of two TIMESTAMP values gets returned as an INTERVAL DAY TO SECOND datatype. And I'd prefer to avoid working with that.
In Oracle, when we do a subtraction of two DATE values, we get a decimal number. That's much easier to work with.
And in terms of "rounding" up a difference in days, I'm fine with disregarding fractional seconds.
If I had to pass in TIMESTAMP values, I would convert them to DATE values. The expressions above are already expecting string values, so I would just replace the ? with
TO_CHAR(?,'YYYY-MM-DD HH24:MI:SS')
If I had a requirement to pass in TIMESTAMP datatype, and return integer days difference rounded up, I would use a query like this:
SELECT CEIL( TO_DATE(TO_CHAR( ? ,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS')
- TO_DATE(TO_CHAR( ? ,'YYYY-MM-DD HH24:MI:SS'),'YYYY-MM-DD HH24:MI:SS')
) AS days_diff
FROM dual
Check out this link. There are answers for results in hours or minutes. What you are looking for should be similar.
My bad. I should not post just-a-link-answers. What you can do, as described there is:
SELECT TRUNC (SYSDATE) - TO_DATE ('10/20/2012', 'mm/dd/yyyy') FROM DUAL;
Notice the following details:
ENDDATE - STARTDATE will give you a number that corresponds to the
number of days between the two dates.
If you want the result in hours, multiply by 24; if minutes, multiply
by 24*60 and so forth.
You can also convert the result to an INTERVAL. There are two type of
intervals: NUMTODSINTERVAL(ENDDATE - STARTDATE, 'DAY') or
NUMTOYMINTERVAL(ENDDATE - STARTDATE, 'DAY')