Turn SAS date into week day of year ending on last Friday - sas

I'm trying to manipulate my Dispensing_Date to give me the weeknum of the year ending on last Friday for each Date, can this be done? Here is what I have so far...
%let 1= 01012016;
%let 53 = 12302016;
**01 import whiteoak file;
proc import
datafile = "E:\Horizon\Adhoc\AH\whiteoak.xlsx"
out = whiteoak
dbms = XLSX
replace;
run;
** 02 remove dupes to ensure unique rx and fill;
proc sort nodup data=whiteoak;
by Rx_ Refill;
run;
** 03 Filter out holds;
data whiteoak;
set whiteoak;
where (Filled_Status="YES");
run;
** 04 create weekday variable;
data dates;
set whiteoak;
format Dispensing_Date MMDDYY8.;
run;

This is my best guess as to what you are asking.
24 data _null_;
25 x = today();
26 d = intnx('week.7',x,-1,'end');
27 put (_all_)(=weekdate.);
28 run;
x=Wednesday, January 4, 2017 d=Friday, December 30, 2016

Does this do what you want?
data weeks;
do date = '22DEC2016'd to '15JAN2017'd;
format date first_friday weekdate.;
sas_week=week(date);
first_friday= intnx('week.7',intnx('year',date,0,'b'),0,'e');
friday_week=1+int((7+date-first_friday)/7) ;
output;
end;
run;
If it does then apply it to your data:
data dates;
set whiteoak;
week = 1 + int((7+Dispensing_Date
- intnx('week.7',intnx('year',Dispensing_Date,0,'b'),0,'e'))/7);
run;

Related

How to find the previous 12Months date starting from last Month

I am trying to create a query to find number of occurrences in a list in a SAS dataset, for the past 12 Months starting from Last Month
I have created the macro below to be used in my WHERE clause:
%let cur_date = %sysfunc(today(), date9.);
%let pre_date2 = %sysfunc(putn(%sysfunc(intnx(month, %sysfunc(today()), -1, End)),%sysfunc(intnx(month, %sysfunc(today()), -12, End)) date9.)));
%put &pre_date4;
I would appreciate if you can help me with this.
Thanks
You need two macro variables: one for the end of the prior month and one for the first day 12 months prior to last month.
%let last_month = %sysfunc(intnx(month, %sysfunc(today()), -1, E) );
%let last_12_months = %sysfunc(intnx(month, &last_month., -12, B) );
Now you can run your query using between:
where date BETWEEN &last_month. AND &last_12_months.;
Example:
data have;
do i = -36 to 0;
date = intnx('month', today(), i, 'B');
output;
end;
format date date9.;
drop i;
run;
data want;
set have;
where date BETWEEN &last_month. AND &last_12_months.;
run;
Output:
date
01OCT2020
01NOV2020
01DEC2020
01JAN2021
01FEB2021
01MAR2021
01APR2021
01MAY2021
01JUN2021
01JUL2021
01AUG2021
01SEP2021

Calculating number of business days between 2 dates in SAS,

Member StartDate EndDate
1 27-Jul-17 27-Oct-17
2 27-Aug-19 11-Sep-19
3 28-Mar-17 31-Jul-17
4 17-Jun-19 13-Aug-19
5 21-Mar-17 16-May-17
6 17-Mar-17 05-Jul-17
7 20-Jan-16 11-Apr-16
8 27-Apr-15 09-Jun-15
9 13-Feb-19 19-Mar-19
10 27-May-15 30-Sep-15
11 16-Dec-16 30-Mar-17
12 17-Nov-16 02-Feb-17
data mydata;
set mdata;
weekdays=intck("weekdays",startdate,enddate);
run;
Holiday data is here:
holiday_date description
01/01/2003 New Years Day
17/02/2003 Family Day
18/04/2003 Good Friday
21/04/2003 Easter Monday
19/05/2003 Victoria Day
01/07/2003 Canada Day
04/08/2003 Civic Holiday
01/09/2003 Labour Day
13/10/2003 Thanksgiving Day
11/11/2003 Remembrance Day
25/12/2003 Christmas Day (*)
26/12/2003 Boxing Day (*)
01/01/2004 New Years Day
16/02/2004 Family Day
09/04/2004 Good Friday
12/04/2004 Easter Monday
24/05/2004 Victoria Day
01/07/2004 Canada Day
02/08/2004 Civic Holiday
I want to calculate number of week days excluding holidays. I have a table with the holidays dates. How do I apply it for each record to calculate business days?
This example is copied from SAS documentation.
Example 3: Using Custom Intervals with the INTCK Function
options intervalds=(BankingDays=BankDayDS);
data BankDayDS(keep=begin);
start = '15DEC1998'd;
stop = '15JAN2002'd;
nwkdays = intck('weekday',start,stop);
do i = 0 to nwkdays;
begin = intnx('weekday',start,i);
year = year(begin);
if begin ne holiday('NEWYEAR',year) and
begin ne holiday('MLK',year) and
begin ne holiday('USPRESIDENTS',year) and
begin ne holiday('MEMORIAL',year) and
begin ne holiday('USINDEPENDENCE',year) and
begin ne holiday('LABOR',year) and
begin ne holiday('COLUMBUS',year) and
begin ne holiday('VETERANS',year) and
begin ne holiday('THANKSGIVING',year) and
begin ne holiday('CHRISTMAS',year) then
output;
end;
format begin date9.;
run;
data CountDays;
start = '01JAN1999'd;
stop = '31DEC2001'd;
ActualDays = intck('DAYS',start,stop);
Weekdays = intck('WEEKDAYS',start,stop);
BankDays = intck('BankingDays',start,stop);
format start stop date9.;
run;
title 'Methods of Counting Days';
proc print data=CountDays;
run;
In response to the comment.
data mydata;
input Member (StartDate EndDate)(:date.);
format startdate enddate date11.;
cards;
1 27-Jul-17 27-Oct-17
2 27-Aug-19 11-Sep-19
3 28-Mar-17 31-Jul-17
4 17-Jun-19 13-Aug-19
5 21-Mar-17 16-May-17
6 17-Mar-17 05-Jul-17
7 20-Jan-16 11-Apr-16
8 27-Apr-15 09-Jun-15
9 13-Feb-19 19-Mar-19
10 27-May-15 30-Sep-15
11 16-Dec-16 30-Mar-17
12 17-Nov-16 02-Feb-17
;;;;
run;
proc print;
run;
proc summary data=mydata nway missing;
output out=range(drop=_:) min(startdate)=start max(enddate)=stop;
run;
proc print;
run;
options intervalds=(BankingDays=BankDayDS);
data BankDayDS(keep=begin);
set range;
nwkdays = intck('weekday',start,stop);
do i = 0 to nwkdays;
begin = intnx('weekday',start,i);
year = year(begin);
if begin ne holiday('NEWYEAR',year) and
begin ne holiday('MLK',year) and
begin ne holiday('USPRESIDENTS',year) and
begin ne holiday('MEMORIAL',year) and
begin ne holiday('USINDEPENDENCE',year) and
begin ne holiday('LABOR',year) and
begin ne holiday('COLUMBUS',year) and
begin ne holiday('VETERANS',year) and
begin ne holiday('THANKSGIVING',year) and
begin ne holiday('CHRISTMAS',year) then
output;
end;
format begin date9.;
run;
data mydata;
set mydata;
ActualDays = intck('DAYS',startdate,enddate);
weekdays = intck("weekdays",startdate,enddate);
BankDays = intck('BankingDays',startdate,enddate);
run;
title 'Methods of Counting Days';
proc print data=mydata;
run;

Date Format in Base SAS

I have to pass Date format in Proc SQL in the where Class.
Date Format is like this "SAT Mar 17 01:29:17 IST 2018" (String Column, length is 28)
Now when i have tried input(Date,datetime18.) and some other date functions, but all are giving me error. Below is my query
proc sql;
Select input(Date,datetime18.) from table;
quit;
How to convert this date into simple date like "17-03-2018", so that i can use the same in proc SQL query?
date is numeric and you should not compare it with string value, compare it with date literal by converting your value also to date. comparing greater and less than values with strings, in general do not serve any purpose and can lead to erroneous results. less than and greater than have meaning/make sense when you compare numeric variables
data have;
b = "SAT Mar 17 01:29:17 IST 2018";
output;
b= "SAT Mar 19 01:29:17 IST 2018";
output;
b= "SAT Jun 20 01:29:17 IST 2018";
output;
b= "SAT Mar 25 01:29:17 IST 2018";
output;
run;
proc sql;
select * from have
where input(cats(scan(b,3),scan(b,2), scan(b, -1)),date9.) > "19Mar2018"d;
The ANYDTDTM can be a go to informat in many cases, however, as you point out (in comments) it is not so for the datetime format presented in the question.
The string can be re-arranged into a SAS inputable date time representation using cats and scan
data have;
date_string = "SAT Mar 17 01:29:17 IST 2018";
run;
data want;
set have;
dt_wrong = input(date_string, anydtdtm.);
dt_right = input ( cats
( scan(date_string,3),
scan(date_string,2),
scan(date_string,6),':',
scan(date_string,4)
), datetime20.);
put date_string= /;
put dt_right= datetime20. " from input of cats of string parts";
put dt_wrong= datetime20. " from anydttm ";
run;
* sample macro that can be applied in data step or sql;
%macro dts_to_datetime(dts);
input ( cats
( scan( &dts , 3),
scan( &dts , 2),
scan( &dts , 6), ':',
scan( &dts , 4)
)
, datetime20.)
%mend;
data want2;
set have;
dt_righton = %dts_to_datetime(date_string);
format dt_righton datetime20.;
put dt_righton=;
run;
The macro can also be used in where statements such as
where '18-Mar-2018:0:0'DT <= %dts_to_datetime (date_string)
Or SQL
, %dts_to_datetime (date_string) as event_dtm format=datetime20.
i have used sub-string.I created a new column NEW_DATE in Dataset. As mentioned above date format is Sat Mar 17 01:01:01 IST 2018. Below is the data step to fetch date in the format of DD-MMM-YYYY
data new;
set old;
new_date = substr(date,9,2)||"-"||substr(date,5,3)||"-"||substr(date,25,4);
new_date_updated = input(new_date,date11.);
format new_date_updated date11.;
run;
then i use new column in proc sql
proc sql;
select * from new where new_date_updated>'17-Mar-2018'd;
quit;
and it worked for me.
Thanks
Checked above approach with all scenarios, working fine with all

SAS Fast forward a date until a limit using INTNX/INTCK

I'm looking to take a variable observation's date and essentially keep rolling it forward by its specified repricing parameter until a target date
the dataset being used is:
data have;
input repricing_frequency date_of_last_repricing end_date;
datalines;
3 15399 21367
10 12265 21367
15 13879 21367
;
format date_of_last_repricing end_date date9.;
informat date_of_last_repricing end_date date9.;
run;
so the idea is that i'd keep applying the repricing frequency of either 3 months, 10 months or 15 months to the date_of_last_repricing until it is as close as it can be to the date "31DEC2017". Thanks in advance.
EDIT including my recent workings:
data want;
set have;
repricing_N = intck('Month',date_of_last_repricing,'31DEC2017'd,'continuous');
dateoflastrepricing = intnx('Month',date_of_last_repricing,repricing_N,'E');
format dateoflastrepricing date9.;
informat dateoflastrepricing date9.;
run;
The INTNX function will compute an incremented date value, and allows the resultant interval alignment to be specified (in your case the 'end' of the month n-months hence)
data have;
format date_of_last_repricing end_date date9.;
informat date_of_last_repricing end_date date9.;
* use 12. to read the raw date values in the datalines;
input repricing_frequency date_of_last_repricing: 12. end_date: 12.;
datalines;
3 15399 21367
10 12265 21367
15 13879 21367
;
run;
data want;
set have;
status = 'Original';
output;
* increment and iterate;
date_of_last_repricing = intnx('month',
date_of_last_repricing, repricing_frequency, 'end'
);
do while (date_of_last_repricing <= end_date);
status = 'Computed';
output;
date_of_last_repricing = intnx('month',
date_of_last_repricing, repricing_frequency, 'end'
);
end;
run;
If you want to compute only the nearest end date, as when iterating by repricing frequency, you do not have to iterate. You can divide the months apart by the frequency to get the number of iterations that would have occurred.
data want2;
set have;
nearest_end_month = intnx('month', end_date, 0, 'end');
if nearest_end_month > end_date then nearest_end_month = intnx('month', nearest_end_month, -1, 'end');
months_apart = intck('month', date_of_last_repricing, nearest_end_month);
iterations_apart = floor(months_apart / repricing_frequency);
iteration_months = iterations_apart * repricing_frequency;
nearest_end_date = intnx('month', date_of_last_repricing, iteration_months, 'end');
format nearest: date9.;
run;
proc sql;
select id, max(date_of_last_repricing) as nearest_end_date format=date9. from want group by id;
select id, nearest_end_date from want2;
quit;

lag daily data by 1 month in sas

I have a data set with daily data in SAS. I would like to convert this to monthly form by taking differences from the previous month's value by id. For example:
thedate, id, val
2012-01-01, 1, 10
2012-01-01, 2, 14
2012-01-02, 1, 11
2012-01-02, 2, 12
...
2012-02-01, 1, 20
2012-02-01, 2, 15
I would like to output:
thedate, id, val
2012-02-01, 1, 10
2012-02-01, 2, 1
Here is one way. If you license SAS-ETS, there might be a better way to do it with PROC EXPAND.
*Setting up the dataset initially;
data have;
informat thedate YYMMDD10.;
input thedate id val;
datalines;
2012-01-01 1 10
2012-01-01 2 14
2012-01-02 1 11
2012-01-02 2 12
2012-02-01 1 20
2012-02-01 2 15
;;;;
run;
*Sorting by ID and DATE so it is in the right order;
proc sort data=have;
by id thedate;
run;
data want;
set have;
retain lastval; *This is retained from record to record, so the value carries down;
by id thedate;
if (first.id) or (last.id) or (day(thedate)=1); *The only records of interest - the first record, the last record, and any record that is the first of a month.;
* To do END: if (first.id) or (last.id) or (thedate=intnx('MONTH',thedate,0,'E'));
if first.id then call missing(lastval); *Each time ID changes, reset lastval to missing;
if missing(lastval) then output; *This will be true for the first record of each ID only - put that record out without changes;
else do;
val = val-lastval; *set val to the new value (current value minus retained value);
output; *put the record out;
end;
lastval=sum(val,lastval); *this value is for the next record;
run;
You could achieve this using a PROC SQL, and the intnx function to bring last months date forward a month...
proc sql ;
create table lag as
select b.thedate, b.id, (b.val - a.val) as val
from mydata b
left join
mydata a on b.date = intnx('month',a.date,1,'s')
and b.id = a.id
order by b.date, b.id ;
quit ;
This may need tweaking to handle scenarios where the previous month doesn't exist or months which have a different number of days to the previous month.