I would like to check whether two period of date was overlapped or not.
%macro period(x,y);
%if &x < &y %then %let ret = %eval(&y-&x);
%else %let ret = 0;
&ret
%mend period;
data aa;
format c2 c1 yymmdd10.;
c2 = input( "2009/09/20", yymmdd10.);
c1 = input( "2009/09/28", yymmdd10.);
r1 = %period(c2,c1);
run;
Above script had no error but r1 = 0. (i.e. 2009/09/20 > 2009/09/28)
Why the result is =0 , not =8 ??
Thank you,
data aa;
format c2 c1 yymmdd10.;
c2 = input( "2009/09/20", yymmdd10.);
c1 = input( "2009/09/28", yymmdd10.);
call symput ('c2',c2);
call symput ('c1',c1);
r1 = %period(&c2,&c1);
put r1;
run;
Notice the difference? %period will not take expressions, rather, just strings.
Regards,
Haikuo
Dear Hai.kuo. Thank you for your quick response.
But the code does not work...
Best Regards,
Hi Hoz,
The reason why the code doesn't return 8 as you expect is due to tokenization with the SAS macro facility happening before the data step is being compiled and executed. The %period macro is being called but &c2 and &c1 in Haikuo's code doesn't exist yet due to the macros being in the symbol table only at data step execution.
You can modify your code to the following which works but I assume you want to apply this method to an entire dataset rather than just 1 row...
%macro period(x,y);
%if &x < &y %then %let ret = %eval(&y-&x);
%else %let ret = 0;
&ret
%mend period;
data aa;
format c2 c1 yymmdd10.;
c2 = input( "2009/09/20", yymmdd10.);
c1 = input( "2009/09/28", yymmdd10.);
call symputx('c2',c2);
call symputx('c1',c1);
run;
data bb;
set aa;
r1 = %period(&c2,&c1);
run;
Clearly if you have more than 1 observation then this method will not suit. As I am not sure what your overall requirement is then I am not sure how best to advise but I hope the above helps and shows you that you can get the value 8 as you expect.
Cheers,
Michelle
Dear Michelle,
Thank you for detailed description.
I have red Phuse's documents, however I don't understand the mechanism between macro phase and data step especially...
My final purpose was to check whether two period of date was overlapped or not.
The script that I thought was following:
%macro period(x1,y1,x2,y2);
%if &x1 le &y2 and &x2 le &y1 %then %do;
%if &x1 le &x2 %then %let start = &x2;
%else %let st = &x1;
%if &y1 le &y2 %then %let end = &y1;
%else %let end = &y2;
%let return = &&ed - &&st + 1;
%end;
&return
%mend period;
data aa;
a1 = "2009/08/29";
a2 = "2009/09/29";
b1 = "2009/09/28";
b2 = "2009/10/29";
format c1 c2 c3 c4 yymmdd10.;
c1 = input( a1, yymmdd10.);
c2 = input( a2, yymmdd10.);
c3 = input( b1, yymmdd10.);
c4 = input( b2, yymmdd10.);
x1 = %dupperiod(c1,c2,c3,c4);
run;
But it didn't work...so I thought to create more simple script, that was good approach at first.
My desire of macro was:
array a_start() a_start1-a_start10;
array a_end() b_start() b_end()
do i=1 to dim();
period&i = %period(a_starat, a_end, b_start, b_end);
end;
Best Regard,
Hi Hoz,
I highly recommend spending some time to read the Macro Language Reference guide starting at http://support.sas.com/documentation/cdl/en/mcrolref/62978/HTML/default/viewer.htm#p1ccprwibo8gvqn1q... or to attend a SAS Macro training course.
With regards to your code/task to create 10 start & end dates and then call your %period for each of them. I would probably use PROC SQL to create all the macro variables instead of a data step and then use a macro loop to call %period on the macro variables.
Example code on how to create macro variables using SQL can be found here: http://support.sas.com/documentation/cdl/en/mcrolref/62978/HTML/default/viewer.htm#n1y2jszlvs4hugn14...
Hope this helps.
Cheers,
Michelle
I believe the general rule for all coding must be to keep things as simple as possible.
In a "SAS context" this means to only use macro code if it can't be done in normal Base SAS language - which in your case is clearly not the case.
/* simple SAS datastep coding */
data aa;
format c2 c1 yymmdd10.;
c2 = input( "2009/09/20", yymmdd10.);
c1 = input( "2009/09/28", yymmdd10.);
if c2<c1 then r1=c1-c2;
else r1=0;
put r1=;
run;
If it must be a macro then below code would work:
/* using a macro */
%macro period(arg1,arg2,ret);
if &arg2<&arg1 then &ret=&arg1-&arg2;
else &ret=0;
%mend;
data aa;
format c2 c1 yymmdd10.;
c2 = input( "2009/09/20", yymmdd10.);
c1 = input( "2009/09/28", yymmdd10.);
%period(c1,c2,r1)
put r1=;
run;
It seems what you're actually trying to do is to create your own function. This is possible since SAS9.2 using PROC FCMP.
This can be very powerful - but also here I would use this option with great care and only if there is good reason as it complicates things (eg. if you start to build up your own function library and then use it everywhere so that even experienced SAS coders first need a year of induction to understand all your new functions in order to maintain the code you implemented).
/* creating and using a function */
proc fcmp outlib=work.funcs.myfuncs;;
function period(arg1,arg2);
if arg2<arg1 then ret=arg1-arg2;
else ret=0;
return (ret);
endsub;
run;
options cmplib=work.funcs;
data aa;
format c2 c1 yymmdd10.;
c2 = input( "2009/09/20", yymmdd10.);
c1 = input( "2009/09/28", yymmdd10.);
r2=period(c1,c2);
put r2=;
run;
Dear Michelle and Patrick,
I appreciate your useful advice.
Based on your advice, it'll be done in Base SAS.
My environment is in SAS 9.1, no use PROC FCMP.
If it'll have updated 9.2, i want to understand feature of PROC FCMP.
And i will learn the macro with url which of michelle advices.
Best Regard,
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
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.