set previous month/year as macro variable in SAS - macros

I know something like this
%let start_date = %sysfunc(intnx(day,%sysfunc(date()),-1),DATE9.);
%put &start_date;
But
%let start_month = %sysfunc(month(intnx(month,%sysfunc(date()),-1),DATE9.));
%put &start_month;
or
%let start_date = %sysfunc(intnx(month,%sysfunc(date()),-1),DATE9.);
%put %sysfunc(month(&start_date));
doesn't work.

You need another %SYSFUNC before INTNX for your example to work.
%let start_month = %sysfunc(month(%sysfunc(intnx(month,%sysfunc(date()),-1))));
%put &start_month;
However, I prefer to use DATA NULL where a lot of %SYSFUNC statements are required with %LET. The following gives you the same result.
data _null_;
call symputx('start_month ', month(intnx('month',date(),-1)));
run;
%put &start_month.;

Related

SAS: macro error with date

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;

SAS Given a start & end date I need to know the dates of each 30 day period AFTER the first 35 days

I am am given 2 dates, a start date and an end date.
I would like to know the date of the first 35 day period, then each subsequent 30 day period.
I have;
start end
22-Jun-15 22-Oct-15
9-Jan-15 15-May-15
I want;
start end tik1 tik2 tik3 tik4
22-Jun-15 22-Oct-15 27-Jul-15 26-Aug-15 25-Sep-15
9-Jan-15 15-May-15 13-Feb-15 15-Mar-15 14-Apr-15 14-May-15
I am fine with the dates calculations but my real issue is creating a variable and incrementing its name. I decided to include my whole problem because I thought it might be easier to explain in its context.
You can solve the problem via following logic:
1) Determining number of columns to be added.
2) Calculating the values for the columns basis the requirement
data test;
input start end;
informat start date9. end date9.;
format start date9. end date9.;
datalines;
22-Jun-15 22-Oct-15
09-Jan-15 15-May-15
;
run;
/*******Determining number of columns*******/
data noc_cal;
set test;
no_of_col = floor((end-start)/30);
run;
proc sql;
select max(no_of_col) into: number_of_columns from noc_cal;
run;
/*******Making an array where 1st iteration(tik1) is increased by 35days whereas others are incremented by 30days*******/
data test1;
set test;
array tik tik1-tik%sysfunc(COMPRESS(&number_of_columns.));
format tik: date9.;
tik1 = intnx('DAYS',START,35);
do i= 2 to %sysfunc(COMPRESS(&number_of_columns.));
tik[i]= intnx('DAYS',tik[i-1],30);
if tik[i] > end then tik[i]=.;
end;
drop i;
run;
Alternate Way (incase you dont want to use proc sql)
data test;
input start end;
informat start date9. end date9.;
format start date9. end date9.;
datalines;
22-Jun-15 22-Oct-15
09-Jan-15 15-May-15
;
run;
/*******Determining number of columns*******/
data noc_cal;
set test;
no_of_col = floor((end-start)/30);
run;
proc sort data=noc_cal;
by no_of_col;
run;
data _null_;
set noc_cal;
by no_of_col;
if last.no_of_col;
call symputx('number_of_columns',no_of_col);
run;
/*******Making an array where 1st iteration(tik1) is increased by 35days whereas others are incremented by 30days*******/
data test1;
set test;
array tik tik1-tik%sysfunc(COMPRESS(&number_of_columns.));
format tik: date9.;
tik1 = intnx('DAYS',START,35);
do i= 2 to %sysfunc(COMPRESS(&number_of_columns.));
tik[i]= intnx('DAYS',tik[i-1],30);
if tik[i] > end then tik[i]=.;
end;
drop i;
run;
My output:
> **start |end |tik1 | tik2 |tik3 |tik4**
> 22Jun2015 |22Oct2015 |27Jul2015| 26Aug2015|25Sep2015|
> 09Jan2015 |15May2015 |13Feb2015| 15Mar2015|14Apr2015|14May2015
I tend to prefer long vertical structures. I would approach it like:
data want;
set have;
tik=start+35;
do while(tik<=end);
output;
tik=tik+30;
end;
format tik mmddyy10.;
run;
If you really need it wide, you could transpose that dataset in a second step.

use a character date string as a date in data step

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;

How To store SAS dates in a macro

I am trying to create different datasets with the names starting from a date which has data for different dates. When i am trying to run the code it is reading the date as numeric numbers and not as Dates. Here is the code
data dates;
input dates mmddyy8. name : $10. ;
format dates date9.;
cards;
01312015 swati
02282015 kangan
01232015 Gotam
04302015 Hushiyar
05172015 yash
09192015 Kuldeep
08302015 David
05172015 yash
11192015 Uninayal
11192015 Uninayal
12032015 sahil
;
data dates;
set dates;
format new date9.;
new=intnx('month', dates, 0, 'e');
run;
proc sql;
select distinct new into : new1 -: new8 from dates;
quit;
%put &new1.;
%macro swati;
%do i= 1 %to 1;
data data_&&new&i.;
set dates;
if new="&&new&i." then output data_&&new&i.;
run;
%end;
%mend;
%swati;
When I try running this code it gives me the error that says it is reading the dates stored in the macro as numbers. How do i make SAS read the dates as just dates only?

Creating a date exactly one month in the past in SAS

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;