In SQL, I have a DATE
variable which I want to round to the next available half hour (ie xx:30). Note that this shouldn't just be to the nearest half hour.
Here are some examples:
Time Expected outcome
2012-03-26 11:25 AM 2012-03-26 11:30 AM
2012-03-26 11:45 AM 2012-03-26 12:30 PM
Is there a way to do this in SQL?
It's a bit convoluted, but something like
SELECT round( (date_col - trunc(date_col)) * 48 )/ 48 +
trunc( date_col )
FROM dual
should work.
SQL> ed
Wrote file afiedt.buf
1 select round((sysdate - trunc(sysdate)) * 48)/48 + trunc(sysdate),
2 sysdate
3* from dual
SQL> /
ROUND((SYSDATE-TRUNC SYSDATE
-------------------- --------------------
26-mar-2012 14:30:00 26-mar-2012 14:35:30
TRUNC(date_col)
truncates the time to midnight. date_col - trunc(date_col)
returns the fraction of a day that has elapsed since midnight. trunc(date_col)
Here's a little adjustment to Justin's answer that I think gives the results you want:
WITH thedate AS (SELECT trunc(SYSDATE)+6.5/48 thedate FROM dual)
select round((thedate - trunc(thedate)) * 24 - 1/(24*3600))/24 + trunc(thedate)+1/48,
theDATE
from thedate;
Basically, this rounds to the nearest hour (after subtracting a second to prevent rounding up when you are exactly on the half-hour) then adds a half hour.
Gave a +1 to Justin's answer for the originality.
If you want a more pedantic (or, perhaps more easily understood or maintained) aproach,
select case when to_number(to_char(sysdate,'mi')) > 30
then trunc(sysdate,'mi') + ((60 - to_number(to_char(sysdate,'mi')) +30)/1440)
else trunc(sysdate,'mi') + (30 - to_number(to_char(sysdate,'mi')))/1440 end
from dual
I'm only tossing this in there as this might be a more adaptable approach if you needed to do something similar against other numbers, like 45 minutes past the hour for example. You would just replace the three 30s with 45s and away you go.
For performance, though, for your exact problem - Justin's is a real winner.
To get the next half hour, modify Justin Cave's solution by changing the ROUND to CEIL:
SELECT CEIL( (date_col - trunc(date_col)) * 48 )/ 48 +
trunc( date_col )
FROM dual
ROUND goes to the nearest (up or down), CEIL goes up to the next (always up). FLOOR would go to the previous (always down).
To answer Michael Broughton's point about maintability:
48 is the number of "half hours" in a day. To change the period, replace both instances with:
60/x * 24
where x
is the number of minutes in the period you want.
Eg Every 10 mins = (60/10) * 24 = 144.
Hope this helps!
My code does this using ROUND function to round to the nearest hour and then adding half an hour
WITH thedate AS
(SELECT TO_DATE ('2012-03-26 11:20 AM', 'YYYY-MM-DD HH:MI AM') mydate
FROM DUAL)
SELECT mydate,
TO_CHAR (ROUND (mydate, 'HH') + 1 / 48,
'YYYY-MM-DD HH:MI AM'
) "Rounded Date"
FROM thedate;
Hope it helps
simplified (I hope)...
select
case
when to_number(to_char(sysdate,'mi')) <= 30
then trunc(sysdate,'hh24') + 30/1440
else trunc(sysdate,'hh24') + 1/24
end
from dual;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.