I have a SAS EG 7.1 program that generates reports on a monthly basis. The old process was very manual, where users, amongst other things, were asked to update a macro variable (&date.) with current month-end (Date9.).
%let Date = '28feb2018'd; /* <--- Input the date to be reported */
/* Generate the year and the month based on the input date */
%let year = %sysfunc(year(&date.));
%let month = %sysfunc(month(&date.));
The &year (4-digit) and &month. (1- or 2-digit depending on the month) are later used in the code as components of a filename to pick up current month's tables:
FROM lib.great_table_loc_&year._&month.;
I am trying to make the program dynamic by prompting the user to chose the current month-end date.
The prompt is working, and outputs date9. format.
I then tried using the macro variable &Prompt_date. in the %sysfunc:
%let Date = '&prompt_date.';
%let year = %sysfunc(year(&prompt_date.));
%let month = %sysfunc(month(&prompt_date.));
When I execute, I get the following error messages:
1)
35 %let year = %sysfunc(year(&prompt_date.));
ERROR: Argument 1 to function YEAR referenced by the %SYSFUNC or
%QSYSFUNC macro function is not a number.
ERROR: Invalid arguments detected in %SYSCALL, %SYSFUNC, or %QSYSFUNC
argument list. Execution of %SYSCALL statement or %SYSFUNC
or %QSYSFUNC function reference is terminated.
36 %let month = %sysfunc(month(&prompt_date.));
ERROR: Argument 1 to function MONTH referenced by the %SYSFUNC or
%QSYSFUNC macro function is not a number.
ERROR: Invalid arguments detected in %SYSCALL, %SYSFUNC, or %QSYSFUNC
argument list. Execution of %SYSCALL statement or %SYSFUNC
or %QSYSFUNC function reference is terminated.
2)
118 lib.great_table_loc_._.
_
22
200
ERROR 22-322: Syntax error, expecting one of the following: a name, ;,
(, ',', ANSIMISS, AS, CROSS, EXCEPT, FULL, GROUP, HAVING,
INNER, INTERSECT, JOIN, LEFT, NATURAL, NOMISS, ORDER, OUTER,
RIGHT, UNION, WHERE.
ERROR 200-322: The symbol is not recognized and will be ignored.
I've tried creating a separate field for month and year, formatted to YYMMN6., input the &prompt_date. and then put(,n.) to make the value numeric - still nothing.
Has anyone encountered a similar problem?
Any tips on how to get what I want?
Thanks!
You have:
%let Date = '&prompt_date.';
%let year = %sysfunc(year(&prompt_date.));
%let month = %sysfunc(month(&prompt_date.));
Two issues.
you assign &Date but don't use it.
prompt date is DDMONYYYY (date9.). SAS will see that as a string. You need quotes and a d to make it a date.
Try
%let year = %sysfunc(year("&prompt_date."d));
%let month = %sysfunc(month("&prompt_date."d));
Related
I am trying to create last date of the month using sas macro. I set year-month yyyymm and would like to get last date of the month
%LET YYYYMM = 201501;
%LET SASDATE = %EVAL(%SYSFUNC(INTNX('MONTH',%SYSFUNC(MDY(%SYSFUNC(MOD(&YYYYMM,100)),1,%SYSFUNC(ROUND(%EVAL(&YYYYMM/100))))),1))-1);
%PUT &SASDATE;
I am getting the following error in the log file. which I don't understand
24 %LET YYYYMM = 201501;
25 %LET SASDATE =
25 ! %EVAL(%SYSFUNC(INTNX('MONTH',%SYSFUNC(MDY(%SYSFUNC(MOD(&YYYYMM,100)),1,%SYSFUNC(ROUND(%EVAL(&YYYYMM/100))))),1))-1);
WARNING: Argument 1 to function INTNX referenced by the %SYSFUNC or %QSYSFUNC macro function is out of range.
NOTE: Mathematical operations could not be performed during %SYSFUNC function execution. The result of the operations have been set
to a missing value.
ERROR: A character operand was found in the %EVAL function or %IF condition where a numeric operand is required. The condition was:
.-1
Can you please help? Thanks.
You can (and should!) use date formats and informats to deal with this sort of thing rather than doing your own date calculations, e.g.
%LET YYYYMM = 201501;
%put END_OF_MONTH = %sysfunc(intnx(month,%sysfunc(inputn(&YYYYMM,yymmn6.)),0,e),yymmdd10.);
Also, note that everything is text in the macro language, so you don't need to wrap text in quotes when using %sysfunc.
%sysfunc invoked functions do not require string literal arguments to be quoted. Remove the single quotes from 'MONTH'.
%let yyyymm = 201501;
%let yyyymm_date = %sysfunc(INPUTN(&YYYYMM,YYMMN6.));
%let next_month1 = %sysfunc (INTNX(MONTH,&YYYYMM_DATE,1));
%let want_yyyymm = %eval (&NEXT_MONTH1-1);
%let date9 = %sysfunc(putn(&want_yyyymm,date9.));
%let date9_literal = "&date9"d;
%put &=yyyymm;
%put &=yyyymm_date;
%put &=next_month1;
%put &=want_yyyymm;
%put &=date9;
%put &=date9_literal;
----- LOG -----
YYYYMM=201501
YYYYMM_DATE=20089
NEXT_MONTH1=20120
WANT_YYYYMM=20119
DATE9=31JAN2015
DATE9_LITERAL="31JAN2015"d
Example use of the macro variables
title "Report for month ending &date9.";
proc print data=have;
where date <= &date9_literal;
...
run;
I have the following two macro variables:
%let start_date = 29MAY2014;
%let end_date = 15JUL2014;
I would like to create a dataset which is a series of dates between these (inclusive.) I cannot change the input format of the macro variables &start_date and &end_date.
I have tried many variations of the following, but SAS spits out an error for each:
data base_dates;
do date = put("&start_date",date9.) to put("&end_date",date9.);
output;
end;
format date date11.;
run;
Any help in this would be much appreciated
Use them as date literals, enclose in quotes and add a d at the end.
Do date = "&start_date"d to "&end_date"d;
It was simple; input() instead of put()
data base_dates;
do date = input("&start_date",date9.) to input("&end_date",date9.);
output;
end;
format date date11.;
run;
Parameters start_date, end_date & output_vars. Dates are charter string. How can I convert it in a macro?
data _null_;
start =;
end = ;
diff=end date-startdate;
days = intck('day',start,end);
weeks = intck('week',start,end);
months = intck('month',start,end);
year = intck('year',start,end);
put days= weeks= months= year=;
run;
First if you have macro parameters then they will be macro variables and not data step variables. So you you need to reference the parameter value as &START_DATE, etc.
Second you can use the %SYSFUNC() macro function to call the INTCK() function in macro code.
Third you need to know the date format that will be used by the parameters. It is easiest if you just request that they use DATE format, then you can use the parameter values as date literals.
%let start_date=01JAN2015 ;
%let end_date=01JAN2016 ;
%let days = %sysfunc(intck(day,"&start_date"d,"&end_date"d));
I have created a macro variable which is the datetime at the time the program is run less one month, formatted to datetime20:
%let startDate = %sysfunc(intnx(dtmonth, %sysfunc(datetime()), -1), datetime20.);
This part works correctly (if I run it right now, it returns 01JUL2015:00:00:00), but what I want to do is subset a dataset based on this date in a PROC SQL statement. Basically I want to keep everything where the date occurs in the last month. My code is:
proc sql;
create table work.last_month as
select * from work.existing_table
where date >= &startDate.;
quit;
The column "date" and the variable "startDate" are both of type 'datetime20', but it is still throwing an error:
ERROR 22-322: Syntax error, expecting one of the following: ;, !, !!, &, *, **, +, -, /, <, <=,
<>, =, >, >=, AND, EQ, EQT, EXCEPT, GE, GET, GROUP, GT, GTT, HAVING, INTERSECT,
LE, LET, LT, LTT, NE, NET, NOT, OR, ORDER, OUTER, UNION, ^, ^=, |, ||, ~, ~=.
I don't know why it is throwing this error. What am I doing wrong?
Thanks!
The macro processor is a code generator so your code is generating
proc sql;
create table work.last_month as
select * from work.existing_table
where date >= 01JUL2015:00:00:00;
quit;
This isn't valid SAS code.
You can either use the SAS datetime number rather than convert/format it to a datetime value, or create a date literal for comparison.
To create a date literal, enclose the macro variable in quotes and end it with dt to indicate a datetime value.
proc sql;
create table work.last_month as
select * from work.existing_table
where date >= "01JUL2015:00:00:00"dt;
quit;
To create a SAS datetime numeric value, remove the format in the %sysfunc().
%let startDate = %sysfunc(intnx(dtmonth, %sysfunc(datetime()), -1));
proc sql;
create table work.last_month as
select * from work.existing_table
where date >= &startDate.;
quit;
Your problem is you are formatting the result - don't do that. Remember, macro variables are just creating text, they're not actual variables - they don't have concepts like "formats" (where a regular SAS variable is able to be the numeric date value AND the "pretty" formatted text).
1 %let startDate = %sysfunc(intnx(dtmonth, %sysfunc(datetime()), -1), datetime20.);
2 %put &=startdate.;
STARTDATE=01JUL2015:00:00:00
So:
proc sql;
create table work.last_month as
select * from work.existing_table
where date >= 01JUL2015:00:00:00;
quit;
That's illegal, because that's not a datetime value, it's a nice pretty human readable datetime that SQL/SAS looks at and doesn't know what to do with.
You can either drop the format bit from the %sysfunc, or add "..."dt around it to make it a datetime constant.
data existing_table;
do date=datetime()-86400*50 to datetime() by 86400;
output;
end;
run;
proc sql;
create table work.last_month as
select * from work.existing_table
where date >= "&startdate."dt;
quit;
I am trying to create two datetime variables in SAS 9.3. The first, "endDate" is the current datetime at the time the program is run. The second, "startDate" is exactly one month in the past.
My code is:
%let endDate = %sysfunc(DATETIME() datetime.);
%let startDate = %sysfunc(intnx('month', DATETIME(), -1) datetime.);
Based on any documentation I can find, I can't figure out what is wrong with it, but I am getting the following error message:
"ERROR: Expected close parenthesis after macro function invocation not found."
What am I doing wrong?
Some additional background: I want to use these two macro variables inside a proc sql statement so I can filter a table to data from within the past month at the run-time.
Thanks!
You have a couple of issues:
%sysfunc() takes two parameters, the second one is optional, but it does need to be separated by a comma.
Your use of DateTime() function in the intnx function also requires a %sysfunc()
You have datetime variables so you need to use DTMONTH as your interval instead of month.
You don't need quotes around literals in a macro call
%let endDate = %sysfunc(DATETIME(), datetime.);
%put &endDate;
%let startDate = %sysfunc(intnx(dtmonth, %sysfunc(datetime()), -1), datetime.);
%put &StartDate;
Four things:
You don't need the single quotes around string arguments when calling functions via %sysfunc
You need to use a %sysfunc for every individual data step function you want to call in the macro environment, which means you need to nest them in this case as you're calling one function inside another. This can get messy.
You need to increment your datetime by a datetime-month increment, not a month increment, so use dtmonth instead of month.
You need a comma between the function call and the format within %sysfunc
Putting it all together:
%let endDate = %sysfunc(DATETIME(), datetime.);
%let startDate = %sysfunc(intnx(dtmonth, %sysfunc(DATETIME()), -1), datetime.);
%let endDate = %sysfunc(DATETIME(), datetime21.);
%let startDate =%sysfunc(putn(%sysfunc(intnx(dtmonth, %sysfunc(DATETIME()), -1,same)),datetime21.));
%put &enddate &startdate;