Repository: fxamacker/cbor (go)

Issue:
bug: decoding CBOR null to time.Time should have no effect
### What version of fxamacker/cbor are you using?

v2.2.0

### Does this issue reproduce with the latest release?

Yes

### What OS and CPU architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/user/.cache/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/user/go"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/go"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build936017716=/tmp/go-build -gno-record-gcc-switches"
</pre></details>

### What did you do?

Decode CBOR null to time.Time.

### What did you expect to see?

Decoding CBOR null to time.Time should be a no-op and return no error according to Unmarshal documentation.

```
To unmarshal CBOR null (0xf6) and undefined (0xf7) values into a slice/map/pointer, Unmarshal sets Go value to nil.  Because null is often used to mean "not present", unmarshalling CBOR null and undefined value into any other Go type has no effect and returns no error.
```

Decoding JSON null to time.Time using encoding/json package is also a no-op.

### What did you see instead?

Decoding CBOR null to time.Time sets value to zero time.

Pull request:
Perform no-op when decoding null to time.Time
Decoding CBOR null (0xf6) and undefined (0xf7) to time.Time has no effect and returns no error.

See Unmarshal documentation.

Closes #254




Patch:
diff --git a/decode.go b/decode.go
index ff4fb95..14367f8 100644
--- a/decode.go
+++ b/decode.go
@@ -588,6 +588,11 @@ func (d *decoder) parseToValue(v reflect.Value, tInfo *typeInfo) error { //nolin
 		case specialTypeTag:
 			return d.parseToTag(v)
 		case specialTypeTime:
+			if d.nextCBORNil() {
+				// Decoding CBOR null and undefined to time.Time is no-op.
+				d.skip()
+				return nil
+			}
 			tm, err := d.parseToTime()
 			if err != nil {
 				return err


Test patch:
diff --git a/decode_test.go b/decode_test.go
index 98b2453..21e7c80 100644
--- a/decode_test.go
+++ b/decode_test.go
@@ -1195,7 +1195,7 @@ func TestUnmarshalNil(t *testing.T) {
 		{"map", map[string]bool{"hello": true, "goodbye": false}, map[string]bool(nil)},
 
 		// Unmarshalling CBOR null to time.Time is a no-op.
-		//{"time.Time", time.Date(2020, time.January, 2, 3, 4, 5, 6, time.UTC), time.Date(2020, time.January, 2, 3, 4, 5, 6, time.UTC)},
+		{"time.Time", time.Date(2020, time.January, 2, 3, 4, 5, 6, time.UTC), time.Date(2020, time.January, 2, 3, 4, 5, 6, time.UTC)},
 
 		// Unmarshalling CBOR null to big.Int is a no-op.
 		{"big.Int", bigIntOrPanic("123"), bigIntOrPanic("123")},
@@ -1795,18 +1795,7 @@ func TestDecodeTime(t *testing.T) {
 		cborUnixTime    []byte
 		wantTime        time.Time
 	}{
-		{
-			name:            "zero time", // decode CBOR null to zero time
-			cborRFC3339Time: hexDecode("f6"),
-			cborUnixTime:    hexDecode("f6"),
-			wantTime:        time.Time{},
-		},
-		{
-			name:            "zero time", // decode CBOR undefined to zero time
-			cborRFC3339Time: hexDecode("f7"),
-			cborUnixTime:    hexDecode("f7"),
-			wantTime:        time.Time{},
-		},
+		// Decoding CBOR null/defined to time.Time is no-op.  See TestUnmarshalNil.
 		{
 			name:            "NaN",
 			cborRFC3339Time: hexDecode("f97e00"),