Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: [PATCH] ztrftime(): Fix truncation for %.



On Mon, Dec 24, 2018 at 03:16:22AM -0600, dana wrote:
> Not directly related, but in reviewing workers/43932 further i found that the
> way ztrftime() handles truncation for %. is problematic:
> 
>   % strftime '%s.%9.' $EPOCHSECONDS $(( 999_999_999 ))
>   1545638724.999999999
>   % strftime '%s.%6.' $EPOCHSECONDS $(( 999_999_000 ))
>   1545638984.999999
>   % strftime '%s.%6.' $EPOCHSECONDS $(( 999_999_999 ))
>   1545638724.100000
> 
> I'm pretty sure it's always been like this, it was just hard to see before
> because there was no way to control the (at the time) microsecond input from
> 'user land'.
> 
> I'm not very good at maths — is there a reason it shouldn't just be a straight
> power-of-ten division like this?
> 
> dana

The reason is because truncation in C just discards the fractional part
of the result. This is not how it works in maths, so If you do it this
way instead of just straight division by 10, the truncation of a number
like 0.999999995 to 8 digits rounds up correctly to 1, whereas he naive
way would just truncate it to 0.99999999:

> hobbes% print -rf '%.9f\n' - 0.999999995
> 0.999999995
> hobbes% print -rf '%.8f\n' - 0.999999995
> 1.00000000
> hobbes% print -rf '%.9f\n' - 0.999999994
> 0.999999994
> hobbes% print -rf '%.8f\n' - 0.999999994
> 0.99999999

Happy snow day!

> diff --git a/Src/utils.c b/Src/utils.c
> index e43a3cdb4..c3badcf77 100644
> --- a/Src/utils.c
> +++ b/Src/utils.c
> @@ -3340,9 +3340,8 @@ morefmt:
>  		    digs = 9;
>  		if (digs < 9) {
>  		    int trunc;
> -		    for (trunc = 8 - digs; trunc; trunc--)
> +		    for (trunc = 9 - digs; trunc; trunc--)
>  			nsec /= 10;
> -		    nsec = (nsec + 8) / 10;
>  		}
>  		sprintf(buf, "%0*ld", digs, nsec);
>  		buf += digs;
> diff --git a/Test/V09datetime.ztst b/Test/V09datetime.ztst
> index 2041d9b40..ed2d99b2f 100644
> --- a/Test/V09datetime.ztst
> +++ b/Test/V09datetime.ztst
> @@ -114,3 +114,15 @@
>  
>    strftime -r '%Y' 2> /dev/null
>  1:-r timestring not optional
> +
> +  for 1 in %. %1. %3. %6. %9. %12.; do
> +    print -rn - "$1 "
> +    strftime "%Y-%m-%d %H:%M:%S.$1" 1012615322 $(( 999_999_999 ))
> +  done
> +0:%. truncation
> +>%. 2002-02-02 02:02:02.999
> +>%1. 2002-02-02 02:02:02.9
> +>%3. 2002-02-02 02:02:02.999
> +>%6. 2002-02-02 02:02:02.999999
> +>%9. 2002-02-02 02:02:02.999999999
> +>%12. 2002-02-02 02:02:02.999999999
> 

-- 
Cheers,
Joey Pabalinas

Attachment: signature.asc
Description: PGP signature



Messages sorted by: Reverse Date, Date, Thread, Author