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