BookmarkSubscribeRSS Feed
mikeydubs23
Calcite | Level 5

Been spinning my wheels on this so posting here because I know I'm overthinking it and coming up with nothing.

 

In my program I have an imported schedule.  The schedule may vary from "2,4,6" or "2,4" or even '"4" where those are days of the week.  The schedule will be dynamic and will be controlled outside the program; it's imported.  What is consistent is that the schedule will pull data since the last scheduled run so for example:

if the schedule is "2,4,6", the program will go back "3,2,2" days respectively.  I know that the formula for this is (today's weekday minus the most recent run day plus 7) then mod 7.  What I'm not sure about is an efficient way (or any) to get the left value when I'm talking about the first value.  I figured I could potentially use a coalesce (value to left, but otherwise the last value in list), but then I think I'm over-complicating this.  

 

I want this to be dynamic since the schedules won't be static.  Any advice?

 

 

11 REPLIES 11
Reeza
Super User

What's the most recent run day? Where is that defined?

Otherwise this seems pretty simple but it depends on how your data exists.

 


array run_dates(*) run_date1-run_date3 (2, 4, 6);

recentRunDayofWeek = run_dates(dim(run_dates)); 

parm1 = mod(run_dates(1)- recentRunDayofWeek +7, 7);
parm2 = mod(run_dates(2)-run_dates(1) + 7, 7);
parm3 = mod(run_dates(3)-run_dates(2) +7, 7);

 

Modified based on responses so far. If this does work, you can generalize it to a loop once you've determine how you're passing information back and forth.

Tom
Super User Tom
Super User

I have no idea what you are trying to describe.

What is it that you are trying to calculate?  It sort of sounds like you want to find the most recent day relative to today that the process was scheduled to run?  If so do you want to include today?

 

Provide concrete examples.  Show how the data you have coming in and what result you want. Make sure to post the example as a simple data step to create the data so it is easy to use and clearly shows the names and types of your variables.

mikeydubs23
Calcite | Level 5

The run schedule will be dynamic.  As an example, one internal customer may want the report run on weekdays 2,4,6 or Monday, Wednesday, and Friday.  Each day it's ran it will go back to the last time it was ran to pull data in.  Today being Monday, there is no value to the left to subtract exactly, but in that case we know that the last day it was run would be the last day of the array so in that case that's 6 or Friday so I know that's 3 days or as I was saying "2,4,6" becomes "3,2,2".  On Monday go back 3 days, on Wednesday, go back 2, and on Friday also go back 2 days.   Again, this is just an example and schedules could vary and it might be once a week or twice a week.

 

I figured I could use the new particular matching value from "3,2,2" array which could be called "Previous_dates_to_include" to subtract from today's date when today's weekday is in the original schedule array.

 

There will be potentially a couple dozen different schedules so this will all be "macrotized" and I was considering potentially converting it at the same time I convert the Excel spreadsheet to macro variables.

 

Thanks for getting back so quickly with your thoughts and additional questions!

Tom
Super User Tom
Super User

Still not following this completely, but it looks like there is a problem with your plan.  If you want to find the last time it ran you should keep track of when it ran, not depend on when it was supposed to run.  Things happen.

 

Are you asking how to implement such a planning system?  

If you just want make a way to represent which days of the week a process is schedule to run you really don't need the commas.  Just use a 7 character string.  You could store the digits 1 to 7.  So '246' or '23'.  or always have 7 characters and just use 0/1 (or any other pair of symbols) to mark if that day of the week is included.  So '0101010' or '0110000'.

 

Are you asking how to implement modulo indexing? 

today=1;
yesterday=today-1;
if yesterday<1 then yesterday=7;

 

mikeydubs23
Calcite | Level 5
Thanks Tom.
The content matter isn't so critical that a run log record would be required to insure it ran when it was supposed to run.
The schedule is imported from a single field (including the commas) in an Excel config sheet and then changed to an array for further processing. I'm going to use the SAS scheduler and macro in the program to iterate through the schedule to find out if it should run the particular internal customer each day if today's weekday is in the array.
mkeintz
PROC Star

I think you are saying that you are given a weekly schedule, showing specific days of the week for a given event.  And you want to calculate the number of days between each event and the most recent event, correct?  And the first event for a given week follows the last event for the prior week, which had the same schedule as the current week, yes?

 

Then:

data schedules;
  input sch1 sch2 sch3;
datalines;
2 4 6   /* M W F*/
1 3 5   /* Su Tu Th */
1 3 6   /* Su W Sa */
run;

data want (drop=s);
  set schedules;
  array _sch  {*} sch1-sch3;
  array _days {*} days1-days3;
  do s=1 to dim(_sch);
    if s=1 then _days{s}=  _sch{1}+7 - _sch{dim(_sch)} ;
    else _days{s}=_sch{s}-_sch{s-1};
  end;
run;

 

By using the "if s=1" statement, you don't really need to do mod7 arithmetic.

 

Editted supplement:  But if you really want to do MOD arithmetic, you can do it both on the array declaration (mod 3) and the result (mod 7):

 

data want2 (drop=s);
  set schedules;
  array _sch  {*} sch1-sch3;
  array _days {*} days1-days3;
  do s=1 to dim(_days);
    _days{s}= mod(_sch{s}+7 - _sch{mod(s+1,3)+1},7);
  end;
run;

In the case of the MOD7 component, you don't need to worry about generating a 7-day interval (which would be zero mod 7), since we assume three dates per week, with ascending values.   But you do need to do an adjustment for the MOD3 component - this avoids trying to subtract _SCH{1} minus _SCH{0} - which doesn't exist.

 

But even that can be avoided by changing the definition of the _SCH array.  This is probably the simplest code that avoid using an IF test:

 

data want3 (drop=s);
  set schedules;
  array _sch{0:3}  sch3 sch1-sch3;
  array _days {*} days1-days3;
  do s=1 to dim(_days);
    _days{s}= mod(_sch{s}+7 - _sch{s-1},7);
  end;
run;

The "trick" here is to define the _SCH array to have 4 elements, starting not at element 1, but at element 0 (which has the same value as element 3).  So when the array index S=1  you will get    _days{1} = _sch{1}+7 - _sch{0}  modulo 7.

 

 

 

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
mikeydubs23
Calcite | Level 5
Thanks mkeintz, this is on the right path. It works for the 3 day schedules, but I'll have to adjust to make it a little more dynamic (maybe counting the array first) to accommodate for schedules where it only runs once or twice or potentially more although that's not really a possibility currently.
mkeintz
PROC Star

This is the problem when you don't completely explain the task, as @Tom requested.  By "dynamic" I now understand you to mean  not only a variation in days of week, but also of number of events per week.  Please provide an actual sample data set in the form of a data step, and an example of what the resulting data set would look like.

 

Help us help you.

 

Supplement:  In the meantime, here is code that accepts whatever number of events per week you encounter (programmed to accept up to 5 here):

 

data schedules;
  infile datalines missover;
  input sch1 sch2 sch3 sch4 sch5 ;
datalines;
2 4 6   
1 3 5   
1 3 6   
1 2 3 4 6  
2
run;

data want (drop=_:);
  set schedules;
  _last_sch=max(of sch:);
  array _sch{*}  _last_sch sch: ;
  array _days {*} days1-days5;
  if n(of sch:)=1 then days1=7;
  else do _s=1 to dim(_days) while (not missing(_sch{_s+1}));
    _days{_s}= mod(_sch{_s+1}+7 - _sch{_s},7);
  end;
run;

 

Except for 1 day a week, this assumes that the first and last days of each week are different.

--------------------------
The hash OUTPUT method will overwrite a SAS data set, but not append. That can be costly. Consider voting for Add a HASH object method which would append a hash object to an existing SAS data set

Would enabling PROC SORT to simultaneously output multiple datasets be useful? Then vote for
Allow PROC SORT to output multiple datasets

--------------------------
mikeydubs23
Calcite | Level 5
Thanks.
Sorry I wasn't clearer.
To elaborate, I'm going to build a spreadsheet so programmers don't have to modify the actual program every time there's a new request for data or schedule change for the dozens of variations of the same report. I chose to capture the weekday schedule run as a single comma delimited string in the spreadsheet, I suppose I could have provided 7 fields in the spreadsheet, but I thought the comma delimited string was easier than 7 different fields. The schedule will determine which days of the week the program runs as the program will be scheduled to run every day and look to see if there was a request for data that day if weekday(today) is in the array schedule for that report request record from the imported spreadsheet. The program is required to include data since the last time it was scheduled and while ideally a log might be the perfect solution, this is the simpler solution and our automation on SAS server is fairly reliable so really just knowing to go back x number of days is good enough.
This i really an exercise in building a better automation mousetrap. We tend to leverage SAS as a powerful, dynamic reporting tool that really anything related to statistical analysis.
Tom
Super User Tom
Super User

@mikeydubs23 wrote:
Thanks mkeintz, this is on the right path. It works for the 3 day schedules, but I'll have to adjust to make it a little more dynamic (maybe counting the array first) to accommodate for schedules where it only runs once or twice or potentially more although that's not really a possibility currently.

Your ARRAY should have a dimension of 7.  And to find the last item don't use DIM() using N() instead to count the non-missing values.

mikeydubs23
Calcite | Level 5

Again thanks for all the help.  Her's what I settled on using your suggestions 

 

I had to switch the input to space delimited since I couldn't get commas to work, but the config file actually has many more elements so I created a single column dataset to show how it works.  One other thing I left out was that I was originally trying to do this with these values stored in macro variables and I would have set the days variable to a macro variable too, but datasets should work just as well.


data schedule;
infile cards ;
input Schedule $13.;
cards;
2 4 6
2 4
4
2 5
run;

 

data Schedule_Import (drop=_: i);
set Schedule (rename=(Schedule=_schedule));
array schedule(7);
i=1;
do until (scan(_schedule,i," ") eq "");
schedule(i)=scan(_schedule,i," ");
i+1;
end;
run;


data Schedule_Export (drop=_:);
set Schedule_Import;
_last_schedule=max(of schedule:);
schedule_count=n(of schedule:);
array _schedule{*} schedule: ;
put array _schedule{*} ;
array _days {*} days1-days7;
if schedule_count=1 then days1=7;
else do _s=1 to schedule_count;
if _s=1 then _days{_s} = mod(_schedule{_s} -_last_schedule +7 ,7);
else _days{_s} = _schedule{_s} - _schedule{_s-1};
end;
put exit;
run;

hackathon24-white-horiz.png

The 2025 SAS Hackathon has begun!

It's finally time to hack! Remember to visit the SAS Hacker's Hub regularly for news and updates.

Latest Updates

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 11 replies
  • 2633 views
  • 2 likes
  • 4 in conversation