Subtract date from macro variable - date

I'm having trouble subtracting a date from a Macro Variable.
Currently, I create a macro variable by running:
%LET date = %SYSFUNC(TODAY(),MMDDYY10.);
I feel like I should be able to subtract 1 day from &date by doing the following:
%LET newDate = %SYSFUNC(%INTNX('day',&date,-1),date9.);
However, this produces the error:
ERROR: Function name missing in %SYSFUNC or %QSYSFUNC macro function reference.
I need the output for &newDate to be in date9.
Any help would be appreciated, thanks!

Quick answer:
%LET date = %SYSFUNC(TODAY());
%LET newDate = %SYSFUNC(INTNX(day,&date,-1),date9.);
%put &=newdate;
Explanation:
Firstly, best to remove the formatting from &date to ensure it is interpreted correctly as a date. Your original code resolved (today) inside intnx() to 12/06/2016, which then resolved to 12 divided by 6 divided by 2016 - etc.
Secondly, the inner function to %sysfunc() should be a datastep function - indeed, the whole point of %sysfunc() is to bring these functions into sas. %intnx() isn't a macro function, but if if was, then by definition you wouldn't need to wrap it in %sysfunc().
Finally, the 'day' parameter shouldn't be quoted - everything in sas macro is treated as text by default.

#RawFocus, you are correct that there is no need to format the original date (today's date), and it is easier to deal with that way.
Just for completeness, if someone wanted to apply the MMDDYY10. format, this is how it could be done:
%LET date = %SYSFUNC(TODAY(),mmddyy10.);
%LET newDate = %SYSFUNC(INTNX(day,%SYSFUNC(INPUTN(&date,mmddyy10)),-1),date9.);
%put &=date &=newdate;

Related

SAS: Get current year in YY format

I want to assign the current year in a YY format to either a macro or data set variable.
I am able to use the automatic macro variables &sysdate or &sysdate9 to get the current date. However, extracting the year in a YY format is proving to be a nightmare. Below are some examples of what I've been trying.
There exists the YEARw. format. But when I try to use it I get errors or weird results. For instance, running
data _null_;
yy = year(input("&sysdate9.", year2.));
put yy=;
run;
produces the error
ERROR 48-59: The informat YEAR was not found or could not be loaded.
If I try to format the variable in the output, I get 1965 instead of the current year. The following
data _null_;
yy = year(input("&sysdate9.", date9.));
put yy= yy year2.;
run;
outputs
yy=2016 65
Please help.
This works to get you the 2-digit year number of the current year:
DATA _NULL_;
YEAR = PUT(TODAY(),YEAR2.);
PUT YEAR;
RUN;
/* Returns: 16 */
To breakdown what I am doing here:
I use TODAY() to get the current date as a DATE type. &SASDATE needs to be converted to a DATE, but also it is the date that the SAS session started. TODAY() is the current date.
PUT allows us to pass in a non-character (numeric/date) value, which is why it is used with TODAY() as opposed to INPUT.
I think it is worth exploring the issues here in more detail.
First, Formats are patterns for converting numeric values to a human readable format. That's what you want to do here: convert a date value to a human readable format, in this case to a year.
Informats, on the other hand, convert human readable information to numeric values. That's not what you're doing here; you have a value already.
Second, put matches with Formats, and input matches with informats, exclusively.
Third, you get close in your last try: but you misuse the year format. Formats are basically value mappings, so they map every possible numeric value in their range (sometimes "all values" is the range, sometimes not) to a display value (string). You need to know what kind of value is expected on the input. YEARw. expects a date value as input, not a year value: meaning input is "number of days from 1/1/1960", mapped to "year". So you cannot take a value you've already mapped to a year value and map it again with that method; it will not make any sense.
Let's look at it:
data _null_;
yy = year(input("&sysdate9.", date9.));
put yy= yy year2.;
run;
yy contains the result of the year function - 2016. Good so far. Now, you need the 2 digit year (16); you can get that through mod function, if you like, or put/substr/input:
data _null_;
yy = input(substr(put(year(input("&sysdate9.", date9.)),4.),3,2),2.);
put yy=;
run;
mod is probably easier though since it's a number. But of course you could've used year:
data _null_;
yy = put(input("&sysdate9.", date9.),year2.);
put yy=;
run;
Now, yy is character, so you could wrap that with input(...,2.) or leave it character depending on your purposes.
Finally - a use note on &sysdate9.. You can easily make this a date without input:
"&sysdate9."d
So:
yy = put("&sysdate9."d,year2.);
That's called a date literal (and "..."dt and "..."t also work for datetime,time). They require things in the standard SAS formats to work properly.
And as pointed out in Nicarus' answer, today() is a bit better than &sysdate9 since it is guaranteed to be today. If you're running this in batch or restart your session daily, this won't matter, but it will if you have a long-running session.
Apply the year function to the date variable
Convert to string
Take last 2 digits
EDIT: change input to PUT
Year = substr(put(year(today()), 4.), 3);

concatenation in sas using macro

I have two variables with me
%let End_of_month =%sysfunc(intnx(month,'&sysdate'd,-1,e),yymmdd10.);
%stamp =00:00:00
Now, i want to create a new variable
%time_stamp = '2016-06-19 00:00:00'
In order to make this variable , i am using cat function with sysfunc
%timestamp =%sysfunc(cat("'","&End_of_month".,"&stamp.","'"));
The above code is not giving me the desired results. Could somebody tell me how do I solve this using a %sysfunc.
I am not really sure how to use %str and nstr in this statement. Please let me know how can we solve cats, cat and catx in a macro.
Thanks
You initial 2 macro variable are wrong. Then End_of_month should rather be like this
%let End_of_month =%sysfunc(intnx(month,%str(%')&sysdate%str(%'d),-1,e),yymmdd10.);
%put &End_of_month;
OR
%let End_of_month =%sysfunc(intnx(month,%sysfunc(today()),-1,e),yymmdd10.);
%put &End_of_month;
Now coming to the creating a single quotation timestamp with 00:00:00 hr:min:sec afte the date with space as the delimiter, you don't have to use base SAS functions.. simply create the variable like below
%let timestamp=%str(%')&End_of_month 00:00:00%str(%');
%put &timestamp;
Also, %stamp means a macro call which has a definition and not a variable like you've mentioned in your questions.. similarly %timestamp= .. this is syntactically wrong in SAS.. %let timestamp= does macro variable creation and %timestamp would ideally call a timestamp named macro definition..I would suggest reading the SAS Macro Language Reference.
The best way to solve this problem (if it is something you do often) is to create your own format to do so. See this answer:
https://stackoverflow.com/a/24044451/214994
You do not need to use functions to concatenate macro variables. Just expand them where ever you need them in your code. Note also that you do not need to quote string literals in macro code. To the macro processor everything is a string literal.
%let end_of_month=%sysfunc(intnx(month,"&sysdate"d,-1,e),yymmdd10.);
%let time_stamp=&end_of_month 00:00:00;
Adding double quotes is simple.
%let time_stamp="&end_of_month 00:00:00";
Adding single quotes is a pain because the macro references are not resolved inside of single quotes. You could try using %bquote(), but then the value is macro quoted, which can cause trouble. So you might need to also add %unquote().
%let time_stamp=%unquote(%bquote('&end_of_month 00:00:00'));
I have found using the dequote() function is a simple way to introduce single quotes. Start with a string that has double quotes on the outside so that the macro references work and then use %sysfunc(dequote()) to remove the double quotes.
%let time_stamp=%sysfunc(dequote("'&end_of_month 00:00:00'"));

How to use a macro variable to be lagged like a date in SAS

I'm using SAS. I have more datesets, one per month and I have to compute variations, means etc. considering more datasets (months) at the same step of the macro because for example for VAR1 I have one value in the dataset of january (month x) and one value in the dataset of february (month x+1).
The datasets are named in this way: xxxxxx_yearmonth (for example yearmonth=201512 for december 2015)
So I have to create a macro variable called yearmonth that can be lagged for more months so I can recall them.
I thought to recall the datasets with the macro variable yearmonth and do: yearmonth - 1 ... yearmonth - 2 ... yearmonth - n. But there is a problem because if is january 2015 yearmonth=201501 and yearmonth-1=201500 and not 201412. The fact is that SAS doesn't recognize yearmonth like a date but treat it like a simple number.
How can I manage this problem?
Thanks in advance.
Convert the string to a date and use the INTNX() function.
%let current=201501;
%let prev=%sysfunc(intnx(month,%sysfunc(inputn(&current.01,yymmdd8)),-1),yymmn6);
%put &=prev;
Try using intnx in combination with sysfunc and the format yymmn6.
Something like:
%let yearmonth1 = %sysfunc(intnx(month,%sysfunc(inputn(&yearmonth,yymmn6.)),-1),yymmn6.);
Or more simple the datastep Version (also better for looping through it):
data _null_;
do i = 1 to 6;
monthid = put(intnx('month',input("&yearmonth",yymmn6.),-i),yymmn6.);
call symput(cats('yearmonth',i),monthid);
end;
run;

Conversion of SAS Macro Variable to time stamp

I am trying to convert SAS Macro variable to timestamp and stumped while conversion. The code which I am using is given below.
%let date = '03/15/2013';
%put %sysfunc(inputn(&date,datetime26.6));
Error which I am getting is
WARNING: Argument 1 to function INPUTN 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.
Please let me know if someone knows answers to this.
That is not a DATETIME, that is a DATE format (to INPUT, which depends on the incoming data, not the outgoing). You also need to remove the quotes, SYSFUNC treats quotes as characters, not as string delimiters.
%let date = 03/15/2013;
%put %sysfunc(inputn(&date,MMDDYY10.));
To actually create the datetime, you need to use PUT:
%let date = 03/15/2013;
%put %sysfunc(putn(%sysfunc(dhms(%sysfunc(inputn(&date,MMDDYY10.)),0,0,0)),datetime26.));
However, the better way to do this if you can is to use a date constant...
%let date=15MAR2013;
%put "&date."d;
Joe is mostly correct. If you want a datetime string of midnight 3/15/13, then use
%let date = 03/15/2013;
%put %sysfunc(putn(%sysfunc(dhms(%sysfunc(inputn(&date,MMDDYY10.)),0,0,0)),datetime26.));
Just using PUTN on a date string to "convert" a date to datetime will convert the number of days from epoch (01JAN1960) to the number of seconds from epoch.
My preference for working with dates in macro variables is to store the actual numeric value in the macro variable, and if I need to view/print the formatted value then assign a format to it on the fly:
%let date = %sysfunc(mdy(3,15,2013));
%put %sysfunc(putn(&date,date9.));
That allows you to use it in comparisons like the below (which I find is the most common task):
data xx;
set something;
where datefield = &date;
run;

sas date - convert today() into yyyymmdd format

How do I convert a SAS date such as "30JUL2009"d into YYYYMMDD format (eg 20090730)?
So for instance:
data _null_;
format test ?????;
test=today();
put test=;
run;
Would give me "test=20090730" in the log...
data _null_;
format test yymmddn8.;
test=today();
put test=;
run;
YYMMDDxw. documentation
%let expectdate1=%sysfunc(putn(%eval(%sysfunc(today())-1),yymmddn8.));
You want to use the format yymmddn8. The 'n' means no separator.
Per http://support.sas.com/kb/24/610.html you can specify B for blank, C for colon, D for dash, N for no separator, P for period, or S for slash.
There is this one that should do the trick too
%let today=%sysfunc(today(),yymmddn8.);
%put &today.;
Everything on the link below
https://communities.sas.com/thread/60111
here's how I did it in macro, but surely there must be a format??!!!
%let today=%sysfunc(compress(%sysfunc(today(),yymmddd10.),'-'));
its weird - the INFORMAT yymmdd8. gives YYYYMMDD result, whereas the FORMAT yymmdd8. gives a YY-MM-DD result!!
You can see all date and time formats in Help tab when you enter 'date' to Index tab and then selecr 'date and time formats'