Code that can Identify the 6th day of the Month excluding weekend - sas

Please can someone help me?
I need a code that can identify every 6th of the Month on a rolling period excluding weekends. i would need the code to send an email every time it is past the 6th of each month.
Please don't worry about the email part, I only need a code that can identify the 6th of every month in SAS.
for instance:
"If the date of the Month is greater than 6th" then %do
Please help.
Thank you.

You can check your date directly by seeing if the day is greater than or equal the 6th. If it's a weekend, then do nothing.
data _null_;
if(day(today()) GE 6 AND 2 LE weekday(today()) LE 6) put 'It's the after the 6th and not a weekend';
else put 'It's not after the 6th or it's a weekend.';
run;
If you need to only run your email once a month, create a small database that stores each day an email was sent. If an email was sent that month then do not send an email.
%macro send_email;
%let today = %sysfunc(today() );
proc sql noprint;
select intnx('month', max(email_date), 0, 'B')
into :check_date
from lib.email_history
;
quit;
%if( %sysfunc(intnx(month, &today., 0, B) ) NE &check_date.
AND %sysfunc(day(&today.) ) GE 6
AND 2 LE %sysfunc(weekday(&today.) ) LE 6
)
%then %do;
/************************/
/* Email code goes here */
/************************/
/* Save a history that an email was sent */
data email_history;
email_date = today();
run;
proc append base=lib.email_history
data=email_history
;
run;
%end;
%mend;
%send_email;

The key function here is intnx, which lets you skip to the next [whatever day].
Here's an example that hopefully explains the concept.
data dates;
do date = '01JAN2022'd to '31DEC2022'd;
weekday = date;
is_sixth = (date = intnx('WEEKDAY',intnx('MONTH',date,0)+5-1,0,'e')+1);
output;
end;
format weekday DOWNAME.;
format date date9.;
run;
Here we first shift to the start of the month and then add 5 (sort of). That gets us 'sixth of the current month'. Then because SAS's weekday intervals are aligned where Fri,Sat,Sun are one "period", we have to subtract one, move to the end of the period, and add one. That gets us to the 6th or later. If we didn't do the subtract/add dance, we'd get to the 6th or earlier.

Related

write conditional in SAS with DATA _NULL_

I am writing a conditional in SAS starts with DATA NULL
%LET today = today();
DATA _NULL_;
if day(today) ge 1 and day(today) le 15 then do;
date1=put(intnx('month',today,-1,'E'), date11.);
date2=put(intnx('month',today,-1,'L'), date11.);
end;
if day(today) > 15 then do;
date1=put(intnx('month',today,0,'B'), date11.);
date2=put(intnx('month',today,0,'L'), date11.);
end;
call symput('report_date',date1);
call symput('report_date2',date2);
RUN;
but with above, I am not getting any values for my report_dates.
the condition is:
date 1 = If the current date is greater than or equal to 1 and less than 16, set the date1 to the 16th of the previous month, otherwise set it to the 1st of the current month
date2 = If the current date is 16 and above, set the date2 to the 15th of the current month, otherwise set date2 to the last day of the previous month
The IF/THEN logic does not account for the missing value you passing to the DAY() function calls.
The variable TODAY is never created in the data step. So just remove the %LET statement and add an actual assignment statement instead.
DATA _NULL_;
today=today();
if day(today) ge 1 and day(today) le 15 then do;
...
Just because you used the same name for the macro variable in the %LET statement as you used for the variable in the data step does not imply that the two have anything at all to do with each other.
If you wanted to use the macro variable to generate the code for the data step you would need to replace the TODAY with &TODAY.
if day(&today) ge 1 and day(&today) le 15 then do;
So for the value you set to the macro variable TODAY it would mean that the SAS code you are trying to run is:
if day(today()) ge 1 and day(today()) le 15 then do;
Note that is actually not a good way to handle this problem because it is calling the TODAY() function multiple times. That could cause strange results if the data step started right before midnight. So the IF condition might be run on the 31st but when you get to the ELSE condition the clock has ticked over to the first of the next month.

SAS MACRO to Cycle Month End Dates

I have a set of code that I am manually adjusting month end dates. The query which runs and uses the dates has left joins to pull data for each declared date. I've been looking at macros because this is labor intensive to change all the dates by one month all the way until the most recent completed month. There's got to be a way to loop through and change each declared month end date by one month and do a loop to run the query until it gets to the most recent completed month end date.
So after the below runs entirely, it would up each declared date by one month and show the month end date. Each data set that runs would be be BEDT. So the first run would be jan2018, so on and so forth.
Can someone assist or point me into the right direction? I've read through so much documentation and have gotten no where. Thanks in advance.
%Let BEdt='01JAN2018'd
%let dt1='28FEB2018'
%let dt2='31MAR2018'
%let dt3='30APR2018'
%let dt4='31MAY2018'
%let dt5='30JUN2018'
%let dt6='31JUL2018'
%let dt7='31AUG2018'
%let dt8='30SEP2018'
%let dt9='31OCT2018'
%let dt10='30NOV2018'
%let dt12='31DEC2018'
%let dt12='31JAN2019'
Let's use something that has a start date and a number of months to pull. We'll use intnx() to increment each month one by one until we reach the last month. intnx() will also help us calculate the start and end dates.
%macro get_data(start=, months=12);
/* Convert start/end values into SAS dates */
%let start_dt = %sysfunc(inputn(&start., date9.));
%do i = 0 %to &months.;
/* Calculate the start and end months for the month of data in the loop */
%let month_s = %sysfunc(intnx(month, &start_dt., &i., B) );
%let month_e = %sysfunc(intnx(month, &start_dt., &i., E) );
%put Pulling data for %cmpres(%sysfunc(putn(&month_s., date9.)) - %sysfunc(putn(&month_e., date9.)));
/***********************************/
/***** SQL/DATA Step goes here *****/
/***********************************/
%end;
%mend;
%get_data(start=01JAN2018);
In the area where you'd add SQL or DATA step code, it could look like this:
data want_&month_s.;
set have;
where date BETWEEN &month_s. AND &month_e.;
run;
Output:
Pulling data for 01JAN2018 - 31JAN2018
Pulling data for 01FEB2018 - 28FEB2018
Pulling data for 01MAR2018 - 31MAR2018
Pulling data for 01APR2018 - 30APR2018
Pulling data for 01MAY2018 - 31MAY2018
Pulling data for 01JUN2018 - 30JUN2018
Pulling data for 01JUL2018 - 31JUL2018
Pulling data for 01AUG2018 - 31AUG2018
Pulling data for 01SEP2018 - 30SEP2018
Pulling data for 01OCT2018 - 31OCT2018
Pulling data for 01NOV2018 - 30NOV2018
Pulling data for 01DEC2018 - 31DEC2018
Pulling data for 01JAN2019 - 31JAN2019
Depending on the complexity of the statement you want to run for each month, you can also use call execute instead of a macro loop.
data _null_;
start_date = "&start."d;
do i = 0 to &months.;
month_start = intnx("month", start_date, i, "B");
month_end = intnx("month", start_date, i, "E");
call execute(
'data want_'||strip(i)||';'||
'set have;'||
'where date between '||month_start||' and '||month_end||';'||
'run;'
);
end;
run;
You only have to be careful about when macro variables get resolved. I nice article on this can be found here
* Do whatever you would do for one month in a macro;
%macro do_a_month(begin_d, end_d);
data want_&begin_d;
set have;
where data between "&begin_d"d and "&end_d"d;
run;
%mend;
* call the macro as much as needed;
data _null_;
begin_d = '01JAN2018'd;
do while (begin_d le '31JAN2019'd);
end_d = intnx("month", begin_d, 0, "E");
call execute ( '&do_a_month('
|| put(begin_d, date9.) ||','
|| put(end_d, date9.) ||')';
* go to next month;
begin_d = end_d + 1;
end;
run;

How to create a calendar table for 30 days prior to today in SAS?

I am a newbie in SAS.
I am trying to create a simple table in SAS that has three columns, date (for thirty days prir to today), how_many_days_before (representing the number of days between date and today ), and which_day (showing the name of that date as monday, tuesday, etc).
Edit: Here is the code I tried. I want to automate the macros with loops. Also the output table has blank values for which_day and how_many_days_before variables for now.
%macro which_day;
if date=160822 then which_day='monday';
else if date=160821 then which_day='sunday';
%mend;
%macro how_many_days_before;
if date=160822 then how_many_days_before=0;
else if date=160821 then how_many_days_before=1;
%mend;
data calendar;
attrib date format=yymmdd6.;
do date=today()-30 to today();
output;
end;
%which_day;
%how_many_days_before;
run;
I have tried intnx function without a luck.
Thanks
I have not tested this code, but it should give you a starter. Hope it helps
data calendar;
attrib date today format=date9.;
do date=today()-30 to today();
output;
end;
run;
I was able to write it in data step without using macros.
data calendar;
attrib date format=yymmdd6.;
do date=today()-30 to today();
how_many_days=today()-date;
which_day=weekday(date);
output;
end;
run;

How can I use different sets of date values depending on the date

I am looking to automate a daily report for my company but I have run in to a bit of trouble. The report gets updated only on the 2nd working day of each month. I found some code on the SAS website which works out what the 2nd working day of any month is.
data scdwrk;
/* advance date to the first day of the month using the INTNX function */
second=intnx('month',today(),0);
/* determine the day of the week using the WEEKDAY function */
day=weekday(second);
/* if day=Monday then advance by 1 */
if day=2 then second+1;
/* if day=Sunday then advance by 2 */
else if day=1 then second+2;
format second date9.;
run ;
I have also set a flag that compares todays date to the date from this generated by this piece of code.
I now need to find a way that if the code is run on the first working day of the month then it runs a particular set of macro date variables
%let start_date="&prevmnth;
%let end_date= &endprevmnth;
%let month= &prevyearmnth;
and then when its run on the 2nd working day of the month it uses the other set of macro date variables (calender month)
%let start_date="&currmnth;
%let end_date= &endcurrmnth;
%let month= &curryearmnth;
Any help on this would be greatly appreciated.
I have some recent code that does just this. Here is how I tackled it.
First, create a table of holidays. This can be maintained yearly.
Second, create a table with the first 5 days of the month that are not weekend days.
Third, delete holidays.
Finally, get the second value in the data set.
data holidays;
format holiday_date date9.;
informat holiday_date date9.;
input holiday_date;
datalines;
01JAN2015
19JAn2015
16FEB2015
03APR2015
25MAY2015
03JUL2015
07SEP2015
26NOV2015
25DEC2015
;
data _dates;
firstday = intnx('month',today(),0);
format firstday date date9.;
do date=firstday to firstday+5;
if 1 < weekday(date) < 7 then
output;
end;
run;
proc sql noprint;
delete from _dates
where date in (select holiday_date from holidays);
quit;
data _null_;
set _dates(firstobs=2);
call symput("secondWorkDay",put(date,date9.));
stop;
run;
%put &secondWorkDay;

Automating the starting date with a macro variable in SAS

Background:
I have a code that pulls transactional data starting at the beginning of the current calendar quarter, but from an year ago.
For example, if I run the code today (August 16, 2013) it will have to pull all the data from July 1, 2012 onwards.
Problem:
I want to automate the starting date for the data pull with a macro variable.
So far, I'm stuck here:
%let ThisYear = %Sysfunc(Date(), YEAR.);
%let LastYear= %eval(&ThisYear-1); /* I get the starting year */
%let QTR_start_month= %eval(3*%Sysfunc(Date(), qtr.)-2); /* this gives me the current quarter starting month. If I run it in August, it outputs 7 for July */
%let start_date=%str(01/%Sysfunc(month(&QTR_start_month))/&lcy);
The final macro variable outputs the date which I want, but in a format which is not recognized by SAS.
I will greatly appreciate any help.
Many thanks in advance!
You can either input that date to a date format, or construct it like a SAS date literal ('01JUL2013'), DDMONYY(YY), or construct it as a date value directly.
INTNX is probably your best option here to construct it; you don't need all that work.
%let start_date = %sysfunc(intnx(Quarter,%sysfunc(date()),-4),DATE9.);
%put &start_date;
You can leave DATE9. to use it as a date literal, or remove the ,DATE9. to get the numeric value that can be used directly. You would use this as "&start_Date."d to use the date literal.
This should do the job.
data test;
format todays_date starting_qtr date9.;
todays_date=today();
/*this takes today's date and rolls back 4 qtrs and sets that date to the first day of that quarter*/
starting_qtr = intnx('qtr',todays_date,-4,'b');
/*so, running this code today, 16AUG2013 would yield starting_qtr=01JUL2012 */
call symputx('start_date', put(starting_qtr, date9.));
run;
%put &start_date.;