Does anyone have an explanation why in version 1 in the code below I'm losing precision but things work for version 2?
/* version 1 */
%Let date1= "05JAN2017:09:58:57.822"dt;
%let date2=%sysfunc(sum(&date1,-10),datetime26.3);
%put &=date1;
%put Losing precision: &=date2;
/* version 2 */
%Let date1= 1799229537.822;
%let date2=%sysfunc(sum(&date1,-10),datetime26.3);
%put &=date1;
%put Full precision: &=date2;
Actually - I think that is the pointer to the real problem...
data _null_;
date1a= "05JAN2017:09:58:57.822"dt;
date1b= 1799229537.822;
put date1a=;
put date1b=;
put date1a= best32.;
put date1b= best32.;
put date1a= binary64.;
put date1b= binary64.;
date2a = sum(date1a,-10);
date2b = sum(date1b,-10);
put date2a= binary64.;
put date2b= binary64.;
run;
Somewhere in the macro variable assignment, BEST12. is being used. BEST12. will yield a rounded value to 1 place.
I don't see a way to get SAS to not do that; for example, even this won't listen:
%Let date1= %sysfunc(sum("05JAN2017:09:58:57.862342"dt),best32.);
%put &=date1;
Presumably because the conversion happens immediately seeing the constant and resolving it and bringing it into the macro facility. So you'll have to do a workaround like data _null_ says, or perhaps a bit simpler,
%Let date1= 05JAN2017:09:58:57.822;
%let date2= %sysfunc(inputn(&date1.,datetime,26));
%put &=date2;
(easier if you leave off all the other stuff and just store the date-as-text in date1).
I don't know the answer, but guessing it has to do with the macro processor as you're assigning the values in %LET.
%Let date1= "05JAN2017:09:58:57.822"dt;
%let date1bin = %sysfunc(putn(&date1.,binary64.));
%Let date2= 1799229537.822;
%let date2bin = %sysfunc(putn(&date2.,binary64.));
%put &=date1;
%put &=date1bin;
%put &=date2;
%put &=date2bin;
Yields two different values:
36 %put &=date1; DATE1="05JAN2017:09:58:57.822"dt 37 %put &=date1bin; DATE1BIN=0100000111011010110011111000010000011000011100110011001100110011 38 %put &=date2; DATE2=1799229537.822 39 %put &=date2bin; DATE2BIN=0100000111011010110011111000010000011000011101001001101110100110
Compare to DATA step:
data _null_;
date1a= "05JAN2017:09:58:57.822"dt;
date1b= 1799229537.822;
put date1a= binary64.;
put date1b= binary64.;
date2a = sum(date1a,-10);
date2b = sum(date1b,-10);
put date2a= binary64.;
put date2b= binary64.;
run;
Output (two pairs of identical values, initial values then the sum values):
date1a=0100000111011010110011111000010000011000011101001001101110100110 date1b=0100000111011010110011111000010000011000011101001001101110100110
date2a=0100000111011010110011111000010000010101111101001001101110100110 date2b=0100000111011010110011111000010000010101111101001001101110100110
A good question like this one is worth a thousand answers
Thanks Chris
I get the same result when using the same input.
Computers are not decimal machines.
Decimal to Binary to Decimal is not reversible.
/* version 1 */
%Let date1= 41DACF8418749BA6;
%let date2=%sysfunc(sum(%sysfunc(inputn(41DACF8418749BA6,hex16.)),-10),datetime26.3);
%put &=date1;
%put Loosing precision: &=date2;
/* version 2 */
%Let date1= 41DACF8418749BA6;
%let date2=%sysfunc(sum(%sysfunc(inputn(41DACF8418749BA6,hex16.)),-10),datetime26.3);
%put &=date1;
%put Full precision: &=date2;
LOG
108 /* version 1 */
109 %Let date1= 41DACF8418749BA6;
110 %let date2=%sysfunc(sum(%sysfunc(inputn(41DACF8418749BA6,hex16.)),-10),datetime26.3);
111 %put &=date1;
DATE1=41DACF8418749BA6
112 %put Loosing precision: &=date2;
Loosing precision: DATE2=05JAN2017:09:58:47.822
113 /* version 2 */
114 %Let date1= 41DACF8418749BA6;
115 %let date2=%sysfunc(sum(%sysfunc(inputn(41DACF8418749BA6,hex16.)),-10),datetime26.3);
116 %put &=date1;
DATE1=41DACF8418749BA6
117 %put Full precision: &=date2;
Full precision: DATE2=05JAN2017:09:58:47.822
I don't know the reason but this rather SYSFUNC heavy expression does produce the correct result.
%let date3=%sysfunc(sum(%sysfunc(inputn(%sysfunc(dequote(&date1)),datetime,26)),-10),datetime26.3); NOTE: DATE3=05JAN2017:09:58:47.822
It's in the conversion of the datetime constant I think:
%Let date1= %sysevalf("05JAN2017:09:58:57.822"dt);
That already loses the extra characters. Probably a question for SAS tech support as to why it happens - however the datetime constant is resolved must only take one decimal place for some reason.
Interestingly, it's not truly losing precision: look at this.
%Let date1= %sysevalf("05JAN2017:09:58:57.862342"dt+0);
That rounds up - meaning SAS is doing this on purpose, this isn't a loss of precision situation.
Even more interestingly, I do not get the same results Chris does in the data step - at least, not when I go through CALL SYMPUTX:
data _null_;
call symputx('date1',"05JAN2017:09:58:57.822"dt);
run;
%put &=date1;
Or even:
data _null_;
x = "05JAN2017:09:58:57.822"dt;
put x=;
call symputx('date3',x);
run;
%put &=date3;
Both `x` and `&date3` have the rounded value.
Actually - I think that is the pointer to the real problem...
data _null_;
date1a= "05JAN2017:09:58:57.822"dt;
date1b= 1799229537.822;
put date1a=;
put date1b=;
put date1a= best32.;
put date1b= best32.;
put date1a= binary64.;
put date1b= binary64.;
date2a = sum(date1a,-10);
date2b = sum(date1b,-10);
put date2a= binary64.;
put date2b= binary64.;
run;
Somewhere in the macro variable assignment, BEST12. is being used. BEST12. will yield a rounded value to 1 place.
I don't see a way to get SAS to not do that; for example, even this won't listen:
%Let date1= %sysfunc(sum("05JAN2017:09:58:57.862342"dt),best32.);
%put &=date1;
Presumably because the conversion happens immediately seeing the constant and resolving it and bringing it into the macro facility. So you'll have to do a workaround like data _null_ says, or perhaps a bit simpler,
%Let date1= 05JAN2017:09:58:57.822;
%let date2= %sysfunc(inputn(&date1.,datetime,26));
%put &=date2;
(easier if you leave off all the other stuff and just store the date-as-text in date1).
Thank you all for your valuable input. ...and also thank you @ChrisHemedinger for fixing my spelling.
Even though I have very rarely to use fractional seconds in real life situations and there are multiple ways to code around this implicit rounding, I'm still going to raise a TechSupport track for this one. I'll keep you posted once I've got a "final" answer.
Available on demand!
Missed SAS Innovate Las Vegas? Watch all the action for free! View the keynotes, general sessions and 22 breakouts on demand.
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.