Jump to content
Server Maintenance This Week. ×

Refactoring a Holiday Work Week function


This topic is 2806 days old. Please don't post here. Open a new topic instead.

Recommended Posts

Have a system that creates schedule inspections for months in advance.

Trying to refactor my functions and calculations to make it recursive so each date that is shifted to avoid holiday and off days are also tested to make sure that the suggested date does not fall on a holiday or off day. 

here is my CF that I am using to test for holiday.

/*
 * =====================================
 * BusinessHolidays ( theDate ; return  )
 *
 * RETURNS:
 *		A ¶-delimited list of the dates or names of observed holidays in the year
 *
 * PARAMETERS:
 *		theDate for extracting the year
 *		return 0-8 for dates for names minor major
 *
 * DEPENDENCIES: ValuePosition
 *
 * NOTES:
 *		This version of this function includes observed U.S. federal holidays.
 *		It should be modified to include any holidays observed by the users of
 *		each particular system.
 *
 * HISTORY:
 *		CREATED on 2011-10-18 by Jeremy Bante http://scr.im/jbante.
 *		MODIFIED on 2016-08-19 by Stephen Dolenski
 * =====================================
*/


Let ( [

theYear = Case ( IsValid ( GetAsDate (theDate) ) ; Year ( theDate ) ; GetAsNumber ( theDate ) ) ; 

@nyd = "New Years Day" ;
nyd = Date ( 1 ; 1 ; theYear ) ;

@mlk = "Martin Luther King, Jr. Day" ; // (3rd Monday in January)
mlk = Date ( 1 ; 15 ; theYear )	// earliest possible date
      + Choose ( DayOfWeek ( Date ( 1 ; 1 ; theYear ) ) - 1;
      1 ; 0 ; 6 ; 5 ; 4 ; 3 ; 2 );	// adjust for day of week of month start

@pd = "President's Day"; // (3rd Monday in February)
pd = Date ( 2 ; 15 ; theYear )	// earliest possible date
      + Choose ( DayOfWeek ( Date ( 2 ; 1 ; theYear ) ) - 1;
      1 ; 0 ; 6 ; 5 ; 4 ; 3 ; 2 );	// adjust for day of week of month start

@md = "Memorial Day"; // (last Monday in May)
md = Date ( 5 ; 25 ; theYear )	// earliest possible date
      + Choose ( DayOfWeek ( Date ( 5 ; 31 ; theYear ) ) - 1;
      0 ; 6 ; 5 ; 4 ; 3 ; 2 ; 1 );	// adjust for day of week of month end

@id = "Independence Day"; // (4 July)
id = Date ( 7 ; 4 ; theYear ) ;

@ld = "Labor Day"; // (1st Monday in September)
ld = Date ( 9 ; 1 ; theYear ) // earliest possible date
	+ Choose ( DayOfWeek ( Date ( 9 ; 1 ; theYear ) ) - 1;
		1 ; 0 ; 6 ; 5 ; 4 ; 3 ; 2 );	// adjust for day of week of month start

@cd = "Columbus Day" ; // (2nd Monday in October)
cd = Date ( 10 ; 8 ; theYear )	// earliest possible date
      + Choose ( DayOfWeek ( Date ( 10 ; 1 ; theYear ) ) - 1;
      1 ; 0 ; 6 ; 5 ; 4 ; 3 ; 2 );	// adjust for day of week of month start

@vd = "Veterans Day" ; // (11 November)
vd = Date ( 11 ; 11 ; theYear );			

@td = "Thanksgiving Day" ; // (4th Thursday in November)
td = Date ( 11 ; 22 ; theYear )	// earliest possible date
      + Choose ( DayOfWeek ( Date ( 11 ; 1 ; theYear ) ) - 1;
      4 ; 3 ; 2 ; 1 ; 0 ; 6 ; 5	); // adjust for day of week of month start

@xe = "Christmas Eve" ; // (24 December)
xe =  Date ( 12 ; 24 ; theYear ) ;

@xd = "Christmas Day" ; // (25 December)
xd = Date ( 12 ; 25 ; theYear );
        
@nye = "New Years Eve" ; // (Last Day of Year)        
nye = Date ( 12 ; 31 ; theYear );

//LIST OF HOLIDAY DATES
major = List ( nyd ; id ; td ; xe ; xd ; nye ) ;
minor = List ( mlk ; pd ; md ; ld ; cd ; vd ) ;
dates = List ( nyd ; mlk ; pd ; md ; id ; ld ; cd ; vd ; td ; xe ; xd ; nye ) ; 

//LIST OF HOLIDYAY NAMES
holidayMajor = List ( @nyd ; @id ; @td ; @xe ; @xd ; @nye );
holidayMinor = List ( @mlk ; @pd ; @md ; @ld ; @cd ; @vd );
holiday = List ( @nyd ; @mlk ; @pd ; @md ; @id ; @ld ; @cd ; @vd ; @td ; @xe ; @xd ; @nye ) ; 


//RETURN HOLIDAY
~valueReplaced = Substitute ( ¶& dates &¶ ; ¶& theDate &¶ ; "¶•¶" ) ;
~value = Position (
		Substitute ( Filter ( ~valueReplaced ; "•¶" );
		[ ¶ ; "|" ] );
	"•" ; 1 ; 1 ) - 1 ;

name = GetValue ( holiday  ; ~value  ) ;

hCount = Choose ( Month ( theDate ) ; 0 ; 2 ; 1 ; 0 ; 0 ; 1 ; 0 ; 1 ; 0 ; 1 ; 1 ; 2 ; 3 )


];

Choose ( return ; dates ; holiday ; name ; hCount ; minor; holidayMinor; major; holidayMajor ) 

)

Here is my function for avoiding holidays and Friday's & Saturday's

/*
 * =====================================
 * HolidayShift ( theDate )
 *
 * RETURNS:
 *		The next workday not holiday, friday, saturday
 *
 * PARAMETERS:
 *		theDate
 *
 * DEPENDENCIES: 
 *       BusinessHolidays (theDate ; return)
 *
 * NOTES:
 *		
 *
 * HISTORY:
 *		MODIFIED on 2016-08-19 by Stephen Dolenski
 * =====================================
*/

Let ( [

@date= GetAsDate ( theDate ) ; 

@shift = @date  + not IsEmpty ( BusinessHolidays ( @date ; 2 ) ) ; 

@weekend = @shift + Case( DayOfWeek ( @shift ) = 6 ; 2 ; DayOfWeek ( @shift  ) = 7 ; 1  ) 

];

@weekend + not  IsEmpty ( BusinessHolidays ( @weekend  ; 2 ) )

)

This is the field that should return the results, the only extra thing is that we push forward all inspections that are tagged for AM to the next day (non holiday)  if they fall on Sunday.

Let ( [

a = HolidayShift ( Date ( Month(schedule::ScheduleDate) ; PlanDay ; Year ( schedule::ScheduleDate) ) ) ;

b = HolidayShift ( a ) ;

c = Case ( DayOfWeek ( b ) = 1 and AM_PM = "AM" ;  HolidayShift ( b + 1 ) ; b ) 


];

HolidayShift ( c )

)

I keep having to test each proposed date to make sure that is a real work day, thinking there is a better way to optimize this.

Link to comment
Share on other sites

46 minutes ago, Ocean West said:

keep having to test each proposed date to make sure that is a real work day, thinking there is a better way to optimize this.

I don't think so. There is no way to calculate if a date is a holiday without testing it against all possible holidays.

 

52 minutes ago, Ocean West said:

not IsEmpty ( BusinessHolidays ( @date ; 2 ) ) ;

That doesn't look right. Doesn't the function return a list of holidays in the year of @date? That list will never be empty.

Link to comment
Share on other sites

The first function will return the following: 

0 return list of major and minor dates
1 return list of major and minor holiday names
2 the name of the holiday if the date matches
3 count of holidays in the month
4 list of minor holiday dates
5 list of minor holiday names
6 list of major holiday dates
7 list of major holiday names

 

Quote

 

not IsEmpty ( BusinessHolidays ( @date ; 2 ) ) ;

 

that would return a 1 if it is a holiday 

Link to comment
Share on other sites

13 minutes ago, Ocean West said:

The first function will return the following: 

...
2 the name of the holiday if the date matches

<shrug> That's not what it says on the label.

Perhaps you should call the function only once, then test each date against the returned list. But you would have to mind the end of a year.

Link to comment
Share on other sites

This topic is 2806 days old. Please don't post here. Open a new topic instead.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.