%let months_back = %sysget(months_back);
data;
m = intnx('month', "&sysdate9"d, -&months_back - 2, 'begin');
m = intnx('day', put(m, date9.), 26, 'same');
m2back = put(m, yymmddd10.);
put m2back;
run;
NOTE: Character values have been converted to numeric values at the
places given by: (Line):(Column).
5:19 NOTE: Invalid numeric data, '01OCT2012' , at line 5 column 19.
I really don't know why this go wrong. The date string is numeric data?
PUT(m, date9.) is the culprit here. The 2nd argument of INTNX needs to be numeric (i.e. a date), the PUT function always returns a character value, in this instance '01OCT2012'. Just take out the PUT function completely and the code should work.
m = intnx('day', m, 26, 'same');
SAS stores dates as numbers - and in fact does not have a truly separate type for them. A SAS date is the number of days since 1/1/1960, so a bit over 19000 for today. The date format is entirely irrelevant to any date calculations - it is solely for human readibility.
The bit where you say:
"&sysdate9"d
actually converts the string "01JAN2012" to a numeric value (18304).
There's actually a quicker way to accomplish what you're trying to do. Because days correspond to whole numbers in SAS, to increment by one day you can simply add one to the value.
For example:
%let months_back=5;
data _null_;
m = intnx('month', today(), -&months_back - 2, 'begin');
m2 = intnx('day', m, 26, 'same');
m3 = intnx('month',"&sysdate9"d, -&months_back - 2)+26;
m2back = put(m2, yymmdd10.);
put m= date9. m2= yymmdd10. m3= yymmdd10.;
run;
M3 does your entire calculation in one step, by using the MONTH interval, then adding 26. INTNX('day'...) is basically pointless, unless there's some other value to using the function (using a shift index for example).
You also can see the use of a format in the PUT(log) statement here - you don't have to PUT it to a character value and then put that to the log to get the formatted value, just put (var) (format.); - and string together as many as you want that way.
Also, "&sysdate9."d is not the best way to get the current date. &sysdate. is only defined on startup of SAS, so if your session ran for 3 days you would not be on the current day (though perhaps that's desired?). Instead, the TODAY() function gets the current date, up to date no matter how long your SAS session has been running.
Finally - I recommend data _null_; if you don't want a dataset (and naming the result dataset if you do want it). data _null_ does not create a dataset. data; simply creates increasing numbers of datasets (data1, data2, ...) which quickly fill up your workspace and make it hard to tell what you're doing.
Related
How to convert the default timestamp "0001-01-01-00.00.00.000000" in SAS, i have tried below code but it has returned null value. Can someone help on this please
data _NULL_;
x = "0001-01-01-00.00.00.000000";
rlstime = input(x,anydtdtm26.);
call symput('rlstime',rlstime);
run;
%put rlst: &rlstime;
As far as I remember, SAS cannot do that. Any date/timestamp before 1.1.1600 doesn't exist for SAS. Do you need it or can you just replace it with a null value? If you really need it you could transform it into another valid timestamp, split it into different columns (year, month, etc.) or just use it as a string. In your example you just write the timestamp into the log, meaning it's not necessary to transform it.
The earliest date that SAS will handle is 1st January, 1582. Additionally, a colon character should be used to delimit the time from the date, as well as the hours, minutes and seconds. Therefore, your code may be adjusted to the following:
data _NULL_;
x = "1582-01-01:00:00:00.000000";
rlstime = input(x,anydtdtm26.);
call symput('rlstime',rlstime);
run;
%put rlst: &rlstime;
I Have a file from excel that is in a short date format, but when SAS reads it in, it turns it into numbers in the 4000 range...when I try and convert this to an excel date with the below formula, it turns the year into 2077...is there a formula to ensure that this date remains in the original format on the read in, or avoid it turning into this 4000 range that is not at all close to the 2017 and 2018 year that my file is starting in. Does that make sense?
data change_date;
format Completed_Date mmddyy8. ;
set check;
completed_date = date_completed;
if 42005 => date_completed >=43466 and date_completed ^=. then
Completed_date = Date_Completed-21916; *commented out 12-21-17 Xalka
dates back to how they are expected;
run;
I am pretty sure this is a duplicate question, but I can't find it.
This is usually caused by mixing character and date values in the same column. This made SAS import the data as a character variable and it results in the actual dates being copied as character versions of the integers that Excel uses to store dates.
Frequently this is caused by entries that look like dates but are really character strings in the Excel file. The best way to fix it is to fix the Excel file so that the column only contains dates. Otherwise you just need to convert the strings to integers and adjust the values to account for the differences in index dates.
So if your values are in a SAS dataset named HAVE in the character variable DATESTRING then you could use this data step to create a new variable with an actual date value.
data want ;
set have ;
if indexc(datestring,'-/') then date=input(datestring,anydtdte32.);
else date = input(datestring,32.) + '01JAN1900'D -2;
format date yymmdd10. ;
run;
The minus 2 is because of difference in whether to start numbering with 1 or 0 and because Excel thinks 1900 was a leap year.
Excel and SAS have different default dates in back-end.
Day 0 in SAS is 1 January 1960 and Day 0 in Excel is 1 January 1900.
So, you will need to convert excel numeric date to sas date using the below formula.
SAS_date = Excel_date - 21916;
data dateExample;
informat dt mmddyy8.;
set dates;
SAS_date = dates - 21916;
dt=sas_Date;
format dt date9.;
run;
How do I convert 06JAN2005(as date format) to 200501 (as a number)
Note that there are only two different variable types in SAS - character and numeric. Dates are stored in numeric variables and are generally formatted to appear as user-readable dates. Specifically, dates are stored as the number of days since 01JAN1960.
So if you have a number already formatted as a date, and would like it to appear formatted differently (but still be a number) you simply need to change the format.
As Joe's comment says - I can't see the relationship between the date you provided and the number you desire (maybe you have a typo?). But the below piece of code will demonstrate how you can simply change the format to change the appearance of the number:
data _null_;
format date1 best.
date2 yymmddn6.
date3 date9.
;
date1 = '06JAN2005'd;
date2 = '06JAN2005'd;
date3 = '06JAN2005'd;
put date1= date2= date3=;
run;
Gives:
date1=16442 date2=050106 date3=06JAN2005
If you want an explicit numeric value, you can use the date functions on your date variable which, as pointed out, is a numeric date value SAS understands.
newdatevar=100*year(olddatevar)+month(olddatevar)
Well if you mean you need year||month then something like this should work:
data two;
set one;
order_month = month(date);
order_year = year(date);
order = put(compress(order_month||order_year),6.)-0;
run;
Disclaimer being I'd reccomend just formatting whatever else you have properly, so you don't need to represent the date as a number. If you're looking to add or substract increments of dates, you might want to look at the intx function too
Try this:
data a;
attrib
v_input format=date.
v_output_n format=8.;
v_input = '06JAN2005'd;
v_output_n = put(v_input,yymmn6.);
run;
I am trying to convert a numeric date into date-time format. I am first subtracting a few days from the date I have.
$let from_date = "21JUL2016:00:00:00"dt;
data _null_;
datediff = intnx('dtday',&from_dt,-180);
call symput("cutoff_dt",datediff);
run;
After this I get numeric date like 17633333 which is fine because I am using this numeric date in pass through queries. But I also need to convert this date into datetime format like "21Dec2015:00:00:00"dt so that I can use this date in proc sql as well. So far after searching through sas documents and blogs I have been unable to do this. Help please.
You can use PUT to apply the format, but if you need quotes and the dt then that's a different story. If you do need them, I think that the current macro variable would work as well. Otherwise you have some other issue going on. There is no requirement for SQL to require the formatted value, unless you need a character or you're passing it through to a DB. In those cases the dt won't be required either.
%let from_date = "21JUL2016:00:00:00"dt;
data _null_;
datediff = intnx('dtday',&from_dt,-180);
call symput("cutoff_dt", put(datediff, datetime21.));
run;
SAS stores dates times and datetime values as numbers. Just like in a datastep
where you can write "where x='19feb2016'd" or "where x=20503" which is the number that SAS stores for the date=19feb2016, you can do the same in proc sql.
You only need to write the date value out as a character value if the variable you are comparing to contains the date as a character string. that is y has the value "19feb2016" and x has the value 20503, the test if y=x will not achieve what you want. That is when you have to write if y=put(x,date9.);
I have a big database. There's a contract start date there. The problem is that in some time ago, several values had been imported there as a datetime format while the rest are just date9. In result now some sql queries or data queries shows weird results due to difference in seeing the "numbers" stored behind the contract start date.
Like when I want to get max(contract_start_date) (via sql, for example) I will get *************** instead of normal results.
My question is how can I unify this format difference? What I would like in the end is to make a new variable with unified format and then replace the existing contract start date with new one.
%let d_breakpoint=%sysfunc(putn('31dec2015'D, 13. -L));
%put &d_breakpoint;
%put %sysfunc(putn(&d_breakpoint, DATETIME. -L));
data indata;
format contract_start_date date9.;
do i=0 to 40;
contract_start_date = i*5000;
output;
end;
drop i;
run;
proc sql;
alter table indata add d_contract_start num format=date9.
;
update indata
set d_contract_start= case when contract_start_date > &d_breakpoint then contract_start_date/(24*60*60)
else contract_start_date end
;
quit;
proc sql;
select
min(d_contract_start) format=date9. as min
, max(d_contract_start) format=date9. as max
from indata
;
quit;
The variable has only one format, but one part of VALUES of that variable stored in table is not corresponding to that format - if the format is for DATE values (date as a number of days since 1jan1960) but some records store DATETIME values (number of seconds since midnight 1jan1960), the results are incorrect.
So you need to modify values to be of just one type - DATE or DATETIME.
The code above will change it to DATE values.
The idea is to define a breakpoint value - values above that will be treated as DATETIME values, the rest will be considered DATE values and will be kept like that.
In my example I've choosen DATE value of 31dec2015 (which is 20453) to be the breakpoint. So this represents 31dec2015 as DATE, while 01JAN60:05:40:53 as DATETIME.
Values below 20453 are considered DATE values, values above 20453 considered DATETIME values.