Good afternoon,
I know there is some way to do this via %SYSFUNC (or so I have heard), but I am having a very difficult time getting much to work and was wondering if anyone else here has ever encountered this same problem.
Basically, all I need to do is have this macro return a numeric result, so that I can utilize it something like:
data s1 ;
date_x = 22;
date_y = 33;
date_z = %getepoch(path) ;
run;quit;
The point of the macro itself is simply to derive the Unix epoch time for a supplied (non-epoch'ed) date.
I have most of what I need already working, but I still don't think the macro is returning an assignable value.
An additional problem or question might be: is there any way to replicate the Powershell execution piece of functionality without invoking 'filename process pipe' ?
I think that section in particular is breaking something in the SAS interpreter. I have pasted a screenshot of that at the following URL: output-log-d — ImgBB (ibb.co)
[actual URL plaintext = https://ibb.co/K9hssG3]
Code snippet is provided below. Side note: I'm pretty sure my numeric format or bestd20 is wrong somehow (still working on that). Thanks in advance if anyone has some ideas on how to fix this.
/* code */
%macro getepoch(twopath);
%let twopath = %sysfunc(quote(%qsysfunc(dequote(&path))));
filename process pipe
"powershell -File C:\Temp\gepoch.ps1 "&twopath."";
data processes;
infile process ;
length
time 8;
format time bestd20. ;
input time;
run ; quit;
proc sql;
select time into :t2 from processes ;
quit;
%put &t2. ;
%mend getepoch;
%let path="C:\Temp\output9.txt" ;
%getepoch(path) ;
data s1 ;
x = 22;
y = 33;
z = %getepoch(path) ;
run;quit;
How about wrapping 4GL in a %sysfunc(DoSubL(...)) sandwich?
%macro getepoch(path);
%local t2;
%LET RC = %SYSFUNC(DOSUBL(%STR( /* <- sandwich start */
filename process pipe
"powershell -File C:\Temp\gepoch.ps1 ""&path.""";
data processes;
infile process ;
length
time 8;
format time bestd20. ;
input time;
run ; quit;
proc sql;
select time into :t2 from processes ;
quit;
))); /* <- sandwich end */
&t2.
%mend getepoch;
%let path=C:\Temp\output9.txt ;
%getepoch(&path.) ;
data s1 ;
x = 22;
y = 33;
z = %getepoch(&path.) ;
run;quit;
Bart
Is macro variable &t2 inside macro %getepoch a number? Seems like an important detail which you haven't mentioned.
If it is a number, you can add (at the top of your code)
%local t2;
then run the macro and next in your data step
z=&t2;
If it is not a number, then we can't help you.
TYPO
I should have used %GLOBAL and not %LOCAL
I have used the %local variables before, but I was trying to do this in such a way that I can just dynamically call the macro anywhere in open code and be guaranteed a result.
Again, I should have said %GLOBAL, and then you can do exactly what you just said, your value of &t2 can be used anywhere.
It might help to describe what the purpose is.
Pretty much can guarantee and macro that calls a data step or other procedure will not do what you want with an assignment inside a data step. As soon as the macro generated data step or proc boundary is found then the previous data step calling the macro will 1) terminate 2) likely with a syntax error because what followed the Z= was not a valid assignment:
Your example code would include the "statement"
Z = filename process pipe "powershell -File C:\Temp\gepoch.ps1 "&twopath."";
which is not a valid call to the FILENAME function in a data step.
When I see statements like " (for as many rows as I need to generate later), and then do my top 20 or top 30 data sets with included " one starts suspecting the problem definition needs to be revised as "generating rows" is maybe better accomplished outside of macro coding.
How about wrapping 4GL in a %sysfunc(DoSubL(...)) sandwich?
%macro getepoch(path);
%local t2;
%LET RC = %SYSFUNC(DOSUBL(%STR( /* <- sandwich start */
filename process pipe
"powershell -File C:\Temp\gepoch.ps1 ""&path.""";
data processes;
infile process ;
length
time 8;
format time bestd20. ;
input time;
run ; quit;
proc sql;
select time into :t2 from processes ;
quit;
))); /* <- sandwich end */
&t2.
%mend getepoch;
%let path=C:\Temp\output9.txt ;
%getepoch(&path.) ;
data s1 ;
x = 22;
y = 33;
z = %getepoch(&path.) ;
run;quit;
Bart
I did not realize that DOSUBL would work like this inside of a macro. So now I have caught up to @Kurt_Bremser , I have learned a new thing today: a new use case for DOSUBL.
This is still quite a lot of arcane programming just to make &t2 available outside of the the macro, which is "less arcane" programming. But the idea of calling the macro wherever the user wants to call it, such as within a data step, still bothers me when you could just use &t2 in that data step. However, if that's what the OP wants...
Yabwon,
Thank you for the help. This is a really clever solution, and it seems to test just fine on my system.
Good news: We've extended SAS Hackathon registration until Sept. 12, so you still have time to be part of our biggest event yet – our five-year anniversary!
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.