Why return string format for FINFO function in SAS EG and SAS DI is different - sas

I am trying to get file "modeified" datetime with
datetimeString = finfo(fid,'Last Modified');``
In SAS EG the return string looks like 12Jan2023:11:03:53
But in SAS DI the return string looks like 12 January 2023 11:03:28
I am trying to convert a string to a datetime like below and obviously it doesn't work for EG and throw invalid argument error.
moddate=input(finfo(fid,'Last Modified'),datetime20.);
I can fix this by writing bit of extra code in DI but would like to know why finfo(fid,'Last Modified'); return different string format?
I am working in data step.

Check the setting of the LOCALE option in the two different SAS sessions.
You can use the NLDATM informat to read the string generated by FINFO()
SAS Documentation on NLDATM informat
Example program that uses NLDATM informat to get datetime from FINFO() function.

Use a different in-format
37 data _null_;
38 x = '12 January 2023 11:03:28';
39 moddate=input(x,datetime20.);
40 moddate2=input(x,anydtdtm30.);
41 put 'NOTE: ' (mod:)(=datetime.);
42 run;
NOTE: Invalid argument to function INPUT at line 39 column 12.
NOTE: moddate=. moddate2=12JAN23:11:03:28

Related

Convert Timestamp to Numeric value in SAS

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;

How to create a datetime macro variable in SAS

%let mydate = "01JUN2021 00:00:00.000"dt;
This does not work. How do I create a datetime macro variable without using proc sql or data step?
The pure macro solution is:
%let mydate = %sysfunc(dhms(%sysfunc(mdy(6,1,2021)), 0, 0, 0));
%put &=mydate; * PRINTS THE UNFORMATTED VALUE STORED;
%put %sysfunc(sum(&mydate), datetime22.); * PRINTS THE DATETIME VALUE FORMATTED;
Output:
MYDATE=1938124800
01JUN2021:00:00:00
You can of course perform the dhms() and mdy() functions on separate lines if that is clearer for you.
Compare this to what your orginal code is doing:
%let mydate="01jan2021:00:00:00"dt;
%put &=mydate;
Prints:
MYDATE="01jan2021:00:00:00"dt
Notice how in your approach the string "01jan2021:00:00:00"dt has been saved into the macro variable, rather than the actual numeric date value 1938124800? Sometimes when you use your approach SAS gets confused when you try to use the value and it is unable to translate the literal to a numeric date value.
try %let mydate = '1Jan2021:0:0:1'dt
Note that it uses single quotes & theres no space between date and time
Your posted macro variable works fine in SAS code.
82 %let mydate = "01JUN2021 00:00:00.000"dt;
83
84 data test;
85 now = datetime();
86 then = &mydate;
87 diff = intck('dtday',then ,now);
88 format now then datetime20. ;
89 put (_all_) (=);
90 run;
now=16JUN2021:08:18:33 then=01JUN2021:00:00:00 diff=15
NOTE: The data set WORK.TEST has 1 observations and 3 variables.
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds
If you need to use the value in pass through SQL code then you will need to set the macro variable to text that the remote database's implementation of SQL will recognize as a datetime value.
So perhaps
%let myts = timestamp '2021-06-01 00:00:00.000';

I want to extract month data from a datetime format column in SAS

I have a data in format 01 Jan 19.00.00 (datetime), and I want to extract the month name only from it.
Tried the below code but getting output in numbers i.e. 1 2 3 and so on. I want the output either in Jan Feb mar format or January February march format.
data want;
set detail;
month = month(datepart(BEGIN_DATE_TIME));
run;
You can use the MONNAME format.
data test;
dt = datetime();
monname = put(datepart(dt),MONNAME.);
put monname=;
run;
If you want "OCT" not "OCTOBER" you can add a 3 to the format (MONNAME3.).
If you are using the value in a report the better approach might be to use a date value formatted with MONNAME.
The values of a date formatted variable will be ordered properly when the variable is used in a CLASS or BY statement. If you had instead computed a new variable as the month name, the default ordering of values would be alphabetical.
data want;
set have;
begin_date = datepart(BEGIN_DATE_TIME);
format begin_date MONNAME3.;
run;

Unable to import .txt file in SAS using proc IMPORT

My program makes a web-service call and receives a response in XML format which I store as output.txt. When opened in notepad, the file looks like this
<OwnerInquiryResponse xmlns="http://www.fedex.com/esotservice/schema"><ResponseHeader><TimeStamp time="2018-02-01T16:09:19.319Z"/></ResponseHeader><Owner><Employee firstName="Gerald" lastName="Harris" emplnbr="108181"/><SalesAttribute type="Sales"/><Territory NodeGlobalRegion="US" SegDesc="Worldwide Sales" SegNbr="1" TTY="2-2-1-2-1-1-10"/></Owner><Delegates/><AlignmentDetail><SalesAttribute type="Sales"/><Alignments/></AlignmentDetail></OwnerInquiryResponse>
I am unable to read this file into SAS using proc IMPORT. My SAS code is below
proc import datafile="/mktg/prc203/abhee/output.txt" out=work.test2 dbms=dlm replace;
delimiter='<>"=';
getnames=yes;
run;
My log is
1 %_eg_hidenotesandsource;
5 %_eg_hidenotesandsource;
28
29 proc import datafile="/mktg/prc203/abhee/output.txt" out=work.test2 dbms=dlm replace;
30 delimiter='<>"=';
31 getnames=yes;
32 run;
NOTE: Unable to open parameter catalog: SASUSER.PARMS.PARMS.SLIST in update mode. Temporary parameter values will be saved to
WORK.PARMS.PARMS.SLIST.
Unable to sample external file, no data in first 5 records.
ERROR: Import unsuccessful. See SAS Log for details.
NOTE: The SAS System stopped processing this step because of errors.
NOTE: PROCEDURE IMPORT used (Total process time):
real time 0.09 seconds
cpu time 0.09 seconds
33
34 %_eg_hidenotesandsource;
46
47
48 %_eg_hidenotesandsource;
51
My ultimate goal is to mine Employee first name (Gerald), last name (Harris) and Employee Number (108181) from the above file and store it in the dataset (and then do this over and over again with a loop and upend the same dataset). If you can help regarding importing the entire file or just the information that I need directly, then that would help.
If you only need these three fields then named input a single input statement is perfectly viable, and arguably preferable to parsing xml with regex:
data want;
infile xmlfile dsd dlm = ' /';
input #"Employee" #"firstName=" firstName :$32. #"lastName=" lastName :$32. #"emplnbr=" emplnbr :8.;
run;
This uses the input file constructed in Richard's answer. The initial #Employee is optional but reduces the risk of picking up any fields with the same names as the desired ones that are subfields of a different top-level field.
Bonus: the same approach can also be used to import json files if you're in a similar situation.
Since you are unable to use the preferred methods of reading xml data, and you are processing a single record result from a service query the git'er done approach seems warranted.
One idea that did not pan out was to use named input.
input #'Employee' lastname= firstname= emplnbr=;
The results could not be made to strip the quotes with $QUOTE. informat nor honor infile dlm=' /'
An approach that did work was to read the single line and parse the value out using a regular expression with capture groups. PRXPARSE is used to compile a pattern, PRXMATCH to test for a match and PRXPOSN to retrieve the capture group.
* create a file to read from (represents the file from the service call capture);
options ls=max;
filename xmlfile "%sysfunc(pathname(WORK))\1-service-call-record.xml";
data have;
input;
file xmlfile;
put _infile_;
datalines;
<OwnerInquiryResponse xmlns="http://www.fedex.com/esotservice/schema"><ResponseHeader><TimeStamp time="2018-02-01T16:09:19.319Z"/></ResponseHeader><Owner><Employee firstName="Gerald" lastName="Harris" emplnbr="108181"/><SalesAttribute type="Sales"/><Territory NodeGlobalRegion="US" SegDesc="Worldwide Sales" SegNbr="1" TTY="2-2-1-2-1-1-10"/></Owner><Delegates/><AlignmentDetail><SalesAttribute type="Sales"/><Alignments/></AlignmentDetail></OwnerInquiryResponse>
run;
* read the entire line from the file and parse out the values using Perl regular expression;
data want;
infile xmlfile;
input;
rx_employee = prxparse('/employee\s+firstname="([^"]+)"\s+lastname="([^"]+)"\s+emplnbr="([^"]+)"/i');
if prxmatch(rx_employee,_infile_) then do;
firstname = prxposn(rx_employee, 1, _infile_);
lastname = prxposn(rx_employee, 2, _infile_);
emplnbr = prxposn(rx_employee, 3, _infile_);
end;
keep firstname last emplnbr;
run;

SAS - adding date format to the macro variable giving strange results

My question is as follows -
I have a code that adds one month to the macro variable and the code works fine:
%let month=1;
%let act_dt = %sysfunc(MDY(&month,1,2016));
%let x_akt=%sysfunc(intnx(MONTH,&act_dt,1),yymmdd10.);
%put current month: &act_dt;
%put plus one month: &x_akt;
giving me the output:
current month: 20454
plus one month: 2016-02-01
But if I add a type of format to the first macro variable, then the function intnx does not work properly.
%let month=1;
%let act_dt = %sysfunc(MDY(&month,1,2016),yymmdd10.);
%let x_akt=%sysfunc(intnx(MONTH,&act_dt,1),yymmdd10.);
%put current month: &act_dt;
%put plus one month: &x_akt;
with the outcome:
current month: 2016-01-01
27 %put plus one month: &x_akt;
plus one month: 1965-08-01
Thank you for any advice, why is it like that and if there is a way how to present both macro variables in the same format.
You can see most of the reason where your first log gives 'current month' as 20454. That's clearly not a human-readable date. In fact, it's SAS's internal representation of the date 1st Jan 2016, represented as the number of days since 1st January 1960.
Your first example works because it passes that numeric value to the INTNX() function, which is what that function needs and expects. Your second example passes the character value '2016-01-01' to the function, which SAS tries to handle by partially converting it to the numeric value 2016, which (taken as a number of days since 1st Jan 1960) is 9th July 1965. The INTNX() function then moves that forward by one month as before.
All SAS date/time function expect to receive numeric input. There is no separate date/time data type in SAS, just numerics with particular date/time formats applied to them. To work in macro variables, your code must either store and manipulate the date values as numbers and then only convert them with a PUT() function for display, or else store them as formatted dates but always convert them back to numeric with a %SYSFUNC(INPUT()) when passing the value to a date/time function.
It's often clearer to do this kind of manipulation in a short DATA _NULL_ step than to have lots of macro code full of %SYSFUNCS().