BookmarkSubscribeRSS Feed
hari5
Calcite | Level 5

%macro test(Indate=,OUTDTC=);

 

__&OUTDTC._INDAT = &Indate.;

 

if vtype(__&OUTDTC._INDAT) = "C" then do;
%let __INDAT_LEN=%sysfunc(length(__&OUTDTC._INDAT));
__&OUTDTC._INDAT1 = input(__&OUTDTC._INDAT,anydtdte&__INDAT_LEN..);
end;
else if vtype(__&OUTDTC._INDAT) ="N" then do;
%if &Indate. ne . %then %do; __&OUTDTC._INDAT1 = &Indate.; %end;
%else %do; __&OUTDTC._INDAT1 = .; %end;
end;
*ff=strip(upcase(&IS_INDATE_TYPE));
format __&OUTDTC._INDAT1 date9.;
%mend;

 

data hh;
dt='2023-03-20'; ti='01:20:00't;output;
dt='2022-04-22'; ti='12:45:00't;output;
dt='10MAR2020'; ti='12:33:00't;output;
format ti time.;
run;

 

data kk;
set hh;
%test(Indate=dt,OUTDTC=DTC1);
run;

 

When I run the above code getting "Character values have been converted to numeric values at the places given by: (Line):(Column)." But the date that I passed is character and why the else if condition is executing with numeric?

8 REPLIES 8
Kurt_Bremser
Super User

This can't work. Well, it works by accident.

At the time when the macro executes (when the code is fetched for the data step compiler), no data step variables exist, so you cannot know the length of those. The length you use for the informat will be the length of the variable name, not the length of the variable value.

 

Because you use __&OUTDTC._INDAT1 in an assignment from the INPUT function with a numeric informat, the data step compiler creates it as numeric, but later (in the "N" branch) it has to compile a direct assignment, so it will have to compile the conversion there (it will never be executed, but it has to be compiled). This is the reason for the message.

 

 

hari5
Calcite | Level 5
Thanks Kurt_Bremser, So we can not avoid that warning?
Kurt_Bremser
Super User

@hari5 wrote:
Thanks Kurt_Bremser, So we can not avoid that warning?

Not the way you try. You have to determine type and length in a preliminary step (from DICTIONARY.COLUMNS), and then have the macro write the complete data step according to the findings.

Tom
Super User Tom
Super User

I am not sure what the heck you are trying to do but there is no need to try and test the LENGTH() of the string you are trying to convert to a date (other than perhaps to make a decision about which informat to use).  That is because the INPUT() function does not care if the WIDTH used on the informat is larger than the length of the string that is being read.  So just use the maximum width that the informat supports.

__&OUTDTC._INDAT1 = input(__&OUTDTC._INDAT,anydtdte60.);

 

If you want to conditionally generate code based on the type of the variable you need to know that before the data step is compiled.  That way you only generate SAS code that is appropriate for the variable type. 

 

If you want to check attributes of a variable in an existing dataset with macro code so you can use the result to decide what SAS code to generate you can use this macro:  https://github.com/sasutils/macros/blob/master/varexist.sas 

 

By using the optional third parameter you can discover the variable's TYPE or its defined storage length (LEN).  You can even check what format (FMT) is attached to it.

 

hari5
Calcite | Level 5

Even if we remove the length statement we still get the warning. Don't think so length statement is giving any issue here. The purpose of the else if statement is we have both Character and numeric dates in the raw data and want to convert character to numeric and if Numeric date present keeping as it is. But it is not working with in the same step.

Tom
Super User Tom
Super User

@hari5 wrote:

Even if we remove the length statement we still get the warning. Don't think so length statement is giving any issue here. The purpose of the else if statement is we have both Character and numeric dates in the raw data and want to convert character to numeric and if Numeric date present keeping as it is. But it is not working with in the same step.


Exactly.  You have to know what code to generate.  So you need to know the type of the variable you are trying to convert BEFORE you start writing the data step code that uses that variable.

 

The easiest way is to use the %VAREXIST() macro.  So now you can write code like this:

data want;
  set have;
%if C=%varexist(have,orginal,type) %then %do;
  new = input(original,anydtdte60.);
%end;
%else %do;
  new = orginal;
%end;
  format new date9.;
run;  

So that you get either this data step when ORIGINAL is character:

data want;
  set have;
  new = input(original,anydtdte60.);
  format new date9.;
run;  

Or this data step when it is not.

data want;
  set have;
  new = orginal;
  format new date9.;
run;  

 

One trick you can use (whether it is helpful for your situation is up to you to decide) is to use the VVALUE() function to convert both numeric and character values into character values by getting their formatted value.

So code like this will run without errors or type conversion whether ORIGINAL is numeric or character.

data want;
  set have;
  length string $60;
  string=vvalue(original);
  new=input(string,anydtdte60.);
  format new date9.;
run;
hari5
Calcite | Level 5
Hi Tom - great %VAREXIST() works really well. Thanks so much!
ballardw
Super User

Please show the non-macro code that worked before you attempted this macro.

And maybe describe what it is intended to do.

 

My feeling is that this attempting to fix a problem from reading data incorrectly which usually should be addressed at that time.

 

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 8 replies
  • 1054 views
  • 0 likes
  • 4 in conversation