Home » SQL & PL/SQL » SQL & PL/SQL » Incorrect number of seconds returned from function (Oracle 11g R2)
Incorrect number of seconds returned from function [message #617187] Wed, 25 June 2014 18:05 Go to next message
PeterS
Messages: 12
Registered: November 2011
Location: California
Junior Member
Hello Oracle gurus.

My task is to determine number of minutes falling on weekend within any time period defined by start and date.
I wrote the following function which returns number of seconds falling on weekend day within any time period defined by start_date and end_date.

CREATE OR REPLACE FUNCTION GET_WEEKEND_SECONDS
(
      P_START_DATE DATE,
      p_END_DATE DATE
)
RETURN NUMBER
IS
CURSOR cur_weekend_minutes IS
SELECT 
CASE WHEN (weekend_day_num = MIN(weekend_day_num) OVER(PARTITION BY START_DATE)/*START_EDGE_ROW. This determines first weekend in order from old to most recent*/ )
        THEN CASE WHEN start_date <= (MIN(WEEKENDDAY_START) OVER(ORDER BY START_DATE))/*first_weekend_start*/THEN 24*60
                  WHEN START_DATE > (MIN(WEEKENDDAY_START) OVER(ORDER BY START_DATE))/*first_weekend_start*/
                    THEN ROUND((MIN(WEEKENDDAY_END) OVER(PARTITION BY START_DATE)/*first_weekend_end*/ - START_DATE)*24*60, 0)
             ELSE 0 END
      WHEN (weekend_day_num = MAX(weekend_day_num) OVER(PARTITION BY END_DATE)/*END_EDGE_ROW. This determines last weekend in order from old to most recent*/)
        THEN CASE WHEN END_DATE >= MAX(weekendday_end) OVER(PARTITION BY end_date)/*last_weekend_end*/THEN 24*60
                  when END_DATE < max(WEEKENDDAY_END) over(partition by END_DATE)/*last_weekend_end*/
                    THEN ROUND((END_DATE - MAX(WEEKENDDAY_START) OVER(PARTITION BY END_DATE)/*last_weekend_start*/)*24*60 , 0)
             ELSE 0 END
 ELSE 24 END AS WEEKEND_MINUTES
FROM
(
 SELECT
 ROWNUM WEEKEND_DAY_NUM
 ,P_START_DATE START_DATE
 ,p_END_DATE END_DATE
 ,trunc(p_START_DATE) + level - 1 WEEKENDDAY_START
 ,TO_DATE(TO_CHAR((TRUNC(p_START_DATE) + level - 1), 'DD-MM-YYYY') || ' 23:59', 'DD-MM-YYYY HH24:MI') as WEEKENDDAY_END
 FROM DUAL
 CONNECT BY LEVEL < = CEIL((p_END_DATE - p_START_DATE)) + 1
)
WHERE TO_CHAR (WEEKENDDAY_START, 'DY') IN ('SAT', 'SUN');

v_total_weekend_minutes NUMBER(23,0) := 0;
v_weekend_minutes_rec cur_weekend_minutes%ROWTYPE;

BEGIN
OPEN cur_weekend_minutes;
LOOP
  FETCH cur_weekend_minutes INTO v_weekend_minutes_rec;
  EXIT when cur_weekend_minutes%NOTFOUND;
  v_total_weekend_minutes := v_total_weekend_minutes + v_weekend_minutes_rec.WEEKEND_MINUTES;
END LOOP;
CLOSE cur_weekend_minutes;
RETURN v_total_weekend_minutes * 60.00;
END;


I know it can be improved on multiple levels, this is my POC at the moment. I am not concerned with performance either, I'll improve it later.

Code successfully compiles and does the job, almost...
I am experiencing trouble with precision of returned data.

Here is my example.
SELECT GET_WEEKEND_MINUTES(TO_DATE('22-JUN-2014 23:46:17', 'DD-MON-YYYY HH24:MI:SS'), TO_DATE('23-JUN-2014 01:51:52', 'DD-MON-YYYY HH24:MI:SS')) FROM DUAL;


It returns 780 seconds which is exactly 13 minutes while I expect 823 seconds which is 13 minutes and 43 seconds.
I am losing 43 seconds.

This is the amount of time falling on weekend day (Sunday in this example) between:
start_date - 22-JUN-2014 23:46:17
end of first weekend day in my time interval -  22-JUN-2014 23:59:59
select (to_date('22-JUN-2014 23:59:59', 'DD-MON-YYYY HH24:MI:SS') - to_date('22-JUN-2014 23:46:17', 'DD-MON-YYYY HH24:MI:SS'))*24*60*60+1 from dual;

WEEKEND_SECONDS
823


I played with conversion to seconds within my cursor, removed rounding - precision was not better than I see with posted code.


Could you please help?

Thank you,
Pit.
Re: Incorrect number of seconds returned from function [message #617189 is a reply to message #617187] Wed, 25 June 2014 18:18 Go to previous messageGo to next message
BlackSwan
Messages: 26766
Registered: January 2009
Location: SoCal
Senior Member
When does "weekend" officially start?
When does "weekend" officially end?
What is the maximum number of seconds in a single weekend?
Re: Incorrect number of seconds returned from function [message #617193 is a reply to message #617187] Wed, 25 June 2014 19:12 Go to previous messageGo to next message
Solomon Yakobson
Messages: 3273
Registered: January 2010
Location: Connecticut, USA
Senior Member
No need for function. Assuming weekend is Saturday and Sunday:

WITH parameters AS (
                    SELECT  TO_DATE('22-JUN-2014 23:46:17', 'DD-MON-YYYY HH24:MI:SS') start_dt,
                            TO_DATE('23-JUN-2014 01:51:52', 'DD-MON-YYYY HH24:MI:SS') end_dt
                      FROM  DUAL
                   ),
          dates AS (
                    SELECT  GREATEST(trunc(start_dt) + level - 1,start_dt) start_dt,
                            LEAST(trunc(start_dt) + level,end_dt) end_dt
                      FROM  parameters
                      WHERE start_dt + level - 1 - trunc(start_dt + level - 1,'IW') >= 5
                      CONNECT BY trunc(start_dt) + level <= trunc(end_dt) + 1
                   )
SELECT  ROUND(SUM(end_dt - start_dt) * 1440) weekend_minutes,
        SUM(end_dt - start_dt) * 86400 weekend_seconds
  FROM  dates
/

WEEKEND_MINUTES WEEKEND_SECONDS
--------------- ---------------
             14             823

SQL>



SY.

[Updated on: Wed, 25 June 2014 19:18]

Report message to a moderator

Re: Incorrect number of seconds returned from function [message #617195 is a reply to message #617189] Wed, 25 June 2014 19:23 Go to previous messageGo to next message
PeterS
Messages: 12
Registered: November 2011
Location: California
Junior Member
When does "weekend" officially start?
Any Saturday at 00:00:00

When does "weekend" officially end?
Any Sunday at 23:59:59

What is the maximum number of seconds in a single weekend?
2*24*60*60

I am trying to be independent of Mon-Sun or Sun-Sat type weeks. I know I depend on TO_CHAR (WEEKENDDAY_START, 'DY') conversion but that's the only dependency in my code.

Thank you,
Pit.
Re: Incorrect number of seconds returned from function [message #617199 is a reply to message #617193] Wed, 25 June 2014 19:58 Go to previous messageGo to next message
PeterS
Messages: 12
Registered: November 2011
Location: California
Junior Member
Thank you, Solomon.

Very elegant and precise logic. I understand that it works for Mon-Sun week.
I have a question though - does it depend on ISO standard of the country? Seems like it does, based on Oracle documentation - http://docs.oracle.com/cd/B28359_01/server.111/b28286/sql_elements004.htm#SQLRF51066

Will it work for Sun-Sat week?

The only reason I made a function is I need to call it from a third-party app for data processing.

Regards,
Pit.
Re: Incorrect number of seconds returned from function [message #617200 is a reply to message #617199] Wed, 25 June 2014 20:15 Go to previous messageGo to next message
PeterS
Messages: 12
Registered: November 2011
Location: California
Junior Member
I am curious if my logic can be improved or there is a flaw in it.

Pit.
Re: Incorrect number of seconds returned from function [message #617224 is a reply to message #617199] Thu, 26 June 2014 04:54 Go to previous message
Solomon Yakobson
Messages: 3273
Registered: January 2010
Location: Connecticut, USA
Senior Member
PeterS wrote on Wed, 25 June 2014 20:58

I have a question though - does it depend on ISO standard of the country?


There is no such thing as ISO standard of the country. ISO standard is international standard and is country independent. Perhaps you meant does it depend on client NLS sessings? It does not.

trunc(start_dt + level - 1,'IW')


always truncates to Monday regardless of NLS settings. Therefore:

WHERE start_dt + level - 1 - trunc(start_dt + level - 1,'IW') >= 5


will always detect Saturday and Sunday regardless of NLS settings.

SY.

[Updated on: Thu, 26 June 2014 04:57]

Report message to a moderator

Previous Topic: Oracle function/package same as SAS spedis function
Next Topic: How to find primary key ,foreign key , index and sequence associated to a table
Goto Forum:
  


Current Time: Tue Apr 23 15:54:05 CDT 2024