A useful thing would be to run a macro loop with a changing date. It would be great if I could say
%macro justaloop; %do date ='31Jan1980'd %to '31Jan2000'd; <some code> %end; %mend; %justaloop;This is invalid because only integer values can be supplied as index values. SAS thinks that you're trying to loop starting with &date set to be the string '31Jan1980'd.
One option is to get the numeric version of the starting and ending dates and then use those in the loop:
%let startdate= '31Jan1980'd; %let enddate= '31Jan2000'd; %macro justaloop; %let startdate=%sysfunc(putn(&startdate, 8.)); %let enddate=%sysfunc(putn(&enddate, 8.)); %do date =&startdate %to &enddate; <some code> %end; %mend; %justaloop;
The statement
%let startdate=%sysfunc(putn(&startdate, 8.));
converts the contents of &STARTDATE from '31Jan1980'd to 7335.The %sysfunc macro function allows you to use DATA step functions in macro code. In this case, it allows me to use the PUTN function.
Using a %put statement to tell me how &STARTDATE changes (with options symbolgen on: see Section 9.2):
%let startdate= '31Jan1980'd; %let startdate=%sysfunc(putn(&startdate, 8.)); %put startdate is &startdate;
the following is written to the log:
%let startdate= '31Jan1980'd; %let startdate=%sysfunc(putn(&startdate, 8.)); SYMBOLGEN: Macro variable STARTDATE resolves to '31Jan1980'd %put startdate is &startdate; SYMBOLGEN: Macro variable STARTDATE resolves to 7335 startdate is 7335
The loop above does whatever some code does for each day between the two dates. However, in this loop I cannot adjust the interval by which the date counter is incremented. For instance, I might want to do something for each end-of-month between startdate and enddate.
To do that, I don't increment the date by 1, instead I increment it manually using a %SYSFUNC call to INTNX:
%let startdate= '31Jan1980'd; %let enddate= '31Jan2000'd; %macro justaloop; %let startdate=%sysfunc(putn(&startdate, 8.)); %let enddate=%sysfunc(putn(&enddate, 8.)); %let date=&startdate; %do %while(&date <= &enddate); <some code> %let date=%eval(%sysfunc(intnx(month, &date+1, 1))-1); %end; %mend; %justaloop;
Another option is to simply do it by year and month and use the mdy() function to convert it into a date as needed:
%macro justaloop; %do year=1963 %to 2007; %do month=1 %to 12; %let begofmonthdate=%sysfunc(mdy(&month, 1, &year)); %let endofmonthdate=%eval(%sysfunc(intnx(month, &begofmonthdate, 1))-1); <some code> %end; %end; %mend; %justaloop;
This is not very flexible.