BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Gick
Pyrite | Level 9

Hello,

 

I have a database in Excel with a date variable of modalities 01/21/2022, 03/02/2019, 06/01/2010, etc. When I import it into SAS, the date variable contains the modalities 44949. I tried this code to keep date variable as character in order to convert it, it doesn't work. My problem is with the import. Can anyone help me please.

Any suggestions for improving codes or another alternative are welcome.

 

Thanks in advance.

Gick

proc import datafile="I:\DOC\Questionnaires.xlsx" 
           dbms=xlsx 		   
           out=data replace ;
	mixed=yes;
     	   scantext=yes;
run;  

 

1 ACCEPTED SOLUTION

Accepted Solutions
Oligolas
Barite | Level 11

if you already have a numeric value use

YOUR_DTC=put(XLSX_COLUMN_NAME-21916,e8601da.);

Difficult to say without knowing your data

________________________

- Cheers -

View solution in original post

14 REPLIES 14
PaigeMiller
Diamond | Level 26

A quick search of the forum for "Excel dates" turns up plenty of correct answers

https://communities.sas.com/t5/forums/searchpage/tab/message?q=excel%20dates

--
Paige Miller
Kurt_Bremser
Super User

Save the sheet to a csv file and read that with a DATA step, where you have full control and can deal with special values which cause the IMPORT problem (reading dates as character).

 

The number you got is the internal representation of a date in Excel. Add '30dec1899'd to it to get the correct SAS date.

Gick
Pyrite | Level 9
Hello,

where do I add it?
Can you elaborate more please? For example by giving an example of code.

Thanks
Gick
PaigeMiller
Diamond | Level 26

@Gick wrote:
Hello,

where do I add it?
Can you elaborate more please? For example by giving an example of code.

Thanks
Gick

The link I gave has oodles of examples of actual SAS code to do this.

--
Paige Miller
Gick
Pyrite | Level 9

Hello,

where do I add it ? Can you elaborate more please? For example by giving an example of code.

 

Thanks.

Gick

Oligolas
Barite | Level 11

Hi,

common source of issue when data providers do not use a suitable database system.

Either you proceed as @Kurt_Bremser said, converting to *.csv where format are kept

or you import as you did and perform the correct date conversion afterwards.

Excel do not use the same start time reference value as SAS, so you have to convert by yourself.

 

YOUR_DTC=put(input(XLSX_COLUMN_NAME,best32.)-21916,e8601da.);

so you get "2023-01-23"

________________________

- Cheers -

Gick
Pyrite | Level 9
it does not work. Here is the message I get in the log

ERROR: Variable date has been defined as both character and numeric.
Kurt_Bremser
Super User

In order to supply working code, we need usable example data so we know the names and attributes of your variables. Post example data as a working DATA step with DATALINES, so we can easily replicate your data in our environments for testing.

The ERROR indicates that you either try to convert "in place", which is not possible, or you already have a variable called date with the wrong type.

In the future, whenever you get WARNINGs or ERRORs, or have other issues with your code, post the complete (all code and all messages) log by copy/pasting into a window opened with this button:

Bildschirmfoto 2020-04-07 um 08.32.59.jpg

Oligolas
Barite | Level 11

if you already have a numeric value use

YOUR_DTC=put(XLSX_COLUMN_NAME-21916,e8601da.);

Difficult to say without knowing your data

________________________

- Cheers -

SASKiwi
PROC Star

I suggest you try the EXCEL engine rather than XLSX:

proc import datafile="I:\DOC\Questionnaires.xlsx" 
           dbms=EXCEL		   
           out=data replace ;
	mixed=yes;
     	   scantext=yes;
run;  

If that doesn't help then try saving the column type in Excel as "Date" or "Short Date" instead of the default "General". Then rerun the above code.

AMSAS
SAS Super FREQ

Find below a simple example using the Excel date Values you had in the initial post

A couple of things to note:

  1. Excel stores dates as a number e.g. 1 = 01 Jan 1990, 2 = 02 Jan 1990, ...
  2. Excel doesn't appear to handle dates prior to 1900 (I'm no Excel expert, just an observation when looking into this post)
  3. SAS stores dates as the number of days since 01 Jan 1960 e.g. 0 = 01 Jan 1960, 1 = 02 Jan 1960, ...

Once you know this it's a relatively simple task to convert Excel date values to SAS date values, you just need to know the number of days to subtract from the Excel date value to convert it to a SAS Date Value. Knowing that 01 Jan 1960 is represented as 21,916 in Excel and 0 in SAS tells us to subtract 21,916 from the Excel Date Value.

/* Simulated date values from Excel */
data have ;
	infile cards ;
	input excelDateValue ;
cards ;
44582
43526
40330
21916
1
;

/* Read the simulated date values and conver to SAS Date values */
data want ;
	format sasDateValue date7. ;
	set have ;
	sasDateValue=excelDateValue-21916 ;
	put sasDateValue= 8. sasDateValue= ;
run ;

 

Tom
Super User Tom
Super User

Do not use magic numbers in programming.

 

The number used in your code posted is 30DEC1899 .

   1  %put %sysfunc(putn(-21916,date9));
30DEC1899

So just use the actual date in the code:

sasDateValue=excelDateValue+'30DEC1899'd ;

Also you left out of your explanation for the reason why you want to use the 30th instead of the 31st.  It is because Excel mimics the decision made for Lotus 1-2-3 to treat the year 1900 as a leap year which causes the difference to be off by one day (at least for dates from 01MAR1900 on).  

Tom_0-1674831698700.png

 

Kurt_Bremser
Super User

Excel does not work with dates prior to 1900 because it perpetuates a bug (actually, a trick to speed up calculations) it inherited from Lotus 1-2-3. It considers 1900 a leap year, which it was not. So all dates before March 1, 1900 are calculated wrongly.

This is also the reason why the correction value is 30dec1899 and not 31dec1899.

 

Other office software (e.g. LibreOffice) has this corrected and does therefore work with dates prior to 1900.

Patrick
Opal | Level 21

Excel is NOT a database and for this reason you can't rely on getting a consistent result when importing into SAS. 

If you can at least rely on the structure of the Excel source - like in the first column should always be a string for a specific variable - then below an approach I'm using sometimes. 

It's reading the Excel with the header row included as data so the resulting SAS variables always become type character and then mapping these initial columns to what I really need.

/* read Excel headers as data so all variables become character */
%let path=<some path>;
%let xlsx_file=<excel workbook name>;
proc import 
  file="&path/&xlsx_file"
  out=work._xl_src
  dbms=xlsx
  replace
  ;
  datarow=1;
  getnames=no;
run;

/* map initial variables to desired variable */
data work._dq_&p1._&target_tbl.;
  set work._xl_src(firstobs=2);
  drop a-<last column from Excel import>;

  /* map source to target columns */
  want_var_1            = input(A, ?? 32.   );
  want_var_2            = input(B, ?? $30.  );
  ...and so on...
run;

 

SAS Innovate 2025: Save the Date

 SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!

Save the date!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 14 replies
  • 3189 views
  • 3 likes
  • 8 in conversation