%* genyyyymm Daniel Brockman 20110609 Generate yyyymm date sequence ; %macro genyyyymm(fr=201001,to=201112,ls=0,rt=1,mc=,argv=) ; /* gennyymm produces a monthly sequence of yyyymm dates and, /* optionally, executes a specified macro on each date. /* fr : first date of sequence yyyymm /* to : last date of sequence yyyymm. If to < fr, then /* the sequence goes from later to earlier. /* ls : if ls=0, then the next date in the sequence is fr. /* if ls=a date between fr and to, then use for ls the /* date last produced, the value stored in gyyyymm. /* if ls=to, then genyyyymm returns having done nothing. /* if ls=other value, then behavior is undefined. /* rt : if rt=1, then genyyyymm generates the next yyyymm date /* in the sequence and only that one, invokes the macro /* for that one, and returns to the caller. /* if rt=0, then genyyyymm cycles through the entire /* sequence before returning. /* if rt=other value, then behavior is undefined. /* mc : name of macro to invoke. genyyyymm finds the next date in /* the sequence, then executes mc. /* If mc="", then no macro is invoked. /* argv : a string, contained in 'single quotes', /* which is the list of arguments that /* macro genyyyymm passes to mc. may contain /* one of the calculated macro variables /* (see example below). /* /* gennyymm assigns these global macro variables, available to /* caller, to macro mc, etc.: /* gyyyymm : the value last produced in the sequence. /* On the next invocation of genyyyymm, use ls=&gyyyymm . /* gyyyymmdd : The LAST day of the month gyyyymm (yyyymmdd). /* dgymd : gyyyymmdd as a SAS date. /* /* Example: /* %genyyyymm(fr=201011, to=201102, ls=0, rt=0, /* mc=testomatic, /* argv='dog=horse,gmonth=&gyyymmdd.' ); /* /* Note: Situations can arise in which executing a macro /* within genyyyymm presents complex macro quoting problems. /* In such cases, set rt=1, and construct a loop within /* which to invoke genyyyymm, saving ls=&gyyyymm for the /* subsequent iteration. /* */ options nomprint nosymbolgen nomlogic ; %global gyyyymm dgymd gyyyymmdd ; %put T042 genyyyymm fr,to,ls,rt,mc,argv: &fr &to &ls &rt &mc &argv ; %let argy=&argv. ; /* save for later */ %let justin=1 ; /* first time thru loop */ %let sgn=1 ; %if ( &to < &fr ) %then %let sgn=-1 ; /* + or - */ %do %while( (&rt eq 0) or (&justin eq 1)) ; %let justin=0 ; /* not first time any more */ %let argv=&argy. ; /* restore original */ /* check for ls out of range. NOTE: this is our NORMAL EXIT */ %if ( &ls ne 0 ) %then %do ; %if ( (&sgn gt 0 and (( &ls lt &fr ) or ( &ls ge &to )) ) or (&sgn lt 0 and (( &ls gt &fr ) or ( &ls le &to )) ) ) %then %return ; %end ; %else %if &ls eq 0 %then /* initiating a sequence */ %let ls=%eval(&fr-(&sgn)) ;/* initiating a sequence */ %let lsmm=%substr(&ls,5,2) ; /* mm part of ls */ %let lsyyyy=%substr(&ls,1,4) ; /* yyyy part of ls */ %if &lsmm eq 00 %then %do; /* before january? */ %let lsmm=12 ; %let lsyyyy=%eval(&lsyyyy-1) ; %end; %else %if &lsmm eq 13 %then %do; /* after December */ %let lsmm=01 ; %let lsyyyy=%eval(&lsyyyy+1) ; %end ; %let lsyyyymmdd = &lsyyyy.&lsmm.01 ; /* first day of mo for ls */ /* express as sas date */ %let dlsyyyymmdd = %qsysfunc(mdy(&lsmm,1,&lsyyyy)) ; /* from this point, we continue the sequence by iterating one month ** from ls toward to. */ %let dlsyyyymmdd = %qsysfunc(intnx(%str(month),&dlsyyyymmdd,&sgn)); /* iterate */ /* at this point, dlsyyyymmdd is the 1st day of the month ** for which we want gyyyymmdd to be the last day of the ** month. */ /* compose gyyyymm gyyyymmdd dgymd */ %let nx1d = %qsysfunc(intnx(%str(month),&dlsyyyymmdd,1)) ; /* 1st of nxt mo */ %let dgymd = %qsysfunc( intnx( %str(day),&nx1d,-1 ) ) ; /* last day of gmo */ %let gyyyymm = %qsysfunc(month(&dgymd)) ; /* month part */ %if &gyyyymm < 10 %then %let gyyyymm = 0&gyyyymm ; /* ldg zero */ %let gyyyymm = %qsysfunc(year(&dgymd))&gyyyymm ; /* yyyymm */ %let gyyyymmdd = %qsysfunc(day(&dgymd)) ; /* day part */ %let gyyyymmdd = &gyyyymm.&gyyyymmdd. ; /* yyyymmdd */ %let ls = &gyyyymm ; /* hold ls for loop */ /* dress for subsequent use */ %let gyyyymm=%unquote(&gyyyymm) ; %let gyyyymmdd=%unquote(&gyyyymmdd) ; %let dgymd=%unquote(&dgymd) ; /* now we launch the macro */ %if ( ( &mc ne "" ) and ( &mc ne %str() ) and ( %unquote(&mc) ne %str() ) ) %then %do ; /* macro specified? */ %let argv=%unquote(%qscan(&argv.,1,%str(''))) ; /* remove qs */ %if ( (%str(&argv.) eq "" ) or (%str(&argv.) eq %str()) or (%str(&argv.) eq '' ) ) %then %let argv= ; %put 103.020 genyyyymm invoke macro mc:&mc w argv:&argv.: ; %put 103.040 genyyyymm gyyyymmdd:&gyyyymmdd: ; %&mc.(%unquote(&argv.)) ; ; /* invoke macro w argv */ %end ; /* if mc ne "" */ %end ; /* do while rt */ options mprint symbolgen mlogic ; %mend genyyyymm ; /* -------------------------------------------------- */ /**** begin test %* options ls=80 mlogic mprint symbolgen ; options ls=80 nomlogic nomprint nosymbolgen ; %macro testomatic(dog=dog,gmonth=) ; %put TEST101 testomatic dog:&dog gmonth:&gmonth ; %mend testomatic ; %macro testarama() ; %put TEST105 testarama gyyyymm:&gyyyymm gyyyymmdd:&gyyyymmdd ; %put TEST106 testarama dgymd:&dgymd %sysfunc(putn(&dgymd,date9.)) ; %mend testarama ; %put T111 TEST Let the games Begin ; %* full defaults ; %put T112 TEST bef gyyyymm:&gyyyymm gyyyymmdd:&gyyyymmdd ; %put T113 TEST bef dgymd:&dgymd %sysfunc(putn(&dgymd,date9.)) ; %genyyyymm() ; %put T114 TEST expecting 20100131 ; %put T115 TEST aft gyyyymm:&gyyyymm gyyyymmdd:&gyyyymmdd ; %put T116 TEST aft dgymd:&dgymd %sysfunc(putn(&dgymd,date9.)); %Put T120 execute macro with no args , cycle entire sequence; %genyyyymm(fr=201011,to=201102,ls=0,rt=0,mc=testarama); %put T123 TEST expecting 20110228 ; %put T124 TEST gyyyymm:&gyyyymm gyyyymmdd:&gyyyymmdd ; %put T125 TEST dgymd:&dgymd %sysfunc(putn(&dgymd,date9.)); %put T127 execute macro with no args, increment first month ; %genyyyymm(fr=201011,to=201102,ls=0,rt=1,mc=testarama); %put T129 TEST expecting 20101130 ; %put T130 TEST gyyyymm:&gyyyymm gyyyymmdd:&gyyyymmdd ; %put T131 TEST dgymd:&dgymd %sysfunc(putn(&dgymd,date9.)); %put T134 execute macro with no args, increment interm month ; %genyyyymm(fr=201011,to=201102,ls=201012,rt=1,mc=testarama); %put T135 TEST expecting 20110131 ; %put T136 TEST gyyyymm:&gyyyymm gyyyymmdd:&gyyyymmdd ; %put T137 TEST dgymd:&dgymd %sysfunc(putn(&dgymd,date9.)); %put T140 macro with args, cycle entire sequence; %genyyyymm(fr=201011,to=201102,ls=0,rt=0,mc=testomatic, argv='dog=Lassie,gmonth=&gyyyymmdd' ); %put T141 TEST expecting 20110228 gyyyymmdd:&gyyyymmdd ; %put T144 execute macro with args, increment first month ; %genyyyymm(fr=201011,to=201102,ls=0,rt=1,mc=testomatic, argv='dog=BlueTickHound,gmonth=&gyyyymmdd' ); %put T145 TEST expecting 20101130 gyyyymmdd:&gyyyymmdd ; %put T151 execute macro with args, increment interm month ; %genyyyymm(fr=201011,to=201102,ls=201012,rt=1,mc=testomatic, argv='dog=Baskervilles,gmonth=&gyyyymmdd' ); %put T152 TEST expecting 20110131 gyyyymmdd:&gyyyymmdd ; /* */