how to get flag and dateformates in sas - sas

Hi I have one doubt in sas
in dataset date format have 08-04-1988
base on this values I want create date styles and along flag values
For datetime flag creation if dateandtime have then consider flag 1 else 0
for date if date have then consider flag 1 else 0
for time if time have then consider flag 1 else 0
DATA DAT;
X= "08APR1988"D;
FORMAT X DDMMYYD10.;
RUN;
Based on above value I want output like below
Datetime | Date | Time | DatetimeFlag | DateFlag |TimeFlag
08APR1988 00:00:00 |08-04-1988 |00:00:00 | 0 |1 |0
I tried like below
DATA DUMM;
SET DAT;
DT=PUT( X, DDMMYY10.);
DATEF=PUT( X, date9.);
DTs=PUT( X, DATETIME32.);
TimeF=PUT( X, TIME.);
RUN;
here if donot have time then its takeing default datewith time similar time also
i want display if time is not available then consider 00:00:00 similar if date not available the date aslo : 1960-01-01
but above scirpt is not given expeted result ,
can you please tell me how to wirte sas coding to achive this task.

SAS has two value types, numeric and character.
Date and DateTime values are numeric with handling.
Date values are the number of days since 01JAN1960.
DateTime values are the number of seconds since 01JAN1960.
Non-integer date values do not get special interpretation (in other date systems, such as Excel, the decimal part of a numeric is the fraction of the day as well)
Non-integer DateTime values are fractional seconds.
You can convert the date to datetime by multiplying by the number of seconds in a day (86,400)
Suppose you had a non-integer date value, such as
data _null_;
D = '01JAN2019'D + 0.5;
format D yymmdd10.;
put D= / D=best12.;
DT = D * 86400;
format DT datetime21.2;
put DT= / DT=best12.;
run;
---------- LOG ----------
D=2019-01-01
D=21550.5
DT=01JAN2019:12:00:00.00
DT=1861963200
You can separate out the date and time parts of a datetime value using the functions DATEPART and TIMEPART
data have;
dt = '01FEB2019:12:34:56.78'DT; output;
dt = '15FEB2019:00:00:00'DT; output;
format dt datetime21.2;
run;
data want;
set have;
d = datepart (dt);
t = timepart (dt);
format d yymmdd10.;
format t time12.2;
dt_is_just_date = (t eq 0);
dt_has_time_part = (t ne 0);
run;
proc print data=want;
run;
-------
dt_is_ dt_has_
just_ time_
Obs dt d t date part
1 01FEB2019:12:34:56.78 2019-02-01 12:34:56.78 0 1
2 15FEB2019:00:00:00.00 2019-02-15 0:00:00.00 1 0

Related

Do loop not pulling in all data- creating dates

We have a code that we use to create quarterly reports of projects. There is a piece of code, a do loop, that takes the startdate and enddate of each project in our dataset and creates an observation for each month and year that the project took place in. For example if we have a project called "Employment Help" with a startdate value of 01JAN2022 and an enddate value of 01APR2022, the do loop will create 4 observations for this project with the month and year values of 1 2022, 2 2022, 3 2022, and 4 2022. We use this to count how many projects happened during our quarters. We are running into an issue where the do loop is dropping projects and not giving them a month or year value and we are losing projects in our count because of this. The dates are all in the same format.
Here is an example of some data that is pulled in, EXAMPLE 2 is properly pulled into the do loop, EXAMPLE 1 does not get pulled through.
Here is the code:
**data test2;
set users3;
do i = 0 to (year(enddate)-year(startdate));
year = year(startdate)+i;
end;
do i = 0 to (month(enddate)-month(startdate));
month = month(startdate)+i;
drop i;
output;
end;
run;**
Consider the following example:
data have;
input project$ startdate:date9. enddate:date9.;
format startdate enddate date9.;
datalines;
A 01JAN2022 01APR2022
B 01MAR2022 01JUN2022
C 01NOV2022 01JAN2023
;
run;
The third row will fail to run because the difference between the start month number and end month number is negative (1 - 11). Instead of doing two loops, one for year and one for month, do a single loop for all of the months from the start date. Use intnx() to generate your months using startdate as the reference month. i will offset each month from the start date. For example:
code output
intnx('month', '01JAN2022'd, 0) 01JAN2022
intnx('month', '01JAN2022'd, 1) 01FEB2022
intnx('month', '01JAN2022'd, 2) 01MAR2022
Since you're incrementing by exactly one month for each date, you can get the year and month number in a single loop.
data want;
set have;
do i = 0 to intck('month', startdate, enddate);
month = month(intnx('month', startdate, i) );
year = year(intnx('month', startdate, i) );
output;
end;
drop i;
run;
Your code doesn't seem to handle the cross of years, ie if a project started in 2021 and ended in 2022.
This should get you closer.
data have;
input startdate : date9. enddate : date9.;
format startdate enddate date9.;
cards;
01Jan2022 01Apr2022
01Sep2021 01Apr2022
;;;
run;
data want;
set have;
nmonths = intck('month', startdate, enddate) +1 ;
date = startdate;
do i = 1 to nmonths;
month = month(date);
year = year(date);
date = intnx('month', startdate, i, 'b');
output;
end;
run;

Using do loops in sas

Assume you have a data file called VIRUS_PROLIF from an infectious disease research center. Each observation has 3 variables COUNTRY START_DATE, and DOUBLE_RATE, where START_DATE is the date that the Country registered its 100th case of COVID-19. For each country, DOUBLE_RATE is the number of days it takes for the number of cases to double in that country. Write the SAS code using DO UNTIL to calculate the date at which that Country would be predicted to register 200,000 cases of COVID-19.
data VIRUS_PROLIF;
INPUT COUNTRY $ start_date mmddyy10. num_of_cases double_rate ;
*here doubling rate is 100% so if day 1 had 100 cases day 2 will have 200;
Datalines;
US 03/13/2020 100 100
;
run;
data VIRUS_PROLIF1 (drop=start_date);
set VIRUS_PROLIF;
do until (num_of_cases>200000);
double_rate+1;
num_of_cases+ (num_of_cases*1);
end;
run;
proc print data=VIRUS_PROLIF1;
run;
The key concept you're missing here is how to employ the growth rate. That would be using the following formula, similar to interest growth for money.
If you have one dollar today and you get 100% interest it becomes
StartingAmount * (1 + interestRate) where the interest rate here is 100/100 = 1.
*fake data;
data VIRUS_PROLIF;
INPUT COUNTRY $ start_date mmddyy10. num_of_cases double_rate;
*here doubling rate is 100% so if day 1 had 100 cases day 2 will have 200;
Datalines;
US 03/13/2020 100 100
AB 03/17/2020 100 20
;
run;
data VIRUS_PROLIF1;
set VIRUS_PROLIF;
*assign date to starting date so both are in output;
date=start_date;
*save record to data set;
output;
do until (num_of_cases>200000);
*increment your day;
date=date+1;
;
*doubling rate is represented as a percent so add it to 1 to show the rate;
num_of_cases=num_of_cases*(1+double_rate/100);
*save record to data set;
output;
end;
*control date display;
format date start_date date9.;
run;
*check results;
proc print data=VIRUS_PROLIF1;
run;
The problem 200,000 < N0 (1+R/100) k can be solved for integer k without iterations
day_of_200K = ceil (
LOG ( 200000 / NUM_OF_CASES )
/ LOG ( 1 + R / 100 )
);

How to subtract date/time values from different rows in the same column in sas

I got this values in my table and I need to know how can I subtract them creating another column with the results.
19FEB2018:14:24:43.00
23MAR2018:12:57:58.00
28MAR2018:15:37:37.00
29JUN2018:10:30:33.00
29JUN2018:13:43:07.00
What I need is:
1- 0h
2- (23MAR2018:12:57:58.00 - 19FEB2018:14:24:43.00)
3- (...)
Just use the DIF() function.
data have;
input dt datetime.;
format dt datetime22.2 ;
cards;
19FEB2018:14:24:43.00
23MAR2018:12:57:58.00
28MAR2018:15:37:37.00
29JUN2018:10:30:33.00
29JUN2018:13:43:07.00
;
data want;
set have ;
diff = dif(dt);
format diff hhmm12.2 ;
run;

How to get week value based on financial year in SAS?

I have below dataset , I need to find the week number from the date given based on the financial year(e.g April 2013 to March 2014). For example 01AprXXX , should be 0th or 1st week of the year and the consequent next year March's last week should be 52/53. I have tried a way to find out the same( code is present below as well).
I am just curious to know if there is any better way in SAS to do this in SAS
. Thanks in advance. Please let me know if this question is redundant, in that case I would delete it at the earliest, although I search for the concept but didn't find anything.
Also my apologies for my English, it may not be grammatically correct.But I hope I am able to convey my point.
DATA
data dsn;
format date date9.;
input date date9.;
cards;
01Nov2015
08Sep2013
06Feb2011
09Mar2004
31Mar2009
01Apr2007
;
run;
CODE
data dsn2;
set dsn;
week_normal = week(date);
dat2 = input(compress("01Apr"||year(date)),date9.);
week_temp = week(dat2);
format dat2 date9.;
x1 = month(input(compress('01Jan'||(year(date)+1)),date9.)) ;***lower cutoff;
x2 = month(input(compress("31mar"||year(date)),date9.)); ***upper cutoff;
x3 = week(input(compress("31dec"||(year(date)-1)),date9.)); ***final week value for the previous year;
if month(dat2) <= month(date) <= month(input(compress("31dec"||year(date)),date9.)) then week_f = week(date) - week_temp;
else if x2 >= month(date) >= x1 then week_f = week_normal + x3 - week(input(compress("31mar"||(year(date)+1)),date9.)) ;
run;
RESULT
INTCK and INTNX are your best bets here. You could use them as I do below, or you could use the advanced functionality with defining your own interval type (fiscal year); that's described more in the documentation.
data dsn2;
set dsn;
week_normal = week(date);
dat2 = intnx('month12.4',date,0); *12 month periods, starting at month 4 (so 01APR), go to the start of the current one;
week_F = intck('week',dat2,date); *Can adjust what day this starts on by adding numbers to week, so 'week.1' etc. shifts the start of week day by one;
format dat2 date9.;
run;

Convert to a SAS Time

I have a txt file containing time in this format 161058.262 which is intended to be 16:10:58.262.
I cannot find an INFORMAT that will turn this value into the correct SAS numeric time value. TIME12.3 will convert into a numeric. It gets stored as 579824520 and displays using format TOD12.3 format as 22:22:00.000
Any suggestions?
Thanks
Dan
I would do a quick transformation to make an existing informat work. For example, your format is the same as what B8601TM expects, except for the dot that separates the fraction of a second. You can strip out the dot from your string and then apply the informat.
Example:
data test;
input t $10.;
format tt TOD12.3;
tt = inputn(compress(t, , "kn"), "B8601TM9.3");
datalines;
161058.262
; run;
I don't know about a specific informat, but you certainly can work in colons, or do the math to make it into a time using HMS.
data test;
informat t_pre $10.;
input t_pre $;
t = input(catx(':',substr(t_pre,1,2),substr(t_pre,3,2),substr(t_pre,5)),TIME12.3);
*CATX concatenates using a delimiter, so this generates a string like 16:10:58.262;
*Then converts to TIME12.3;
put t= TIME12.3 t_pre=;
datalines;
161058.262
;;;;
run;
data test;
input t_pre;
t = hms(floor(t_pre/10000),floor(mod(t_pre,10000)/100),mod(t_pre,100));
*HMS generates a time value from hours, minutes, seconds, and allows milliseconds in the seconds;
*So we use combination of division and modulo to separate the number into component parts;
put t= TIME12.3;
datalines;
161058.262
;;;;
run;
code
data _null_;
input int_val $10.;
format time_val timeampm15.3;
time_val = input(
prxchange('s/(\d?\d)(\d\d)(\d\d\.\d\d\d)/$1:$2:$3/',
-1, int_val),
time10.3);
put int_val
#15 time_val timeampm15.3
#30 time_val 10.3;
datalines;
000000.001
012345.678
12345.678
161058.262
235959.999
run;
log
000000.001 12:00:00.000 AM 0.000
012345.678 1:23:45.600 AM 5025.600
12345.678 1:23:45.670 AM 5025.670
161058.262 4:10:58.200 PM 58258.200
235959.999 11:59:59.900 PM 86399.900
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds