can i use to_number(to_char()) function in order to exclude all the weekends from a range of dates?
For instance, there are two date columns in my table such as start and finish (in the form of '06/06/2011 10:00:00 am'), and i want to estimate the duration of finish-start excluding Saturdays and Sundays.
If I understand you right you want to calculate the difference between two dates, but exclude the 2 days of each weekend in the range from the result. Is that correct?
If this is what you want the below code should work with the following assumptions:
I am assume start and end will not be on weekends.
I am not validating that end is before start.
Basically its just a matter of working out how many weekends are in the date range. So obviously there's one weekend per 7 days. Then we just have to check if the range wraps around a weekend, and if so add one more.
FUNCION dateDiff( dt_start DATE, dt_end DATE ) RETURN NUMBER
IS
raw_diff NUMBER;
weekends NUMBER;
BEGIN
raw_diff := dt_end - dt_start;
weekends := TRUNC( raw_diff / 7 );
IF( ( dt_start - TRUNC( dt_start, 'DAY' ) )
> ( dt_end - TRUNC( dt_end , 'DAY' ) ) )
THEN
weekends := weekends + 1;
END IF;
RETURN raw_diff - ( weekends * 2 );
END;
Related
I have two time stamps #starttimestamp and #endtimestamp. How to calculate number of working hours between these two
Working hours is defined below:
Mon- Thursday (9:00-17:00)
Friday (9:00-13:00)
Have to work in impala
think i found a better solution.
we will create a series of numbers using a large table. You can get a time dimension type table too. Make it doenst get truncated. I am using a large table from my db.
Use this series to generate a date range between start and end date.
date_add (t.start_date,rs.uniqueid) -- create range of dates
join (select row_number() over ( order by mycol) as uniqueid -- create range of unique ids
from largetab) rs
where end_date >=date_add (t.start_date,rs.uniqueid)
Then we will calculate total hour difference between the timestamp using unix timestamp considering date and time.
unix_timestamp(endtimestamp - starttimestamp )
Exclude non working hours like 16hours on M-T, 20hours on F, 24hours on S-S.
case when dayofweek ( dday) in (1,7) then 24
when dayofweek ( dday) =5 then 20
else 16 end as non work hours
Here is complete SQL.
select
end_date, start_date,
diff_in_hr - sum(case when dayofweek ( dday) in (1,7) then 24
when dayofweek ( dday) =5 then 20
else 16 end ) total_workhrs
from (
select (unix_timestamp(end_date)- unix_timestamp(start_date))/3600 as diff_in_hr , end_date, start_date,date_add (t.start_date,rs.uniqueid) as dDay
from tdate t
join (select row_number() over ( order by mycol) as uniqueid from largetab) rs
where end_date >=date_add (t.start_date,rs.uniqueid)
)rs2
group by 1,2,diff_in_hr
The below code gives me the output of current review date and the next review date. Here the current review date is fixed to today's date.
I want to keep that as a user defined variable. I tried using the --> ReviewDate = &enter_date; but whichever format i put in the dialog box it gives me an error (i tried 08-06-2020, 06-08-2020, 08-Jun-2020, etc). Is there any built-in function in oracle which will convert the value I input to the correct system date which oracle will understand ?
Also, what should be the code if i want to exclude any weekends from my current logic ? Here the next review date is set to 6 months from current review date but i want my code to exclude the weekends from this.
Thanks!!
SET SERVEROUTPUT ON;
DECLARE
ReviewDate workforce.Jdate%TYPE;
BEGIN
ReviewDate := '08-06-2020';
ReviewDate_New := add_months(ReviewDate, 6);
dbms_output.put_line('Last Review Date: ' || '08-06-2020');
dbms_output.put_line('Next Review Date: ' || ReviewDate_New);
END;
The ANSI format for a date literal is DATE 'YYYY-NN-DD' so:
ReviewDate := DATE '2020-06-08';
To avoid weekends you would have to check the day of the week returned by the add_months function and then increment the date accordingly. to_char with the 'D' format returns you a number 1-7 for the day of the week, so something like:
CASE TO_CHAR(ReviewDate_New, 'D')
WHEN 6 THEN
ReviewDate_New := ReviewDate_New + 2;
WHEN 7 THEN
ReviewDate_New := ReviewDate_New + 1;
ELSE
NULL; -- Do nothing
END CASE;
This assumes that Saturdays and Sundays are day 6 and 7 in your database (it depends on NLS settings).
I have this anonymous block:
DECLARE
V_DATA DATE;
BEGIN
V_DATA := '01-GEN-2000';
HR.STATISTICHE.RATINGOPERATORI (V_DATA);
COMMIT;
END;
but I would to generate the date in a random way. How can I do?
You can generate random dates between two dates ,as displayed in the query below .Random Dates are generated between 1-jan-2000 and 31-dec-9999
SELECT TO_DATE(
TRUNC(
DBMS_RANDOM.VALUE(TO_CHAR(DATE '2000-01-01','J')
,TO_CHAR(DATE '9999-12-31','J')
)
),'J'
) FROM DUAL;
OR you can use
SELECT TO_DATE (
TRUNC (
DBMS_RANDOM.VALUE (2451545, 5373484)
)
, 'J'
)
FROM DUAL
In the above example ,the first value is 01-Jan-2000 and the second value id 31-dec-9999
To generate random date you can use
select to_date('2010-01-01', 'yyyy-mm-dd')+trunc(dbms_random.value(1,1000)) from dual
or for random datetime
select to_date('2010-01-01', 'yyyy-mm-dd')+dbms_random.value(1,1000) from dual
If you want to see it's logic, you can also use this code.
create or replace procedure genDate(result out nvarchar2) IS
year number;
month number;
day number;
Begin
year:=FLOOR(DBMS_RANDOM.value(2000,2100));
month:=FLOOR(DBMS_RANDOM.value(1,12));
IF month=2 and (year/4)=0 and (year/100)!=0 then
day:=FLOOR(DBMS_RANDOM.value(1,29));
ELSIF month=2 or (year/100)=0 then
day:=FLOOR(DBMS_RANDOM.value(1,28));
ELSIF MOD(month,2)=1 then
day:=FLOOR(DBMS_RANDOM.value(1,31));
ELSIF MOD(month,2)=0 and month!=2 then
day:=FLOOR(DBMS_RANDOM.value(1,30));
END IF;
result:=month||'-'||day||'-'||year;
End;
here is one more option to generate date going back from now where 365 - days quanitity to move back from today, 'DD.MM.YYYY'- mask
to_char(sysdate-dbms_random.value()*365, 'DD.MM.YYYY')
I needed to generate employee data for testing. Each employee needed a date of birth that put them between 16 and 65 years of age, and a date of hire sometime between their 16th birthday and SYSDATE. Here's how...
FUNCTION randomDateInRange(alpha IN DATE, omega IN DATE) RETURN DATE IS
BEGIN
RETURN alpha + DBMS_RANDOM.VALUE(0, omega - alpha);
END;
...and then, to use this function...
-- an employee can be any age from 16 to 65 years of age
DoB := randomDateInRange(
SYSDATE - INTERVAL '65' YEAR,
SYSDATE - INTERVAL '16' YEAR
);
-- an employee could have been hired any date since their sixteenth birthday
DoH := randomDateInRange(
DoB + INTERVAL '16' YEAR,
SYSDATE
);
I need a help on this function. The code has no error but it keeps returning the same result, that the value from of the second condition/statement.
This is how it suppose to work:
If employees age at hire date (DOFA) is less than or equals to 25 the retirement date is 35 years from hire date. Otherwise retirement date is when employees age is 60
create or replace function EDOR_FUNCTION
(DOFA in date, DOB in date)
return date
is
new_edor_date date;
begin
if
DOFA - DOB <= 25 then new_edor_date := add_months(DOFA, 35*12);
else
new_edor_date := add_months(DOB, 60*12);
end if;
return new_edor_date;
end;
Your condition subtracts one date from another. This gives the number of days between the two, not the number of years.
months_between() gives the number of months between two dates. Multiply by twelve to get number of years
if months_between(DOFA , DOB) <= (25*12) then
new_edor_date := add_months(DOFA, 35*12);
else
new_edor_date := add_months(DOB, 60*12);
end if;
i want to make a function in oracle database. in witch i want to get 1 day previous date from selected date, if selected date is "Monday" then i want to select date of "Friday" as previous date as it is last working day of week.
Try this:
CREATE OR REPLACE FUNCTION PREVIOUS_WORKING_DAY(pDate IN DATE)
RETURN DATE
IS
strDay_of_week VARCHAR2(50);
dtPrev DATE;
BEGIN
strDay_of_week := TRIM(TO_CHAR(pDate, 'DAY'));
CASE strDay_of_week
WHEN 'MONDAY' THEN
dtPrev := TRUNC(pDate) - INTERVAL '3' DAY;
WHEN 'SUNDAY' THEN
dtPrev := TRUNC(pDate) - INTERVAL '2' DAY;
ELSE
dtPrev := TRUNC(pDATE) - INTERVAL '1' DAY;
END CASE;
RETURN dtPrev;
END PREVIOUS_WORKING_DAY;
Share and enjoy.