From 1b1a2a5b4e62a010baed9679e2e2cb885bcf1643 Mon Sep 17 00:00:00 2001 From: AdamMagued Date: Fri, 2 Oct 2026 13:37:25 +0000 Subject: [PATCH] feat: add FormatFloatNoTrailingZero and FormatIntegerNoTrailingZero --- number.go | 44 ++++++++++++++++++++++++++++++++++++++------ number_test.go | 18 ++++++++++++++++++ 2 files changed, 56 insertions(+), 6 deletions(-) diff --git a/number.go b/number.go index f6d1c48..2fbccae 100644 --- a/number.go +++ b/number.go @@ -11,6 +11,7 @@ Source: https://gist.github.com/gorhill/5285193 import ( "math" "strconv" + "strings" ) var ( @@ -64,6 +65,36 @@ var ( // There is also a version for integer number, FormatInteger(), // which is convenient for calls within template. func FormatFloat(format string, n float64) string { + return formatFloat(format, n, false) +} + +// FormatFloatNoTrailingZero produces a formatted number as string based on the user-specified +// criteria, omitting unneeded trailing decimal zeros. +// +// Usage: s := FormatFloatNoTrailingZero(format, n) +// +// Examples of format strings, given n = 12345.6789: +// "#,###.##" => "12,345.68" +// "#.###,######" => "12.345,6789" +// +// See FormatFloat. +func FormatFloatNoTrailingZero(format string, val float64) string { + return formatFloat(format, val, true) +} + +// FormatInteger produces a formatted number as string. +// See FormatFloat. +func FormatInteger(format string, n int) string { + return FormatFloat(format, float64(n)) +} + +// FormatIntegerNoTrailingZero produces a formatted number as string without trailing zeros. +// See FormatFloatNoTrailingZero. +func FormatIntegerNoTrailingZero(format string, n int) string { + return FormatFloatNoTrailingZero(format, float64(n)) +} + +func formatFloat(format string, n float64, trimTrailingZeros bool) string { // Special cases: // NaN = "NaN" // +Inf = "+Infinity" @@ -183,11 +214,12 @@ func FormatFloat(format string, n float64) string { fracStr = "000000000000000"[:precision-len(fracStr)] + fracStr } - return signStr + intStr + decimalStr + fracStr -} + if trimTrailingZeros { + fracStr = strings.TrimRight(fracStr, "0") + if len(fracStr) == 0 { + return signStr + intStr + } + } -// FormatInteger produces a formatted number as string. -// See FormatFloat. -func FormatInteger(format string, n int) string { - return FormatFloat(format, float64(n)) + return signStr + intStr + decimalStr + fracStr } diff --git a/number_test.go b/number_test.go index 7111744..ed070c2 100644 --- a/number_test.go +++ b/number_test.go @@ -54,6 +54,24 @@ func TestFormatFloat(t *testing.T) { t.Errorf("On %v (%v, %v), got %v, wanted %v", "integerTest", "#", 12345, got, "12345.000000000") } + + // Test FormatFloatNoTrailingZero and FormatIntegerNoTrailingZero + noTrailingTests := []TestStruct{ + {"no trailing zero with decimals", "#,###.##", 12345.6, "12,345.6"}, + {"no trailing zero whole number", "#,###.##", 12345.0, "12,345"}, + {"no trailing zero retains significant digits", "#,###.##", 12345.68, "12,345.68"}, + {"no trailing zero multiple fractional zeros", "#.###,######", 12345.6789, "12.345,6789"}, + } + for _, test := range noTrailingTests { + got := FormatFloatNoTrailingZero(test.format, test.num) + if got != test.formatted { + t.Errorf("On %v (%v, %v), got %v, wanted %v", + test.name, test.format, test.num, got, test.formatted) + } + } + if gotInt := FormatIntegerNoTrailingZero("#", 12345); gotInt != "12345" { + t.Errorf("FormatIntegerNoTrailingZero got %v, wanted %v", gotInt, "12345") + } // Test the things that could panic panictests := []TestStruct{ {"FormatFloat(): invalid positive sign directive", "-", 12345.6789, "12,345.68"},