I have a var of birth date in this format: 15APR1954
I need to set a new var that will present the current age - as if today's date is 01.01.2011
in order to use the var, how do I convert the date?
otherwise it gives me the following error :"The MDY function call does not have enough arguments".
data DAT2;set DAT1;
array BD{*} birth_date;
Curage=0;
do i=1 to dim(BD);
Curage+(MDY(01012011)-(birth_date));
end;
drop i;
run;
The best way to calculate age is to use the SAS built-in function yrdif().
data dat2;
set dat1;
curage = yrdif(birth_date, today(), 'AGE');
run;
The function today() returns today's date. If you want the age as of a certain date, e.g. 2011-01-01 like in your example, you can replace today() with '01JAN2011'd or with mdy(1, 1, 2011). (Note that your syntax for mdy() was incorrect.)
I'll also note that your array approach doesn't make a whole lot of sense; you're defining an array with only one element, so you might as well just perform operations on that value. Arrays are useful when you wish to perform identical operations to a group of 2 or more variables. For thorough information on array processing in SAS, see this section of the documentation.
Related
I tried a lot to convert the column LOADTIME (Format Datetime20.) into DDMMYYP10. But it doesn't work.
I tried it also just with PUT or INPUT and also DATEPART, but nothing works.
PROC SQL;
UPDATE SERVER.VIEWTABLE V
SET 'Load_Time__c'n = INPUT(PUT(V.LOAD_TIME, DATETIME20.), DDMMYYP10.);
QUIT;
The result of the code below is nothing, it runs thru but nothing is written in the field Load_Time__c.
SAS stores DATETIME values as the number of seconds and DATE values are the number of days. So before you change the display format attached to the variable you need to change the values stored in the variable. You can use the DATEPART() function to convert a datetime value to a date value.
It is probably going to be easier to make a NEW dataset with the new variable instead of trying to modify the existing dataset. Or possibly a new VIEW?
data want ;
set have ;
LOAD_TIME = datepart(LOAD_TIME);
format LOAD_TIME ddmmyyp10.;
run;
I wanted to know, how can we define date format from given date
for example, i have date 20180423 then in sas I want to define format as 'yyyymmdd'
similarly , i have date given in data as 12022018 then i want to define as 'ddmmyyyy'
Please note that, date is provided to me in proper date, but i want to define format now.
Date given may be different in future
so I need to take care all of the date format through SAS
What I thought was given date 20180422
use substr function
data test;
a=20180422;
a=substr(a,1,4);
b=substr(a,5,1);
c=substr(a,7,1);
run;
but not sure.
If anyone can provide the solution,then it really helps me in my project work.
Thanks in Advance for help.
It sounds like you want to convert various values to a date. SAS stores dates as a number, being the number of days since 1st Jan 1960. It's then usual to format this number to display as a date, in whichever format is preferred.
When importing dates that's are already in a format, it is necessary to use the input function, along with an informat, to convert the formatted value to a SAS date. If the date values being read in are all in the same format, then the specific informat can be used. In your case, where different formats are used, you can use the anydtdte. informat which will convert most of the standard date formats to a SAS date.
The example below converts 3 different date formats to a SAS date, then displays the SAS date in the date9. format. I've printed both the unformatted and formatted new values to the log, just so you can see they are stored as numbers.
data _null_;
input date_in $20.;
date_out = input(date_in, anydtdte20.);
put date_in date_out date_out :date9.;
datalines;
20180422
12022018
27apr2018
;
run;
Use the input(a,anydtdte20.); this will convert any date to SAS date, then use the functions Year(), Month(), Day() to extract the data you want.
You will find this SAS Post very useful about dates and locales.
Solution:
I created a table with two rows; each row have a different date format YYYYMMDD & DDMMYYYY to show you how the code will handles different date formats, saved them to SAS date and broke them down to Year, Month & Day:
options DATESTYLE=DMY;
data have;
input a;
datalines;
20180422
12022018
;
run;
data test;
set have;
format date_a date9.;
date_a=input(a,anydtdte20.);
Year_a=year(date_a);
month_a=month(date_a);
day_a=day(date_a);
run;
Output:
a=20180422 date_a=22APR2018 Year_a=2018 month_a=4 day_a=22
a=12022018 date_a=12FEB2018 Year_a=2018 month_a=2 day_a=12
You can use an if condition inside a data step. Using If condition, check for the condition to be true (check date value satisfies the required criteria), then format the date using a put function.Put function can take a source as first argument and format as second argument , and return the formatted value. Different values of same column, can have different formats specified that way.
Something like this,
if a = 'date1CheckCondtion' then newA = put(a , dateformat1.);
if a = 'date2' then newA = put(a , dateformat2.);
You may then choose to get all values in a common format like this:
dateA=input(newA,mmddyy6.);
Good day,
I wish to merge two dates to next closest.
Datasets are huge 500Mb to 1G so proc sql is out of the question.
I have two data sets. First (Fleet) has observations, second has date and which generation number to use for further processing. Like this:
data Fleet
CreatedPortalDate
2013/2/19
2013/8/22
2013/8/25
2013/10/01
2013/10/07
data gennum_list
date
01/12/2014
08/12/2014
15/12/2014
22/12/2014
29/12/2014
...
What I'd like to have is a link-table like this:
data link_table
CreatedPortalDate date
14-12-03 01/12/2014
14-12-06 01/12/2014
14-12-09 08/12/2014
14-12-11 08/12/2014
14-12-14 08/12/2014
With logic that
Date < CreatedPortalDate and (CreatedPortalDate - date) = min(CreatedPortalDate - date)
What I came up with is a bit clunky and I'm looking for an efficient/better way to accomplish this.
data all_comb;
set devFleet(keep=createdportaldate);
do i=1 to n;
set gennum_list(keep=date) point=i nobs=n;
if createdportaldate > date
and createdportaldate - 15 < date then do;/*Assumption, the generations are created weekly.*/
distance= createdportaldate - date;
output;
end;
end;
run;
proc sort data=all_comb; by createdportaldate distance; run;
data link_table;
set _all_comb(drop=distance);
by createdportaldate;
if first.createdportaldate;
run;
Any ideas how to improve or approach this issue?
Ignorant idea: Could I create hash tables where distance would be stored.
Arrays maybe? somehow.
EDIT:
common format
Done
Where does the billion rows come from?
Yes, there are other data involved but the date is the only linking variable.
Sorted?
Yes, the data is sorted and can be sorted again.
Are gen num dates always seven days apart ?
No. That's the tricky part. Otherwise I could use weekand year(or other binning) as unique identifier.
Huge is a relative term, today's huge is tomorrow's speck.
Key data features indicate a direct addressing lookup scheme is possible
Date values are integers.
Date value ranges are limited.
A date value, or any of the next 14 days will be used as a lookup verifier
The key is a date value, which can be used as an array index.
Load the Gennum lookup once as follows
array gennum_of ( %sysfunc(today()) ) _temporary_;
if last_date then
do index = last_date to date-1;
gennum_of(index) = prev_date;
end;
last_date = date;
And fetch a gennum as
if portaldate > last_date
then portal_gennum = last_date;
else portal_gennum = gennum_of ( portaldate );
If you have many rows due to grouping by account ids, you will have to clear and load up the gennum array per group.
This is a typical application of a sas by statement.
The by statement in a data step is meant to read two or more data sets at onece sorted by a common variable.
The common variable is the date, but it is named differently on both datasets. In sql, you solve that by requiring equality of the one variable to the other Fleet.CreatedPortalDate = gennum_list.date, but the by statement does not allow such construction, so we have to rename (at least) one of them while reading the datasets. That is waht we do in the rename clause within the options of gennum_list
data all_comb;
merge gennum_list (in = in_gennum rename = (date = CreatedPortalDate))
Fleet (in = in_fleet);
by CreatedPortalDate;
I choose to combine the by statement with a merge statement, though a set would have done the job too, but then the order of both input datasets makes a difference.
Also note that I requested sas to create indicator variables in_gennum and in_fleet that indicate in which input dataset a value was present. It is handy to know that this type of variables id not written to the result data set.
However, we have to recover the date from the CreatedPortalDate, of course
if in_gennum then date = CreatedPortalDate;
If you are new to sas, you will be surprised the above statement does not work unless you explicitly instruct sas to retain the value of date from one observation to the nest. (Observation is sas jargon for row.)
retain date;
And here we write out one observation for each observation read from the Fleet dataset.
if in_fleet then output;
run;
The advantages of this approach are
you need much less logic to correctly combine the observations from both input datasets (and that is what the data step is invented for)
you never have to retain an array of values in memory, so you can not have overflow problems
this sollution is of order 1 (O1), in the size of the datasets (apart from the sorting), so we know upfront that doubling the amount of data will only const double the time.
Disclaimer: this answer is under construction.
It will be tested later this week
I am trying to see if a variable falls into a boundary of dates.
I hate a DATE1 already in MMDDYY10.
I use the following code
DATA GIANT;
SET GIANT;
UPPER_BOUND= intnx('week', DATE1, 2);
run;
it gives me back something in Num 8.
I want to restore it to MMDDYY10. so that I can compare it to my other dates.
Two Questions:
How can I convert a NUMERIC of length 8 into a date?
Why does intnx ... designed to work with dates return a numeric and not something in the same format?
I tried to convert it like this:
DATA GIANT;
SET GIANT;
UP_DATE=INPUT(PUT(UPPER_BOUND, 8.), MMDDYY10.);
FORMAT UP_DOS MMDDYY10.;
run;
but now it all comes up as null.
SAS Dates are always numeric (# of days since 1/1/1960). Date formats are simply a way of making that numeric readable. INTNX returns a numeric because that's all a date is; it's up to you to apply a date format to the new variable.
In your case it's very simple. You almost got it right in your attempt, but you don't need the input/put business.
data giant;
set giant;
upper_bound=intnx('week',Date1,2);
format upper_bound MMDDYY10.;
run;
INPUT converts human readable text into a value (usually a number). PUT converts a value into human readable text. PUT(INPUT(...)) is commonly used to convert a formatted value into a different kind of formatted value (for example, to convert the string "1/1/1960" to "01JAN1960"); INPUT(PUT(...)) is not very commonly used unless you are parsing the string that PUT created (such as, to read just a particular date element or something like that). Both change the type (from numeric to character in PUT or other way in INPUT) in most cases and certainly change the actual stored value.
Applying a format to a numeric column leaves the column as a numeric (which is usually good) but tells SAS how to display that numeric so you can understand it (also usually good). So underneath the value is 19857 but what is displayed is 05/14/2014.
I am working on writing a SAS code and since I am new to SAS (Have worked on R all the time), I am having trouble understanding the date formats in SAS.
I Have a SAS data set Sales_yyyymm and I am creating a code that takes the user's input of a date value, and if Sales data exists for that date, I need to create a flag as 1 else as 0. Currently I am using this code -
%Let check_date = 20010120;
Data A;
Set B;
If date=&check_date then Date_Flag = 1;
else Date_Flag = 0;
run;
date is the Date column in my SAS data set Sales_yyyymm and the values are like 20130129, 20110412, 20140120 etc.
But if I run this code, I get all my Date_Flag values as 0. The IF condition is being ignored and I am not sure how or why this is happening.
Any idea?
Thanks!
You need to read Understanding How SAS Handles Dates article to get how SAS internally stores a date and how arithmetic on date including comparisions are carried out.
In SAS, every date is a unique number on a number line. Dates before
January 1, 1960, are negative numbers; those after January 1, 1960,
are positive. Because SAS date values are numeric variables, you can
sort them easily, determine time intervals, and use dates as
constants, as arguments in SAS functions, or in calculations.
As I mentioned in the comments you really need to specify your date literals in "ddmmmyyyy"d format.
So, %Let check_date = 20010120; should be written as:
%Let check_date = 20JAN2001;
Data A;
Set B;
If date="&check_date."d then Date_Flag = 1;
else Date_Flag = 0;
run;
20010120 translated into SAS date goes beyond the valid range SAS can handle. Ex: 2001012 - note there is no zero at the end, corresponds to "03AUG7438" - yes, that's year 7438!!
Whereas 14995 is the integer that SAS understands to be the date 20JAN2001