BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
AllSoEasy
Obsidian | Level 7

Hey guys,

Ok so I have this code to calculate months between a numeric date range:

Example:

%let start_month = 200201;

%let end_month = 201301;

%let second_end_month = 201212;

%let start_yr = %eval(&start_month. / 100);

%let end_yr = %eval(&end_month. / 100);

%let start_mod = %modulo(&start_month.,100);

%let end_mod = %modulo(&end_month.,100);

%let yr_dif = %eval(&end_yr. - &start_yr.);

%let nmonths = %eval(12 * &yr_dif.);

%let temp1 = %eval(&nmonths - &start_mod.);

%let temp2 = %eval(&temp1 + &end_mod.);

%let num_observations = %eval(&temp2 + 1);

This is within a macro being called within my program, which sets different date ranges dependent on the current data being processed.

When I run this selection of code, it runs fine, and outputs the correct value when I check witha %put statement (133). However When I just run my entire program (which has been operating for some time without error, and this is the only piece of code added since), I receive the error:

" ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand

       is required. The condition was: 132 - 1;

ERROR: The macro SET_PRODUCT_SPECIFICS will stop executing. "

I don't understand this error, I don't understand why it is occuring in the same piece of code when run with the entire program, but not when the selection is run alone, also I don't see why "132-1" is not valid input for %eval().

Any help is greatly appreciated. Thanks!

-Ryan

1 ACCEPTED SOLUTION

Accepted Solutions
Astounding
PROC Star

Right issue, right solution.  You might be seeing how this plays out, but I'm not sure.  Inside a macro, the condition is %eval(132-1;)

Outside a macro, the condition is %eval(132-1)

In both cases, the original code generates something like:

%let start_mod = %eval( (201201 - 201201/100 * 100);;

I've taken out all the extra %evals, since they are not really needed.  But the difference is this.  Outside of a macro, the first semicolon ends the %let statement.  The second just becomes a null statement.  Inside a macro, the second semicolon ends the %let statement.  The first becomes part of the value of &START_MOD.

View solution in original post

6 REPLIES 6
art297
Opal | Level 21

What is %modulo?  Is it another macro?

AllSoEasy
Obsidian | Level 7

Yes, it is:

%macro modulo(a, b);                 

%eval(&a - %eval(%eval(&a/&b) * &b));

%mend; 

But we can see that that macro is not the issue because all of the lines execute properly up until

%let temp1 = %eval(&nmonths - &start_mod.); - which actually throws the error, after the preceding statement have resolved (if the modulo function did not work it wouldn't be passing in "132-1" on the error line, which are correct numbers from the preceding calculations.

art297
Opal | Level 21

Remove the semi-colon, in the modulo macro, in it's %eval line.  i.e., make it:

%macro modulo(a, b);                

%eval(&a - %eval(%eval(&a/&b) * &b))

%mend;

Astounding
PROC Star

In light of everything, does the code work fine when you run it in open code, but cause problems when you run it inside a macro definition?

art297
Opal | Level 21

: That is why I recommended that the OP remove the semicolon from within the function style macro that the initially posted set of %let statements .. inside a macro .. returns an error: The condition was: 132 - 1;

a %eval of 132-1;   will fail in a macro even though it would work in open code.  The semicolon at the end of the one line in the modulo macro will cause it to fail when called from within a macro.  If the OP removes it, it will work both in open code and in a macro.

Astounding
PROC Star

Right issue, right solution.  You might be seeing how this plays out, but I'm not sure.  Inside a macro, the condition is %eval(132-1;)

Outside a macro, the condition is %eval(132-1)

In both cases, the original code generates something like:

%let start_mod = %eval( (201201 - 201201/100 * 100);;

I've taken out all the extra %evals, since they are not really needed.  But the difference is this.  Outside of a macro, the first semicolon ends the %let statement.  The second just becomes a null statement.  Inside a macro, the second semicolon ends the %let statement.  The first becomes part of the value of &START_MOD.

sas-innovate-2024.png

Join us for SAS Innovate April 16-19 at the Aria in Las Vegas. Bring the team and save big with our group pricing for a limited time only.

Pre-conference courses and tutorials are filling up fast and are always a sellout. Register today to reserve your seat.

 

Register now!

How to Concatenate Values

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 6 replies
  • 974 views
  • 6 likes
  • 3 in conversation