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

Hello all,

 

I am trying to loop dates so that it returned something like this:

 

31jan2015:23:59:59.000

28feb2015:23:59:59.000

31mar2015:23:59:59.000

.

.

.

31jul2016:23:59:59.000

 

The code actually does not work:

 

data _null_;

do i = 1 to 19;

a = put(intnx('month',intnx('month',today(),-i),0,'end'),date9.);

call symput ('d',a||':23:59:59.000');

put "&d.";

end;

run;

 

Any suggestions? Thanks

 

Jiri

 

1 ACCEPTED SOLUTION

Accepted Solutions
Kurt_Bremser
Super User

Macro calls (everything starting with a & or %) are expanded immediately when encountered in the program text. So SAS tries to find the macro variable d before the data step (that creates a macro variable with call symput during runtime) is compiled and executed.

Try this for clarification:

data _null_;
do i = 1 to 19;
a = put(intnx('month',intnx('month',today(),-i),0,'end'),date9.);
call symput ('d',a||':23:59:59.000');
end;
run;
%put "d=&d.";

Since you seem to want to store a list of dates for later actions, it is better to store them in a dataset and use that later.

View solution in original post

13 REPLIES 13
Kurt_Bremser
Super User

Macro calls (everything starting with a & or %) are expanded immediately when encountered in the program text. So SAS tries to find the macro variable d before the data step (that creates a macro variable with call symput during runtime) is compiled and executed.

Try this for clarification:

data _null_;
do i = 1 to 19;
a = put(intnx('month',intnx('month',today(),-i),0,'end'),date9.);
call symput ('d',a||':23:59:59.000');
end;
run;
%put "d=&d.";

Since you seem to want to store a list of dates for later actions, it is better to store them in a dataset and use that later.

Uknown_user
Quartz | Level 8

Thanks for your help!

 

Jiri

Kurt_Bremser
Super User

And compare my previous post with this (look into the log):

data _null_;
do i = 1 to 19;
a = put(intnx('month',intnx('month',today(),-i),0,'end'),date9.);
d = a||':23:59:59.000';
put d=;
end;
run;
Uknown_user
Quartz | Level 8

I tried to run the code with your amendment but it for some reason fails to remember i's values. Any further suggestions? Thanks again

Kurt_Bremser
Super User

@Uknown_user wrote:

I tried to run the code with your amendment but it for some reason fails to remember i's values. Any further suggestions? Thanks again


This very much depends on what you want to do with your list of dates and index numbers.

Ksharp
Super User
data _null_;
do i = 1 to 19;
a = intnx('dtmonth',datetime(),-i,'end');
put a= datetime32.3;
end;
run;

Uknown_user
Quartz | Level 8

Thx for all suggestions. I used this code:

 

data _null_;

do i = 2 to 20;

a = intnx('dtmonth',datetime(),-i,'end');

call symput('a',put(a,datetime32.3));

end;

run;

%put a = &a;

 

However, the created list contains just one value. It says that macro variable a resolves just the last i's value:

 

"Macro variable A resolves to 31DEC2014:23:59:59.000"

 

I cannot get how come it does not store all dates?

 

Any tips? thx

 

Jiri

 

ballardw
Super User

 


The call symput named every value with the same macro variable name. Also, you only requested to see one value. You would have to assign multi macro variable names and then a different %put (or other approach) to see them.

 

Look at:

data _null_;
   length aname $ 10;
   do i = 2 to 20;
      aname = cats('a',i);
      a = intnx('dtmonth',datetime(),-i,'end');
      call symput(aname,put(a,datetime32.3));
   end;
run;
%put &a2 &a3 &a4 &a20;
Uknown_user
Quartz | Level 8

Thx, is there any way to store all values from the created list of dates and work with them as with single object (one macro variable)? Writing down all values might be complicated when the range gets bigger. When I put object "aname" from your code into macro variable:

 

%put a = &aname;

 

It says:

 

"WARNING: Apparent symbolic reference ANAME not resolved."

 

I am not quite sure how to work with arrays but it could help this problem?

 

Thanks for suggestions.

 

Jiri

ballardw
Super User

%put &aname fails because you did not create a MACRO varaible aname. You would have had to have a call symput("aname", ) for that.

 

Without knowing your exact useage it is a bit difficult to say what to put in the list. For instance if you want to use the values later such as this:

 

if somevariable in (<macro list>) then do ....

 

Then the values of the elements of the macro list probably should not be formatted datetimes as then you have to add quotes and DT to indicate they are date literals.

 

Here is one way to build a list that is comma separated, remove the comma from the "separated by ', ' " if you want spaces.

data temp;
   length aname $ 10;
   do i = 2 to 20;
      a = intnx('dtmonth',datetime(),-i,'end');
      output;
   end;
run;

proc sql noprint;
   select put(a,datetime32.3)  into : a separated by ', '
   from temp
   ;
quit;

%put &a;

Note the addition of creating a dataset and the output statment.

 

This approach may be the easiest overall for a single list because it does not requie pre-calculating the length of the character value that would be needed in the data step approach. There is a default maximum size for the length of a single macro variable do consider. If you are generating enough of these to approach the 65,000 characters your approach should be reconsidered.

 

If you describe what you are actually going to do with this list it would help as I suspect you are going to cause yourself more work than needed.

Uknown_user
Quartz | Level 8

Thanks for your reply. I am trying to produce the list of dates:

 

30JUN2016:23:59:59.000

31MAY2016:23:59:59.000

30APR2016:23:59:59.000

31MAR2016:23:59:59.000

29FEB2016:23:59:59.000

31JAN2016:23:59:59.000

31DEC2015:23:59:59.000

30NOV2015:23:59:59.000

31OCT2015:23:59:59.000

30SEP2015:23:59:59.000

31AUG2015:23:59:59.000

31JUL2015:23:59:59.000

30JUN2015:23:59:59.000

31MAY2015:23:59:59.000

30APR2015:23:59:59.000

31MAR2015:23:59:59.000

28FEB2015:23:59:59.000

31JAN2015:23:59:59.000

31DEC2014:23:59:59.000

 

which will consequently source the macro (each date should be one macro variable, so in the first step it goes for ... then ..., etc) . The format of datetime is required by the macro it self. Any suggestions how to aporoach this? Thanks

 

Kurt_Bremser
Super User
%let num_months=19;

data temp;
length datetime_value $ 10;
do i = 0 to &num_months - 1;
  datetime_value = intnx('dtmonth',datetime(),i,'end');
  output;
end;
run;

data _null_;
set temp;
call execute('%your_macro('!!put(datetime_value,best.)!!')');
run;

You only have to set the number of months, everything else happens dynamically, and the code is rather simple.

Anytime you need to work through a list of values, consider storing them in a dataset and working from that.

Uknown_user
Quartz | Level 8

Thanks for help!

 

Jiri

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
  • 13 replies
  • 3307 views
  • 2 likes
  • 4 in conversation