BookmarkSubscribeRSS Feed
ErikLund_Jensen
Rhodochrosite | Level 12

Hi Tom

 

Your post made me look closer on the date range, because I feared a flaw in a program working on similar principles.

 

SAS acceps dates between January 1, 1582 and December 31, 9999. The corresponding internal values are:
date: -138061 to 2936547
datetime: -11928470400 253717747199

 

This makes values in the interval -138061 to 2936547 ambiguous. It could be a datetime between
30dec1959:09:38:59 and 03feb1960:23:42:27 or a date in the whole legal day span.

 

Outside that interval, there is no ambiguity, so NOT (-138061 <= value <= 2936547) will be true for datetime values only, so if it is certain that the the transaction or whatever occurred within the last 58 years, it should be safe to distinguish using the magnitude.

EvoluZion3
Obsidian | Level 7
Hi Tom, no they are two different fields, one with Dates and one with DateTimes. "Date field and a DateTime field next to eachother".
EvoluZion3
Obsidian | Level 7

Morning everyone. Thanks for your input. After a bit of faffing around I did manage to find a tactical solution to this.

I took my Import from Excel macro:

 

 

%MACRO IMPORT_EXCEL_PCFILES(FULL_PATH, TAB_NAME, OUTPUT_LOCATION, FIELD_DEFINITIONS, FIELD_FORMATS);

	%PUT ### Call to IMPORT_EXCEL_PCFILES;
	options nomprint nosource2; /* MUST go before any text files with passwords are included! */
	%include '~/uid_pwd.sas' /nosource;

	/*
		FIELD_DEFINITIONS and FIELD_FORMATS are optional. Omitting them trusts SAS to work out the field formats for you, based on Excel metadata.
		You generally only need to provide some FIELD_FORMATS to display DATEs correctly.
		To import a spreadsheet tab put a $ after the TAB_NAME. To import just a named range do not put a $ after the TAB_NAME.

		Example of usage

			%LET FIELDS =	MYSTRING $6
										VARIABLE_NAME $32
										VARIABLE_NUM 8
										BIRTHDAY 8
										EXACTLY_WHEN 8;
			%LET FORMATS = BIRTHDAY DATE9.
										 EXACTLY_WHEN DATETIME19.;
			%IMPORT_EXCEL_PCFILES("\\WindowsServer\My_Metrics.xlsb", "Variables$", WORK.MY_VARIABLES, &FIELDS., &FORMATS.);
	*/

	PROC IMPORT 
		dbms=excelcs
		OUT=WORK.______TMP000000______imp_exc_pcf
		DATAFILE= &FULL_PATH. REPLACE;
		server="our_pcfiles_server";
	  port=1234;
		range=&TAB_NAME.;
	  SERVERUSER=&uname.;
	  SERVERPASS="%sysfunc(dequote(&ad_pwd.))";
	RUN;

	DATA &OUTPUT_LOCATION.;
		LENGTH &FIELD_DEFINITIONS.;
		SET WORK.______TMP000000______imp_exc_pcf;
		FORMAT _all_;
		FORMAT &FIELD_FORMATS.;
	RUN;
	
	%_eg_conditional_dropds(WORK.______TMP000000______imp_exc_pcf);

%MEND;

 

 

 

...and added in code to USE_DATE=NO, iterate through the FIELD_FORMATS variable passed in by the user, and create an UPDATE...SET...x=DATETIME(x) where the date formats are DATE9:

 

 

 

%LET FULL_PATH = '\\WindowsServer\test.xlsx';
%LET TAB_NAME = 'Sheet1$';
%LET OUTPUT_LOCATION = WORK.OUTPUT;
%LET FIELD_DEFINITIONS = NAME $16
                                                                                         MYDATETIME 8
                                                                                         MYDATE 8
                                                                                         MY_ID 8
                                                                                         LAST_TRANX 8
                                                                                         BIRTHDAY 8
                                                                                         ANOTHER_DATE 8;
%LET FIELD_FORMATS =       MYDATETIME DATETIME19.
                                                                           MYDATE DATE9.
                                                                           LAST_TRANX DATETIME19.
                                                                           BIRTHDAY DATE9.
                                                                           ANOTHER_DATE DATE9.;


PROC IMPORT 
       dbms=excelcs
       OUT=WORK.______TMP000000______imp_exc_pcf
       DATAFILE= &FULL_PATH. REPLACE;
       server="our_pcfiles_server";
  port=1234;
       range=&TAB_NAME.;
       USEDATE = NO;
       SERVERUSER=&uname.;
  SERVERPASS="%sysfunc(dequote(&ad_pwd.))";
RUN;

DATA &OUTPUT_LOCATION.;
       LENGTH &FIELD_DEFINITIONS.;
       SET WORK.______TMP000000______imp_exc_pcf;
       FORMAT _all_;
       FORMAT &FIELD_FORMATS.;
RUN;


/* Date vs DateTime problem - SAS can't import an Excel if there's a Date field and a DateTime field (by default it ignores the Time part of a DateTime), so we need to override this using the USEDATE=NO option to import
       everything as a DateTime (which breaks normal Dates by pushing them to the year x million), scan through the field formats in FIELD_FORMATS by the user, identify any Dates, then iterate through the intermediate table
       and apply a DatePart() to correct the Dates. */

/* i) Split FIELD_FORMATS down into a table, allowing us to identify any DATE9 fields */
DATA WORK.______TMP000001______imp_exc_pcf;
   length word $32;
   do until(word=' ');
      count+1;
      word = scan("&FIELD_FORMATS.", count);
      output;
   end;
RUN;

/* ii) The above table has fieldnames and field formats alternately, so tidy this up and create a new temporary table */
PROC SQL;
       CREATE TABLE WORK.______TMP000001______imp_exc_pcf AS
       SELECT
              FIELDS.WORD AS FIELDNAME
       FROM
              (
                     SELECT
                           count - 1 AS ROW_ID
                     FROM
                           WORK.______TMP000001______imp_exc_pcf
                     WHERE
                           word = 'DATE9'
              ) DATE9
              INNER JOIN WORK.______TMP000001______imp_exc_pcf FIELDS
                     ON DATE9.ROW_ID = FIELDS.COUNT;
QUIT;

/* iii) Iterate through the above table and dynamically create a line of SQL which performs an UPDATE and a DATEPART() on the relevant fields */
%MACRO PARSE_AND_DATEPART;
       PROC SQL noprint; SELECT COUNT(*) INTO :import_excel_fields_datepart FROM WORK.______TMP000001______imp_exc_pcf; QUIT;
       %if &import_excel_fields_datepart. > 0 %then %do;
              %LET import_excel_fields_datepart_sql = UPDATE &OUTPUT_LOCATION. SET ;
              %do import_excel_fields_datepart_l = 1 %to &import_excel_fields_datepart.;
                     PROC SQL noprint; SELECT FIELDNAME INTO :import_excel_fields_datepart_f trimmed FROM WORK.______TMP000001______imp_exc_pcf WHERE MONOTONIC() = &import_excel_fields_datepart_l.; QUIT;
                     /*%put &import_excel_fields_datepart_l.: &import_excel_fields_datepart_f.;*/
                     %if &import_excel_fields_datepart_l. < &import_excel_fields_datepart. %then %do; %LET import_excel_fields_datepart_c = ,; %end; %else %do; %LET import_excel_fields_datepart_c =  ;  %end;
                     %LET import_excel_fields_datepart_sql = &import_excel_fields_datepart_sql. &import_excel_fields_datepart_f. = DATEPART(&import_excel_fields_datepart_f.) &import_excel_fields_datepart_c. ;
              %end;
              /*%put &import_excel_fields_datepart_sql.;*/
              PROC SQL; &import_excel_fields_datepart_sql.; QUIT;
       %end;
%MEND;
%PARSE_AND_DATEPART;

 

 

 

 

I know I know, it's horrible, it's not finding the perfect solution, but so far it's working.

 

Patrick
Opal | Level 21

@EvoluZion3 

Just to add a few remarks:

- Excel is not a reliable format for data exchange and you'll have other problems in the future. But I understand that realities sometimes don't give us a choice.

- If you have a reasonable recent SAS version then I'd use the XLSX engine to import Excel files. This engine comes as part of SAS/Access Interface to PC Files. The XLSX files can "live" anywhere to where the SAS Server has access to. It doesn't need to be a mapped Windows file system.

- I understand that you can't convert the Excel to CSV by calling MS Office components in a Linux environment. What could be working though to convert the Excels to Text is Tika. https://tika.apache.org/1.18/formats.html#Microsoft_Office_document_formats 

SAS uses Tika for some of its products so there is a good chance that it's already available in your environment. If not then it's just a .jar file which you simply can copy onto your environment without having admin rights. You just need the right JRE installed - but that's likely available. I've used Tika in past projects and it's a really great tool which you can call out of SAS without any problems (as long as option XCMD is set). The advantage of reading data from text files is that you've got full control how you read the data.

- That you can't read text files doesn't make any sense. That's Foundation SAS (Base SAS) functionality and I've never seen that not working anywhere. If you've got such an issue then I'd strongly suggest you raise a SAS TechSupport ticket so that you get leverage to get this resolved - or guidance what you need to change in your code to make this work.

RW9
Diamond | Level 26 RW9
Diamond | Level 26

That Tika Jar system seems quite interesting and powerful.  Unlike ordinary command line converter programs, which would need command line access, this could theoretically be run just within SAS using the declare javaobject:

http://support.sas.com/documentation/cdl/en/lecompobjref/63327/HTML/default/viewer.htm#n0cdvh1d0v4g5...

Could it not?  I wonder if anyone has tried doing such a thing, I could not find any examples online, and I think it would be useful to see a full working example of something like this.  The documentation on it is also sorely lacking any kind of solid examples:

http://support.sas.com/documentation/cdl/en/lecompobjref/63327/HTML/default/viewer.htm#n0cdvh1d0v4g5...

If I get some time I will have a fiddle around with it myself.

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

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.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 19 replies
  • 2343 views
  • 0 likes
  • 7 in conversation