Add a number of days to SAS datetime format - sas

I need help with SAS datetime format.
Dataset(including desired column exp_dt):
datetime valid exp_dt
4OCT2017:13.00.00 1 5OCT2017:13.00.00
4OCT2017:15.20.00 7 11OCT2017:15.20.00
6OCT2017:08.00.00 30 5NOV2017:08.00.00
So, I need to add valid values (number of days) to datetime.
I've just started with SAS Base and I am not sure if any other datetime format is acceptable.
I've tried with this, but not sure if even going in right direction:
PlannedSchedTime = datetime ;
Postunit = 'DAY' ;
postval = valid ;
exp_dt = put(intnx(Postunit,PlannedSchedTime,postval,'same'),datetime20.);
put exp_dt= ;
run;
Also, I'm working on project in SAS Enterprise Guide, so maybe there is easier way through the GUI tasks?

Here a code sample that will print your desired result. Like the other answer states, DTDAY will tell SAS to add days when the base value is a datetime instead of a date.
data datetimes;
informat datetime anydtdtm. valid best12.;
format datetime datetime20.;
input datetime valid;
cards;
4OCT2017:13.00.00 1
4OCT2017:15.20.00 7
6OCT2017:08.00.00 30
;
run;
data datetimes_added;
set datetimes;
format exp_dt datetime20.;
exp_dt = intnx('DTDAY',datetime,valid,'SAME');
put exp_dt = ;
run;

You are definitely on the right path! Because you are dealing with datetime values, replace DAY by dtDAY.
If you don't want exp_dt to be a character column, don't use the put function but rather a format (e.g. format exp_dt2 datetime20.;).

Related

SAS: Converting numeric to character values

I am trying to convert datatime20. from numeric to character value.
Currently I have numeric values like this: 01Jan200:00:00:00 and I need to convert it to character values and received output like: 2020-01-01 00:00:00.0
What format and informat should be used in aboved ?
I have tried used PUT function to convert numeric to character and tried many option, each time receiving other format. Should be also use DHMS function before PUT ?
There is not a native format that produces that string exactly. But it it not hard to build it in steps using existing formats. Or you could use PICTURE statement in PROC FORMAT to build your own format.
If you don't really care about the time of day part of the datetime value then this is an easy and clearly understand way to convert the numeric variable DT with number of seconds into a new character variable in that style. Use DATEPART() to get the date (number of days) from the datetime value and then use the YYMMDD format to generate the 10 character string for the date and then just append the constant string of the formatted zeros.
length dt_string $21.;
dt_string = put(datepart(dt),yymmdd10.)||' 00:00:00.0';
If you need the time of day part then you could also use the TOD format.
dt_string = put(datepart(dt),yymmdd10.)||put(dt,tod11.1);
Or you could use the format E8601DT21.1 and then change the letter T between the date and time to a space instead.
dt_string = translate(put(dt,E8601DT21.1),' ','T');
If you want to figure out what formats exist for datetime values and what the formatted results look like you could run a little program to pull the formats from the meta data and apply them to a specific datetime value.
data datetime_formats;
length format $50 string $80 ;
set sashelp.vformat;
where fmttype='F';
where also fmtinfo(fmtname,'cat')='datetime';
keep format string fmtname maxw minw maxd ;
format=cats(fmtname,maxw,'.','-L');
string=putn('01Jan2020:01:02:03'dt,format);
run;
A custom format can be defined to return the result of a user defined function. Docs
proc format;
value <format-name> (default=<width>)
other = [<function-name>()]
;
run;
Example:
options cmplib=(sasuser.functions);
proc fcmp outlib=sasuser.functions.temporal;
function E8601DTS (datetime) $21;
return (
translate (putn(datetime,'E8601DT21.1'),' ','T')
);
endsub;
run;
proc format;
value E8601DTS (default=21)
other = [E8601DTS()]
;
run;
data have;
do dt = '01jan2020:0:0'dt to '10jan2020:0:0'dt by '60:00't;
output;
end;
format dt datetime16.;
run;
ods html file='function-based-format.html';
proc print data=have(obs=4); title 'stock E8601DT';
proc print data=have(obs=4); title 'custom E8601DTS';
format dt E8601DTS.;
run;
ods html close;

Excel to SAS Date not working in SAS

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;

SAS: convert date to numeric

I have a column that contains date values. So when imported as numeric, it shows 20668, 20669...etc. if I format it as yymmddn8, it shows 20160802 etc. However, what I really want is a numeric variable that shows 20160802. I have tried to create other to get day, month, year and then concatenate them. Unfortunately, the issue is if month and day is 1 digit, it would only show 201682. what would be the quickest way to achieve my goal. I guess a can turn the day and month variable to text and add 0 if day or month is less than 10. But this is not elegant and efficient. Please help.
Thanks
You can just wrap an input around that format:
data test;
date = 20668;
full_date = input(put(date,yymmddn8.),best12.);
run;
The put is converting the date to character in the format as you want it to appear, and the input with the best12. format is converting it back to numeric in that format.
It sounds like you just need to attach a format to your variable.
format date yymmddn8. ;
Try running this program to see a few of the different formats that are available for displaying dates.
data _null_;
do date = 20668, 20669 ;
put (6*date) (=10. =date9. =yymmddn8. =mmddyy10. =ddmmyy10. =yymmdd10.) ;
end;
run;

How to convert Datetime into SAS format

I am working with a huge number of observations in different tables in different versions.
I will use a date %let date_to_view = "20JAN2014:16:10"dt;
But how to convert this date into SAS format?
I knew how to Convert SAS data type (use proc sql):
dhms("01JAN1970'd,3,0,i.valid_dttm/1000) format datetime20.
I see date 20JAN2014:16:34:10 is 1390224849927 but how to convert it into code?
In your formula dhms("01JAN1970'd,3,0,i.valid_dttm/1000) you are converting a number that represents the number of milliseconds since 01JAN1970 to a SAS datetime value that represents the number of seconds since 01JAN1960. You also appear to be adding 3 hours.
So it sounds like your question is how to convert a SAS DATETIME value into a Unix timestamp value. So just reverse the arithmetic.
Your formula to convert from a Unix timestamp to a SAS datetime was:
sasdt2 = '01JAN1970:00:00'dt + '03:00't + unix_timestamp2/1000 ;
So to convert from a SAS datetime value to a Unix timestamp use:
unix_timestamp1 = 1000*(sasdt1 - '01JAN1970:00:00'dt - '03:00't) ;
"20JAN2014:16:10"dt is already in the correct SAS date (datetime) format, but as a date literal. SAS stores this as a number, representing the number of seconds since 01JAN1960:00:00:00.
If you just want the date component of the datetime, use the datepart() function, and format the result accordingly, e.g. date9..
data want ;
dt = "20JAN2014:16:10"dt ;
date = datepart(dt) ;
format dt datetime19. date date9. ;
/* To have 'date' show as the unformatted value, simply remove the format */
format date best32. ;
run ;

DateTime trouble in SAS

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.