Domanda

How to subtract Time in two dates. For example, I have 15:32:34 as sign_out date and 13:34:21 as sign_in date, now I want to do sign_out - sign_in with DATE data type, but I am unable to do it, I am getting 0 value for days, but I need to get the difference of time, can any one help me please

È stato utile?

Soluzione

If your columns are timestamp then the difference between them will be an interval. For the values you added as a comment:

select id, time_out - time_in as worked
from t42;

        ID WORKED    
---------- -----------
         1 0 4:22:0.0  
         1 0 2:23:2.0

You want the total, but you can't directly sum intervals. You could convert them to a numeric representation, sum them, and then convert them back:

select id, numtodsinterval(sum(
  extract(day from dd) * (24 * 60 * 60)
    + extract(hour from dd) * (60 * 60)
    + extract(minute from dd) * 60
    + extract(second from dd)
  ), 'SECOND') as total_worked
from (
  select id, time_out - time_in as dd
  from t42
)
group by id;

        ID TOTAL_WORKED
---------- ------------
         1 0 6:45:2.0   

You could also treat them as dates; it isn't entirely clear if you're using fractional seconds but for this kind of data it would seem like unnecessary precision. I'm not sure why you aren't using date columns here (perhaps you just didn't realise that an Oracle date column does contain the time down to the second anyway?). Anyway, you can cast them to dates:

select id,
  sum(cast(time_out as date) - cast(time_in as date)) as total_days,
  numtodsinterval(sum(cast(time_out as date) - cast(time_in as date)), 'DAY')
    as total_interval,
  to_char(trunc(sysdate)
      + sum(cast(time_out as date) - cast(time_in as date)), 'HH24:MI:SS')
    as total_string
from t42
group by id;

        ID TOTAL_DAYS TOTAL_INTERVAL TOTAL_STRING
---------- ---------- -------------- ------------
         1 .281273148 0 6:45:2.0     06:45:02     

The result of subtracting two dates is a number, where 1 would be a whole day. I've shown two ways to convert that to something more useful.

The to_char version will only work if the total is less than a day though; if it might exceed 24 hours then you'd need to calculate it a different way:

select id,
  trunc(dd * 24) as hh,
  trunc((dd - (trunc(dd * 24)/24)) * 24 * 60) as mi,
  trunc((dd - trunc(dd * 24 * 60)/(24 * 60)) * (24 * 60 * 60)) as ss
from (
  select id,
    sum(cast(time_out as date) - cast(time_in as date)) as dd
  from t42
  group by id
);

        ID         HH         MI         SS
---------- ---------- ---------- ----------
         1          6         45          1 

... and you can concatenate those into a string if you want (with lpad to add leading zeros). It's odd that the 'seconds' value here is shown as 1, since (dd - trunc(dd * 24 * 60)/(24 * 60)) * (24 * 60 * 60) is 2, and trunc(2) is 2; not sure if there's a rounding error going on in their somewhere. If you use round instead of trunc in the final clasue then it works, but might give a slightly higher value than expected if you do have fractions of seconds.

SQL Fiddle, which doesn't show intervals in a very friendly format, unfortunately. That's with your sample, and another ID that does exceed 24 hours so you can see the difference; and with both round and trunc for the seconds in the last query.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top