How to subtract two dates in sas studio? - sas

I need help with a question.
I need to subtract two dates in sas studio. I have the next:
%let date_star = %SYSFUNC( DATETIME());
%let date_end = %SYSFUNC( DATETIME());
But I dont´n now how to subtract these variables.
Thanks for your help.

Use the INTCK() function to return the number of interval boundaries of a given kind that lie between two dates, times, or datetime values. The possible values of interval are listed in Date and Time Intervals.
%MACRO want;
%let date_start = %SYSFUNC(DATETIME());
data _null_;
rc=SLEEP(10,1); /* Sleep for 10 seconds */
run;
%let date_end = %SYSFUNC(DATETIME());
%put %sysfunc(intck(second, &date_start., &date_end.));
%MEND;
%want;
Result is 10 seconds, as expected.

So you haven't really created any variables there, just macro variables. Normally you would want to use SAS code to work with data, not macro code, but you can do it in a pinch.
You also do not have two DATE values. SAS stores dates as the number of days. Instead you have two DATETIME values. The DATETIME() function returns the number of seconds since 1960. So the difference between two datetime values will be a number in seconds.
The datetime value returned by DATETIME() will include fractions of a second. To perform floating point arithmetic in macro code you need to use the %SYSEVALF() function. The %EVAL() function that is used by default to evaluate conditions, like in a %IF statement, only handles integer arithmetic.
%let elapsed_time=%sysevalf(&date_end - &date_star);
If you would like to see the value in hours, minutes and seconds then you could apply a format to it.
%put Elasped time was %sysfunc(putn(&elapsed_time,time15.3));

Related

SAS macro to get the last date of the current month

I would like to use a macro in SAS to calculate the last day of the current month when executed.
As i'm quite new to the SAS macro's i've tried to create on based on the information i've found on the internet.
%let last_day = %sysfunc(putn(%sysfunc(intnx(month,%sysfunc(today()),e), date9.));
However it does not seem to work when i execute it.
You left out the number of intervals in the INTNX() function call.
To create a macro variable with the string that looks like the last day of the current month in the style produced by the DATE9. format just use:
%let last_day = %sysfunc(intnx(month,%sysfunc(today()),0,e), date9.);
You could then use that macro variable to generate strings. Such as in a TITLE statement.
TITLE "End of the month is &last_day";
If you want to use it as an actual date you will need to convert it to a date literal by adding quotes and the letter d.
...
where date <= "&last_day"d ;
And if so it is probably simpler to not use the DATE9. format at all and just store the raw number of days since 1960 in the macro variable.
%let last_day = %sysfunc(intnx(month,%sysfunc(today()),0,e));
...
where date <= &last_day ;

Convert Timestamp to Numeric value in SAS

How to convert the default timestamp "0001-01-01-00.00.00.000000" in SAS, i have tried below code but it has returned null value. Can someone help on this please
data _NULL_;
x = "0001-01-01-00.00.00.000000";
rlstime = input(x,anydtdtm26.);
call symput('rlstime',rlstime);
run;
%put rlst: &rlstime;
As far as I remember, SAS cannot do that. Any date/timestamp before 1.1.1600 doesn't exist for SAS. Do you need it or can you just replace it with a null value? If you really need it you could transform it into another valid timestamp, split it into different columns (year, month, etc.) or just use it as a string. In your example you just write the timestamp into the log, meaning it's not necessary to transform it.
The earliest date that SAS will handle is 1st January, 1582. Additionally, a colon character should be used to delimit the time from the date, as well as the hours, minutes and seconds. Therefore, your code may be adjusted to the following:
data _NULL_;
x = "1582-01-01:00:00:00.000000";
rlstime = input(x,anydtdtm26.);
call symput('rlstime',rlstime);
run;
%put rlst: &rlstime;

SAS HANA Date from data step in PRO

A little new to SAS here. I am using the following data step to get the first and last day of the month.
Data _NULL_;
begindt=IntNX("Month", Date(), 0) ;
enddt=IntNX("Month", Date(),0,'E');
PUT begindt=E8601DA. enddt=E8601DA.;
Run;
The data step gets the results of begindt=2021-09-01 and enddt=2021-09-30.
However, I am having trouble converting the value to a date format to use in a where claus in a PROC SQL statement later in the program. The commented out code works, but I can't get the date from data step in the correct format for the PROC SQL statement to work.
/* AND "DETAILAR"."CLEAR_DOC_POSTING_DATE" = '2021-09-01' */
AND "DETAILAR"."CLEAR_DOC_POSTING_DATE" = begindt
SAS has date and time literals that make dealing with dates and times easy. SAS dates are the number of days since Jan 1 1960, and SAS datetimes are the number of seconds since Jan 1 1960. SAS automatically converts date literals to these times for you. Some examples of date and datetime literals:
'04SEP2021'd
'04SEP2021:00:00'dt
You don't have to use these all the time*, but they make debugging way easier. In your case, you simply need to feed a date literal into proc sql. If you're connecting to SAP HANA through SAS, the SAS/ACCESS engine to SAP will handle the conversion for you.
data _null_
begindt = intnx('month', today(), 0, 'B');
enddt = intnx('month', today(), 0, 'E');
call symputx('begindt', put(begindt, date9.) );
call symputx('enddt', put(enddt, date9.) );
run;
Or, equivalently:
%let begindt = %sysfunc(intnx(month, %sysfunc(today()), 0, B), date9.);
%let enddt = %sysfunc(intnx(month, %sysfunc(today()), 0, E), date9.);
Now you have two macro variables that you can not only easily read, but SAS will convert them for you. You can view them below:
%put &begindt;
%put &enddt;
Simply add them as date literals to your where clause in proc sql and let SAS do the rest.
proc sql;
create table want as
select *
from have
where CLEAR_DOC_POSTING_DATE BETWEEN "&begindt"d AND "&enddate"d
;
quit;
There are other literals too, like time literals, hex literals and name literals for variables with spaces in them.
'10:00't - Time Literal
'32'x - Hex literal
'this is a var'n - Name literal
*proc timeseries, proc timedata, and proc tsmodel require date/datetime literals for the start and end options. But those are the only ones I know of.
If you want to generate code like '2021-09-01' then why not create a macro variable with that string in it?
In your data _null_ step use:
call symputx('begindt',quote(put(intnx('month',date(),0),yymmdd10.),"'"));
Working from the inside out that statement will:
calculate today's date
convert to the start of the month
convert to a 10 character string representing that date
add single quotes around the string
store the value into a macro variable named begindt
Now you reference the macro variable to generate the code you want
and "DETAILAR"."CLEAR_DOC_POSTING_DATE" = &begindt.
Which will generate the code:
and "DETAILAR"."CLEAR_DOC_POSTING_DATE" = '2021-09-01'

How to set report dates automatically for %str arguments

I'm compiling order data using a program that has already been built, but am trying to update a section of the code to take today's date minus 61 days and plus 56 days for the respective start and end dates, rather than a manually typed in date as shown below. The current, functional code as well as one of my attempts is below.
The current format that is working and executing is:
/* Set report dates (dd-mm-yyyy) */
%let fore_start = %str(08-SEP-2019);
%let fore_end = %str(03-JAN-2020);
I'm attempting to build something like:
/* Set report dates (dd-mm-yyyy) */
%let fore_start = %str(TODAY()-61);
%let fore_end = %str(TODAY()+56);
I'm looking for help devising a syntactically sound line to solve this problem. Any help would be appreciated!
Try this:
%let fore_start = %sysfunc(putn(%eval(%sysfunc( today() ) - 61), ddmmyyd10.) );
%let fore_end = %sysfunc(putn(%eval(%sysfunc( today() ) + 56), ddmmyyd10.) );
It looks like there's a lot there, but it really isn't. Removing all of the syntax of macro language and converting it into data step functions, here's all you are doing:
fore_start = put(today() - 61, ddmmyyd10.);
fore_end = put(today() + 56, ddmmyyd10.);
There are a few things at play:
In macro language, SAS functions such as putn and today() need to both be enclosed with %sysfunc(). %sysfunc() is your connection to SAS system functions and the macro facility.
%eval will subtract two integers from each other.
putn, another SAS function, will convert the resulting SAS date into your desired format of ddmmyyd10.. putn is required for macro language instead of put.
The date representations you show as being kept in macro variables fore_start and fore_end are actually dd-mmm-yyyy, or format DATE11.
The %sysfunc marco function will invoke a DATA step function and optionally format the result. The INTNX function will perform date arithmetic.
%let fore_start = %sysfunc(intnx(DAY, %sysfunc(today()), -61), DATE11);
%let fore_end = %sysfunc(intnx(DAY, %sysfunc(today()), +56), DATE11);

INTNX Function is One Day Off

I am using the INTNX function to calculate month intervals. I'm finding that the results are frequently one day off from what I would expect... For example, look at this code:
data test;
olddate='20140531';
oldsasdate=input(olddate,yymmdd8.);
newsasdate=intnx('month',oldsasdate,-17);
newdate=put(newsasdate,yymmdd8.);
run;
In this code, I try to find the date 17 months before 05/31/2014. I would expect the function to return 11/30/2012, but it instead returns 12/1/2012. Any idea what's going on here? Is there a way to fix this?
The default for intnx is to align with the start of the month. It basically tracks interval boundaries, so each time it goes from MM/01/YY to MM/30/YY it ticks one interval crossed.
So,
data _null_;
x = intnx('month','31MAY2014'd, -1);
put x= date9.;
run;
Returns '01APR14'd, not '30APR14'd.
You can change it to 'same' alignment with the optional 4th parameter (SAS 9.2+ I believe).
data _null_;
x = intnx('month','31MAY2014'd, -1,'s');
put x= date9.;
run;