encoding/jsonpb: fix encoding of max/min Duration and max Timestamp

Bad off-by-one error:(

Change-Id: I47dfaa8529fcdb2d53a4fc67c1f046d2152fe8fe
Reviewed-on: https://go-review.googlesource.com/c/protobuf/+/173837
Reviewed-by: Joe Tsai <thebrokentoaster@gmail.com>
diff --git a/encoding/jsonpb/decode_test.go b/encoding/jsonpb/decode_test.go
index cb99bcd..9fb95d6 100644
--- a/encoding/jsonpb/decode_test.go
+++ b/encoding/jsonpb/decode_test.go
@@ -1823,6 +1823,16 @@
 		inputText:    `"0.5s"`,
 		wantMessage:  &knownpb.Duration{Nanos: 5e8},
 	}, {
+		desc:         "Duration max value",
+		inputMessage: &knownpb.Duration{},
+		inputText:    `"315576000000.999999999s"`,
+		wantMessage:  &knownpb.Duration{Seconds: 315576000000, Nanos: 999999999},
+	}, {
+		desc:         "Duration min value",
+		inputMessage: &knownpb.Duration{},
+		inputText:    `"-315576000000.999999999s"`,
+		wantMessage:  &knownpb.Duration{Seconds: -315576000000, Nanos: -999999999},
+	}, {
 		desc:         "Duration with +secs out of range",
 		inputMessage: &knownpb.Duration{},
 		inputText:    `"315576000001s"`,
@@ -1883,22 +1893,22 @@
 		inputText:    `"2019-03-19T23:03:21.000000001Z"`,
 		wantMessage:  &knownpb.Timestamp{Seconds: 1553036601, Nanos: 1},
 	}, {
-		desc:         "Timestamp upper limit",
+		desc:         "Timestamp max value",
 		inputMessage: &knownpb.Timestamp{},
 		inputText:    `"9999-12-31T23:59:59.999999999Z"`,
 		wantMessage:  &knownpb.Timestamp{Seconds: 253402300799, Nanos: 999999999},
 	}, {
-		desc:         "Timestamp above upper limit",
+		desc:         "Timestamp above max value",
 		inputMessage: &knownpb.Timestamp{},
 		inputText:    `"9999-12-31T23:59:59-01:00"`,
 		wantErr:      true,
 	}, {
-		desc:         "Timestamp lower limit",
+		desc:         "Timestamp min value",
 		inputMessage: &knownpb.Timestamp{},
 		inputText:    `"0001-01-01T00:00:00Z"`,
 		wantMessage:  &knownpb.Timestamp{Seconds: -62135596800},
 	}, {
-		desc:         "Timestamp below lower limit",
+		desc:         "Timestamp below min value",
 		inputMessage: &knownpb.Timestamp{},
 		inputText:    `"0001-01-01T00:00:00+01:00"`,
 		wantErr:      true,
diff --git a/encoding/jsonpb/encode_test.go b/encoding/jsonpb/encode_test.go
index 0c12861..b0e3973 100644
--- a/encoding/jsonpb/encode_test.go
+++ b/encoding/jsonpb/encode_test.go
@@ -1422,6 +1422,14 @@
 		input: &knownpb.Duration{Seconds: -123, Nanos: -450},
 		want:  `"-123.000000450s"`,
 	}, {
+		desc:  "Duration max value",
+		input: &knownpb.Duration{Seconds: 315576000000, Nanos: 999999999},
+		want:  `"315576000000.999999999s"`,
+	}, {
+		desc:  "Duration min value",
+		input: &knownpb.Duration{Seconds: -315576000000, Nanos: -999999999},
+		want:  `"-315576000000.999999999s"`,
+	}, {
 		desc:    "Duration with +secs -nanos",
 		input:   &knownpb.Duration{Seconds: 1, Nanos: -1},
 		wantErr: true,
@@ -1466,6 +1474,14 @@
 		input: &knownpb.Timestamp{Nanos: 1e7},
 		want:  `"1970-01-01T00:00:00.010Z"`,
 	}, {
+		desc:  "Timestamp max value",
+		input: &knownpb.Timestamp{Seconds: 253402300799, Nanos: 999999999},
+		want:  `"9999-12-31T23:59:59.999999999Z"`,
+	}, {
+		desc:  "Timestamp min value",
+		input: &knownpb.Timestamp{Seconds: -62135596800},
+		want:  `"0001-01-01T00:00:00Z"`,
+	}, {
 		desc:    "Timestamp with +secs out of range",
 		input:   &knownpb.Timestamp{Seconds: 253402300800},
 		wantErr: true,
diff --git a/encoding/jsonpb/well_known_types.go b/encoding/jsonpb/well_known_types.go
index 512adc2..19c8230 100644
--- a/encoding/jsonpb/well_known_types.go
+++ b/encoding/jsonpb/well_known_types.go
@@ -644,10 +644,10 @@
 	secs := secsVal.Int()
 	nanos := nanosVal.Int()
 	if secs < -maxSecondsInDuration || secs > maxSecondsInDuration {
-		return errors.New("%s: seconds out of range", msgType.FullName())
+		return errors.New("%s: seconds out of range %v", msgType.FullName(), secs)
 	}
-	if nanos <= -secondsInNanos || nanos >= secondsInNanos {
-		return errors.New("%s: nanos out of range", msgType.FullName())
+	if nanos < -secondsInNanos || nanos > secondsInNanos {
+		return errors.New("%s: nanos out of range %v", msgType.FullName(), nanos)
 	}
 	if (secs > 0 && nanos < 0) || (secs < 0 && nanos > 0) {
 		return errors.New("%s: signs of seconds and nanos do not match", msgType.FullName())
@@ -834,10 +834,10 @@
 	secs := secsVal.Int()
 	nanos := nanosVal.Int()
 	if secs < minTimestampSeconds || secs > maxTimestampSeconds {
-		return errors.New("%s: seconds out of range %q", msgType.FullName(), secs)
+		return errors.New("%s: seconds out of range %v", msgType.FullName(), secs)
 	}
-	if nanos < 0 || nanos >= secondsInNanos {
-		return errors.New("%s: nanos out of range %q", msgType.FullName(), nanos)
+	if nanos < 0 || nanos > secondsInNanos {
+		return errors.New("%s: nanos out of range %v", msgType.FullName(), nanos)
 	}
 	// Uses RFC 3339, where generated output will be Z-normalized and uses 0, 3,
 	// 6 or 9 fractional digits.