Automating weekday function for multiple dates with different permutations - date

I need to apply a certain treatment to sas dates depending on what day of the month the 1st of the month falls on. I need this to go forward for a number of months.
I’ve created the following as I also need macro variables for the start and end dates of the month.
%let first_dt = '01Jun2020'd;
data _null_
do j =0 to 12;
call Symputx(cats("&monstrt",j),put(intnx("month","first_dt",j,"b"),date9.),'g');
call Symputx(cats("&monend",j),put(intnx("month","first_dt",j,"e"),date9.),'g');
end;
run;
I now need to based on the 12 start of the month dates I have, increment the number of days. E.g. if start of month is a Monday I need to increment by 5 days, I’d start of the month is a Tuesday I need to increment by 6 days and so on.
I have attempted the following but it doesn’t appear to be working.
%macro weekdays(weekday);
data test;
if weekday("strt&i."d) = &weekday. then
new_stdt = put(intnx('day',"strt&i."d,+5),date9.)
;
%mend;
%weekdays(1,2,3,4,5,6,7);
Essentially I’m hoping to get all these dates to become populated based off the first_st variable, if this then subsequently changed, I could amend the original value and new values would be populated off of the back of that.

Here is a method that allows you to specify the values the add as a list of 7 numbers. For example this list matches the values in your comment.
%let add=11 5 6 7 8 9 10;
Notice how Monday and Tuesday are mapped to the 5 and 6 you mentioned in your question.
So if you have these values:
%let first_dt = '01Jun2020'd;
%let offset= 8 ;
You can generate a new date value like:
%let date = %sysfunc(intnx(month,&first_dt,&offset,b));
%let date = %eval(&date + %scan(&add,%sysfunc(weekday(&date))));
If you need to have the value of DATE look like something a human would understand you could add.
%let date = "%sysfunc(putn(&date,date9.))"d ;
So when the month offset is 8 the first of the month is on a Monday so the resulting date is 5 days after the first of the month.
1168 %put &=date;
DATE="06FEB2021"d

Related

SAS set the 'middle' parameter of intnx to always set to the 15th

I have the following SAS codes:
DATA _NULL_;
today = today();
if day(today) ge 1 and day(today) le 15 then do;
date2=put(intnx('month',today,-1,'m'), date11.);
date1=put(intnx('month',today,-1,'E'), date11.);
end;
if day(today) > 15 then do;
date2=put(intnx('month',today,0,'B'), date11.);
date1=put(intnx('month',today,0,'m'), date11.);
end;
call symput('dt',date1);
call symput('dt2',date2);
RUN;
The code above says if the date part of today's date is less than or equal to 15, set date2 to the middle of last month and date1 be set to the last/end of last month. otherwise, set date2 to the beginning of the current month and date1 to the middle of the current month.
I like how SAS has the 'm' or 'middle' to get the middle date of the month. It works great with months that have 30 days and the middle will fall on the 15th. But on months with 31 days, it will always fall on the 16th, special case with February. What I would like is to always make the middle be on the 15th.
I tried adding '-1' to every line to check if it will give me what I need, but it returns a blank date when I call the variable. It returns a dot for a not working date call with -1.
one of them is %put &rpt_dt. &rpt_dt2.; . 01-JAN-2023
Since January has 31 days and if I put the -1 as such:
date1=put(intnx('month',today,0,'m')-1, date11.);
I will get the desired Jan15th, but it will not be dynamic. If the same code with -1 will be run next month, the code will always subtract 1 and it will fall a day before the middle, same with months that have 30 days.
If you literally want it to be the 15th exactly, then why not do this?
date1=put(intnx('month',today,0,'b')+14, date11.);
Seems straightforward to me...

How can I count the number of weekdays between two dates, considering Saturday a weekday?

I have a dataset with the first and the last day of an event. I need to calculate the number of weekdays between the two dates. However, I need to consider Saturday as a weekday. How can I do that?
This is the example which is exactly like my dataset, but smaller. I've been using it to test the code before running everything:
data testing_weekdays;
input id $ date_1 date9. id2 $ dat2_2 date9.;
format date_1 date9. dat2_2 date9.;
datalines;
AA 01jan2019 AA 25jan2019
BB 02feb2019 BB 12feb2019
CC 10aug1990 CC 05jan1995
DD 11dec1999 DD 21dec1999
;
run;
When I use the intck function with the parameter 'weekday', I get the difference considering both Saturday and Sunday as weekend. But I would like to consider only Sunday.
I saw this solution on SAS community: https://communities.sas.com/t5/SAS-Programming/Sunday-to-Saturday-work-day/td-p/338412, but I can't make it work.
You can use sas function intck to find required interval. in your example, following will be the statement:
data want;
set testing_weekdays;
wkdays=intck('WEEKDAY1W',date_1,dat2_2);
run;
You can use different formats for Weekday interval. The days are numbered as Sunday(1) .. Saturday(7). So if you want to keep Sunday as a weekend, then WEEKDAY1W is used as interval.. Say if you want Monday(2), Wed(4) as weekends, then use- WEEKDAY24W
data new;
set old
interval=intck('weekday1w',begin,end);
run;

Marking full weeks inside a month including remaining days from other months

I have a dataset with daily data. I need to create a variable which brings the number of the week in each month (1 to (4 or 5)).
I have reached that with the following formula:
WK_NUM = intck('week',intnx('month',DATE,0),DATE)+1;
It works fine, but frequently the first and the last weeks of the month aren't full weeks, so the line only brings partial weeks. I need to improve it to bring remaining days from previous or next month in order to fill each week with 7 days.
Any ideas?
Hope this creates the expected result:
/* initial data set with dates */
data a;
format date date9.;
do date="15apr2017"d to "15jun2017"d;
output;
end;
run;
/* adding week number */
data a;
set a;
wk_num = week(date,'u');
run;
/* selecting May and modifying wk_num */
proc sql noprint;
CREATE TABLE b AS
SELECT date
,wk_num - ((SELECT min(wk_num) FROM a WHERE date="01may2017"d)-1)
FROM a
WHERE wk_num between (SELECT min(wk_num) FROM a WHERE date="01may2017"d) AND (SELECT max(wk_num) FROM a WHERE date="31may2017"d)
;
quit;
Option for week function:
u (default): specifies the number-of-the-week within the year. Sunday is considered the first day of the week. The number-of-the-week value is represented as a decimal number in the range 0-53. Week 53 has no special meaning. The value of week('31dec2006'd, 'u') is 53.
v: specifies the number-of-the-week whose value is represented as a decimal number in the range 1-53. Monday is considered the first day of the week and week 1 of the year is the week that includes both January 4th and the first Thursday of the year. If the first Monday of January is the 2nd, 3rd, or 4th, the preceding days are part of the last week of the preceding year.
w: specifies the number-of-the-week within the year. Monday is considered the first day of the week. The number-of-the-week value is represented as a decimal number in the range 0-53. Week 53 has no special meaning. The value of week('31dec2006'd, 'w') is 53.

SAS: create time ID variable with program (instead of using the point-and-click system)

SAS offers a point-and-click system to create a time ID variable from a certain starting date using a particular frequency (e.g. weeks, quarters, years).
Since I need to do this proces repeatedly, I like to use a code as it makes things much easier. My data covers 1985-2005 and is divided into quarters (which gives 21 years * 4 quarters = 84 observations).
The date variable column should look like this (or give any other sas date which can be formated):
Date:
1985/1
1985/2
1985/3
1985/4
1986/1
etc.
Does anyone knows how to write a code for this?
Thank you very much in advance!
Rens (a PhD student in sociology working on the music charts)
You can use a data step and the YYQ function.
data quarters;
do year = 1985 to 2005;
do quarter = 1 to 4;
date = yyq(year,quarter);
output;
end;
end;
format date yyq.;
run;
proc print;
run;
Use intnx function.
data have;
do i=0 by 1;
date=intnx('quarter',yyq(1985,1),i);
if date>yyq(2005,4) then return;
output;
end;
format date yyqs6.;
run;

Selecting first of month sas dates

I have a sasdataset with a number of observations where one of the variables is called DATO.
This variable contains the Date that the observation was added to the dataset.
Previously i have used the following:
WHERE (DATE() - DATO) < 250;
To select which Observations to print, but this comes with issues. Previously i added observations monthly, but now i do it on daily basis.
I need to find a way to print out only observations which are from the first day of the last 8 months.
I can probably figure out the issue with the 8 months, but not how to select only the first day of the month. Any help would be greatly appreciated.
data _null_;
infile cards;
input DATO:date9.;
if day(DATO)=1 /* first of the month */
and DATO>intnx('MONTH',date(),-8) /* returns date shifted back 8 months */
then put DATO= date9.;
cards;
01JAN2013
02JAN2013
01FEB2013
01MAR2013
03MAR2013
;run;
results:
DATO=01JAN2013
DATO=01FEB2013
DATO=01MAR2013