%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;
Registration is open! SAS is returning to Vegas for an AI and analytics experience like no other! Whether you're an executive, manager, end user or SAS partner, SAS Innovate is designed for everyone on your team. Register for just $495 by 12/31/2023.
If you are interested in speaking, there is still time to submit a session idea. More details are posted on the website.
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.