%macro dt_date(date=,interval=,format=,offset=-1,alignment=B,quote=Y)/minoperator;
%put Start macro dt_date(date=&date,interval=&interval,format=&format,offset=&offset,alignment=&alignment,quote="e);
%local interval_temp;
%local d fmt rc dsid;
%if %superq(date)=%str() %then %let date=&dt_sas;
%let interval=%upcase(&interval);
%let quote=%upcase("e);
%let alignment=%upcase(&alignment);
%if &format ne %str() %then
%do;
%let fmt=%upcase(%sysfunc(compress(&format,%str(.),d)));
%let dsid=%sysfunc(open(sashelp.vformat(where=(fmtname="&fmt"))));
%let rc=%sysfunc(fetch(&dsid));
%let dsid=%sysfunc(close(&dsid));
%if &rc=-1 %then
%do;
%let errormsg1=&format is not a valid format.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%end;
%else
%do;
%let format=best.;
%let quote=N;
%end;
%let interval_temp=%scan(&interval,1,%str(.));
%let pos=%sysfunc(anydigit(&interval_temp));
%if &pos %then %let interval_temp=%substr(&interval_temp,1,%eval(&pos-1));
%if %eval(&interval_temp in YEAR QTR MONTH WEEK DAY YEARLY QUARTERLY MONTHLY WEEKLY DAILY)=0 %then
%do;
%let errormsg1=&interval is not a valid date interval.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%if %sysfunc(inputn(&offset, best.))=%str() %then
%do;
%let errormsg1=&offset is not a valid offset.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%if "e ne Y and "e ne N %then
%do;
%let errormsg1="e is not a valid Quote value. Must be Y or N.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%if &alignment ne B and &alignment ne E and &alignment ne M and &alignment ne S %then
%do;
%let errormsg1=&alignment is not a valid alignment value. Must be B, E, M, S.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%let date=%sysfunc(intnx(&interval,&date,&offset,&alignment));
%let d=%sysfunc(putn(&date,&format));
%if %superq(d)=%str() %then
%do;
%let errormsg1=&format is not a valid format.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%if "e=Y %then %let d=%unquote(%str(%')&d%str(%'));
%EXIT:
%unquote(&d)
%put End macro dt_date - Date Value returned is %unquote(&d);
%mend dt_date;
This code demonstrates why developers should spend the time to add inline comments with explanations.
I believe a "explain everything" is likely a too big ask for this forum.
I just tried and asked ChatGPT to explain the code. The answer wasn't too bad. I suggest you try this first and then come back here with some targeted detail questions should there still be a need. ....and of course if there are just some macro functions you don't understand first consult the SAS docu.
Adding to @Patrick 's comment about lack of comments, there is a complete lack of proper code layout to make it at least readable. That includes having blank lines between sections and indenting %DO blocks.
Adding to the other comments. Don't use the macro language when you can use ordinary SAS code. I wrote some multi-thousand line macros in my day. Of course they had macro code. That said, when ever possible, I used DATA _NULL_ DATA step code to process parameters and strings. It makes your life much easier.
It is an over complicated way to call the INTNX() function.
%sysfunc(intnx(&interval,&date,&offset,&alignment),&format)
If you are interested here is a partial list of the logic/coding mistakes:
%if %superq(date)=%str() %then %let date=&dt_sas;
%let fmt=%upcase(%sysfunc(compress(&format,%str(.),d)));
%if %sysfunc(inputn(&offset, best.))=%str() %then %do;
Assuming that PUTN() will return an empty string when the value is missing instead of the normal single period.%let d=%sysfunc(putn(&date,&format));
%if %superq(d)=%str() %then %do;
%unquote(&d)
Note it does not handle this format:
461 %put %dt_date(date='01JAN2023'd,interval=month,format=e8601da.,offset=-1,alignment=B,quote=Y); Start macro dt_date(date='01JAN2023'd,interval=month,format=e8601da.,offset=-1,alignment=B,quote=Y) End macro dt_date - Date Value returned is 462 %put %sysfunc(intnx(month,'01JAN2023'd,-1,b),e8601da.); 2022-12-01
I think I found out why - another error in the macro:
%let fmt=%upcase(%sysfunc(compress(&format,%str(.),d)));
This removes all digits from the format name, including the "8601" in "E8601DA.", so the format name becomes "EDA". The code does not flag this error though, as the code
%let errormsg1=&format is not a valid format.;
does not write the error message anywhere (and the variable is %LOCAL, unless it has been defined outside the macro).
For those who want to see what the macro does, here is a version in readable format:
%macro dt_date(date=,interval=,format=,offset=-1,alignment=B,quote=Y)/minoperator;
%put Start macro dt_date(date=&date,interval=&interval,format=&format,offset=&offset,alignment=&alignment,quote="e);
%local interval_temp;
%local d fmt rc dsid;
%if %superq(date)=%str() %then %let date=&dt_sas;
%let interval=%upcase(&interval);
%let quote=%upcase("e);
%let alignment=%upcase(&alignment);
%if &format ne %str() %then %do;
%let fmt=%upcase(%sysfunc(compress(&format,%str(.),d)));
%let dsid=%sysfunc(open(sashelp.vformat(where=(fmtname="&fmt"))));
%let rc=%sysfunc(fetch(&dsid));
%let dsid=%sysfunc(close(&dsid));
%if &rc=-1 %then %do;
%let errormsg1=&format is not a valid format.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%end;
%else %do;
%let format=best.;
%let quote=N;
%end;
%let interval_temp=%scan(&interval,1,%str(.));
%let pos=%sysfunc(anydigit(&interval_temp));
%if &pos %then %let interval_temp=%substr(&interval_temp,1,%eval(&pos-1));
%if %eval(&interval_temp in YEAR QTR MONTH WEEK DAY YEARLY QUARTERLY MONTHLY WEEKLY DAILY)=0 %then %do;
%let errormsg1=&interval is not a valid date interval.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%if %sysfunc(inputn(&offset, best.))=%str() %then %do;
%let errormsg1=&offset is not a valid offset.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%if "e ne Y and "e ne N %then %do;
%let errormsg1="e is not a valid Quote value. Must be Y or N.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%if &alignment ne B and &alignment ne E and &alignment ne M and &alignment ne S %then %do;
%let errormsg1=&alignment is not a valid alignment value. Must be B, E, M, S.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%let date=%sysfunc(intnx(&interval,&date,&offset,&alignment));
%let d=%sysfunc(putn(&date,&format));
%if %superq(d)=%str() %then %do;
%let errormsg1=&format is not a valid format.;
%let jumptoexit=1;
%let d=;
%goto EXIT;
%end;
%if "e=Y %then %let d=%unquote(%str(%')&d%str(%'));
%EXIT:
%unquote(&d)
%put End macro dt_date - Date Value returned is %unquote(&d);
%mend dt_date;
Join us for SAS Innovate 2025, our biggest and most exciting global event of the year, in Orlando, FL, from May 6-9. Sign up by March 14 for just $795.
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.
Ready to level-up your skills? Choose your own adventure.