internal/msgfmt: fix formatting of negative Duration

If the seconds is zero, but the nanoseconds are negative,
there should still be a leading negative sign.

Change-Id: Ia72a26bc3455a80e572b6bf2ff41395381f811c7
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/247457
Reviewed-by: Herbie Ong <herbie@google.com>
Reviewed-by: Damien Neil <dneil@google.com>
diff --git a/internal/msgfmt/format.go b/internal/msgfmt/format.go
index a8a8031..6561b8b 100644
--- a/internal/msgfmt/format.go
+++ b/internal/msgfmt/format.go
@@ -10,7 +10,6 @@
 import (
 	"bytes"
 	"fmt"
-	"math"
 	"reflect"
 	"sort"
 	"strconv"
@@ -130,12 +129,16 @@
 		return append(b, x+"Z"...)
 
 	case genid.Duration_message_fullname:
+		sign := ""
 		secs := m.Get(fds.ByNumber(genid.Duration_Seconds_field_number)).Int()
 		nanos := m.Get(fds.ByNumber(genid.Duration_Nanos_field_number)).Int()
 		if nanos <= -1e9 || nanos >= 1e9 || (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0) {
 			return nil
 		}
-		x := fmt.Sprintf("%d.%09d", secs, int64(math.Abs(float64(nanos))))
+		if secs < 0 || nanos < 0 {
+			sign, secs, nanos = "-", -1*secs, -1*nanos
+		}
+		x := fmt.Sprintf("%s%d.%09d", sign, secs, nanos)
 		x = strings.TrimSuffix(x, "000")
 		x = strings.TrimSuffix(x, "000")
 		x = strings.TrimSuffix(x, ".000")
diff --git a/internal/msgfmt/format_test.go b/internal/msgfmt/format_test.go
index 6136d0e..6ba0768 100644
--- a/internal/msgfmt/format_test.go
+++ b/internal/msgfmt/format_test.go
@@ -201,6 +201,11 @@
 		want: `{opt_duration:-1257894123.000456789s}`,
 	}, {
 		in: &textpb.KnownTypes{
+			OptDuration: &durpb.Duration{Seconds: 0, Nanos: -1},
+		},
+		want: `{opt_duration:-0.000000001s}`,
+	}, {
+		in: &textpb.KnownTypes{
 			OptBool:   &wpb.BoolValue{},
 			OptInt32:  &wpb.Int32Value{},
 			OptInt64:  &wpb.Int64Value{},