Using %sysfunc and %eval in SAS

Posts: 1

Using %sysfunc and %eval in SAS

Hi there,


I need to create a counter inside of a macro. I can get it to work fine with a data step, but I am having trouble getting it to work inside of the macro. Please could you help, I'm not sure if the %sysfunc is in the wrong place.


The code below was my attempt;


%let Start_date =%sysfunc(input(%sysfunc(strip(%sysfunc(put(201503,6.))))||'01',yymmdd10.));
%let Curr_Date =%sysfunc(input(%sysfunc(strip(%sysfunc(put(201505,6.))))||'01',yymmdd10.));

%let counter = %sysfunc(intck('month',&Start_date.,&Curr_Date.));
%put &counter.;

%do i = 1 %to &COUNTER.;


Thanks in advance. 


Note: using EG 7.1

Respected Advisor
Posts: 3,775

Re: Using %sysfunc and %eval in SAS

You can't use PUT or INPUT functions with %SYSFUNC use PUTC/PUTN or INPUTC/INPUTN you have other issues quotes where they should not be and concatenation operator.  Do you want the YYYYMM part of the date to be a variable? 


34         %let Start_date =%sysfunc(inputn(20150301,yymmdd10));
35         %let Curr_Date  =%sysfunc(inputn(20150501,yymmdd10));
36         %let counter = %sysfunc(intck(month,&Start_date.,&Curr_Date.));
37         %put NOTE COUNTER=&counter.;



Esteemed Advisor
Posts: 6,698

Re: Using %sysfunc and %eval in SAS

Ouch. Use a data step:

%let start=201503;
%let end=201505;

data _null_;
date_start = input("&start.01",yymmdd8.);
date_end = input("&end.01",yymmdd8.);
counter = intck('month',date_start,date_end);
call symput('counter',put(counter,best.));

Maxims of Maximally Efficient SAS Programmers
Respected Advisor
Posts: 3,775

Re: Using %sysfunc and %eval in SAS

@KurtBremser and @RW9 seem overly dismissive and a bit harsh in reply to @TFitz92 question.  While it might be true that it is much easier do run functions in data steps. Sometimes data steps cannot be used and whether that is the case here or not is irrelevant.


I appreciate @Quentin for explaining is detail the issues with the code presented and why it didn't work and how it can be improved.  

Esteemed Advisor
Posts: 6,698

Re: Using %sysfunc and %eval in SAS

Once I see 4(!) parentheses in direct succession, I know that somebody is about to outsmart her/himself.

Code like that is a horror to maintain.


KISS rules.

Maxims of Maximally Efficient SAS Programmers
Esteemed Advisor
Esteemed Advisor
Posts: 7,249

Re: Using %sysfunc and %eval in SAS

And why do you *need* to do it in macro?  Macro language is a syntax for generating text code which is then operated upon.  It doesn't have the strcutures needed to process data in an efficient way. Datastep is designed to process and manipulate data, hence would be a better fit for manipulating dates.

Now I don't know what the %do loop does or the rest of the code, so can't really advise there, however to get the ouptut:

data _null_;
  call symputx('counter', intck('month',"20150301"d,"20150501"d));

Reads far easier.  Obviously the example would change based on your other code.

Trusted Advisor
Posts: 1,216

Re: Using %sysfunc and %eval in SAS

@data_null__ already gave the answer, but I'll take a minute to expand on some of the general macro issues.


Consider this line:

%let Start_date =%sysfunc(input(%sysfunc(strip(%sysfunc(put(201503​,6.))))||'01',yymmdd10.));

You are trying to make a macro variable, Start_date, which will resolve the the SAS date for March 1, 2015.  A few points:



1.  In the inner most bit with putc you are trying to make the string 20150301 the pieces 201503 and 01.  In the data step language, you would use the PUT function to convert the numeric value to 201503 to text value "201503", and the concatenator operator to concatenate the text value "01" to that.  But in the macro language all data is text.  So if you want to concatenate 201503 with 01, you can do it with just:

%let SomeDate=20150301;

Okay, that's not clear because it looks like assignment of one value, not concatenation, so perhaps this is a better exmple:


%let yyyymm=201503;
%let SomeDate=&yyyymm.01;

With that, &SomeDate will resolve to 20150301.  There is no concactenation operator, and no put function to convert numeric values to chacter, beacuse the macro language all data is just text.  There are also no quotes around "01".  If you add quotes, they will become part of the value of SomeDate and will probably break things.  The macro language is a text manipulation language (used to build SAS code), not a data processing language.



2.  If you want to convert the text value 20150301 to the text value 20148 (This is the SAS date of March 1, 2015), you can use the INPUTN function. The INPUT function cannot be called by %SYSFUNC.

%let Start_Date=%sysfunc(inputn(20150301,yymmdd8));

3.  The INTCK function is happy to take SAS date literals instead of SAS date values.  This means you can also do something like below:



%let Start_Date="01MAR2015"d;
%let Curr_Date="01MAY2015"d;
%let Counter = %sysfunc(intck(month,&Start_Date,&Curr_Date));


To me, this is an example where the macro solution could actually read clearer than the data step solution, at least to my eyes.

Grand Advisor
Posts: 10,239

Re: Using %sysfunc and %eval in SAS

I agree that generally a direct assignment using the date literal format might be best. If this macro is eventually going to be used in such a form that you could pass the year and month a numerals then another option might work.


%let Start_date = %sysfunc(mdy(3,1,2015));

%let Curr_date = %sysfunc(mdy(5,1,2015));

The start date would have the numeric value of a SAS date literal which appears to mimic the original intent.


If you are going to make the months and years as parameters to a macro call:

%let Start_date = %sysfunc(mdy(&Start_Month,1,&Start_Year));

%let Curr_date = %sysfunc(mdy(&Curr_Month,1,&Curr_year));

Ask a Question
Discussion stats
  • 7 replies
  • 6 in conversation