SAS importing dates from excel - sas

I have an xlsx dataset that I import using proc import. There is a column in excel that holds date values like:
2018-11-30 00:00:00
When I import it into SAS it automatically converts it into a number 43434.
When I try to cast this to a date: put(col,date9.), i get:
2078-12-01
What is happening? How can I get back the correct date. I tried mixed=yes option but it does not work with dbms=xlsx. When i do dbms=excel, it does not work as expected

Sometimes SAS imports the date as a raw Excel date. I don't know exactly why or when it does this, but I think it has something to do with the format of the date. If this happens, subtract the date by 21916 to convert from an Excel date to a SAS date.
data want;
set imported_from_excel;
date = excel_date - 21916;
run;

Related

SAS date imported wrong

When I imported my excel sheet some dates imported differently than others. I tried to fix this with the code below to format the date.
DATA volume;
SET mice.volume;
format Date MMDDYY10.;
run;
However, I received the following error.
ERROR 48-59: The format $MMDDYY was not found or could not be loaded.
I had also tried with the following code
DATA volume;
SET mice.volume;
If date= 44138 then date= '11/3';
If date= 44141 then date= '11/6';
run;
NOTE: Character values have been converted to numeric values at the places given by: (Line):(Column).
A Proc Contents shows the variable= Date type= Char Len=7 format=$7 Informat=$7 Label= Date
How do I fix this?
The date column being character having a mix of 'date looking' strings, and Excel date value numbers tells me some of the date values in your Excel are actually strings, such as '11/10 or ='11/10'.
The raw number 44138 is:
a SAS date value is 04-NOV-2080 (obviously not what is wanted)
an Excel date value 03-NOV-2020 (aha!)
03-NOV-2020 as SAS date value is 22222
an offset of -21916 from Excel
-21916 is the SAS date 30-DEC-1899
Date Epochs
An epoch is the date corresponding to a base number 0 in a systems calendar. SAS Base year is 1960 and Excel Base year is 1900.
Formatted
Number Actual Date Date Shown System/Format
------ ----------- ----------- ----------
0 31-DEC-1899 1/0/1900 Excel / Short Date (Formatter is weird at Epoch)
0 01-JAN-1960 01-JAN-1960 SAS / DATE11.
21916 01-JAN-1960 1/1/1960 Excel / Short Date
-21916 30-DEC-1899 31-DEC-1899 SAS / DATE11.
Notice the round trip is from 31-dec-1899 to 30-dec-1899. This due to an Excel 97 bug that has been carried forth for legacy reasons. See Microsoft's explanation in "Excel incorrectly assumes that the year 1900 is a leap year" which pushes the blame back even further to Lotus 1-2-3
The formula to convert between systems S1 and S2 date numbers is to add the # for the other systems epoch date (# # 0)
SAS#(date) = Excel#(date) + SAS#(Excel Epoch Date) - 1 (Excel leap year bug), or
sas_dt = excel_dt + '31-DEC-1899'd - 1; *or;
sas_dt = excel_dt + '30-DEC-1899'd;
What happened
Mixed value types in the Excel date column forced IMPORT to perceive the date variable as character.
The Excel cells with a date looking m/d string were brought in as the string
The Excel cells with a date, likely custom formatted as m/d, were brought in as the underlying Excel date number.
The ERROR
You tried to apply the date format MMDDYY. to the character variable Date.
A character column can not be assigned a numeric or date format, thus you get the
ERROR 48-59: The format $MMDDYY was not found or could not be loaded.
SAS automatically presumed MMDDYY. meant a character format $MMDDYY. because the variable type was character.
The Fix
You can convert the values in the character date column with code such as the following (untested):
if index(date,'/') then
date_fixed = input (trim(date)||'/2020', mmddyy10.);
else
date_fixed = input(date,best12.) + '30-DEC-1899'D;
format date_fixed yymmdd10.;
If you want to continue showing only mm/dd in SAS, use the format NLDATEM5.
format date_fixed NLDATEM5.;

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;

Add a number of days to SAS datetime format

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.;).

Convert SAS numeric dates to datetime format

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.);

How to add hyphen in values in SAS Enterprise Guide (to put in date format)?

I have a table in SAS that has a column of dates but are not in the typical date format (DD-MM-YY). For example, one of them is
21JUN2012:00:00:00
What can I do so that it is in the format
21-Jun-12
? I am using SAS Enterprise Guide so I know I would have to selected Computed Column but I do not know how to go from there. I was thinking of using TRANWRD but I can't seem to get it work.
I would appreciate any help, thanks.
Right-click on the column to be converted and select Properties.
Change the type to Numeric and click Yes in the warning prompt regarding precision.
Change the Group to Date.
Click Informats; the selected value under Categories should be Date.
Change the informat to DDMMYYSw.
Under Attributes, assign an overall width of 10
Click Formats; the selected value under Categories should be Date.
Change the format to DDMMYYSw.
Under Attributes, assign an overall width of 10.
Click OK
If the conversion results are correct in the Preview Results window,
click Commit changes.
Reference
There are many date formats and informats available in SAS to change the date format being presented. A full list of the formats can be found here in the SAS documentation. The format you want is ddmmyyd. and you can just apply the format to the date value (see col1_ example).
For datetime values, you need to use the DATEPART function to extract the date value before applying the format (see col2_ and col3_ examples below).
If your date is provided as text, you need to apply an informat to it to convert it to SAS date value and then you can apply your desired date format to the value using PUT statements. Including converting this value back to text (see col4_ examples below).
data date_infile;
infile datalines delimiter=',';
input col1_date :date9. col2_dtime :datetime18. col3_dtime :datetime18. col4_text $18.;
format col1_date date9. col2_dtime col3_dtime datetime18.;
datalines;
21jun2012,21JUN2012:00:00:00,21JUN2012:12:34:56,21JUN2012:00:00:00
11aug2012,11AUG2012:00:00:00,11AUG2012:01:23:45,11AUG2012:00:00:00
05oct2019,05OCT2019:00:00:00,05OCT2019:01:23:45,05OCT2019:00:00:00
;
run;
data date_results;
set date_infile;
format col1_date col2_date col3_date col4_date ddmmyyd.;
col2_date = datepart(col2_dtime);
col3_date = datepart(col3_dtime);
col4_date = datepart(input(col4_text, datetime18.));
col4_date_as_text = put(put(datepart(input(col4_text, datetime18.)), ddmmyyd.), $8.);
run;