diff --git a/marshal.go b/marshal.go index f8eba8a..365543a 100644 --- a/marshal.go +++ b/marshal.go @@ -830,7 +830,21 @@ func (d *Decoder) valueFromTree(mtype reflect.Type, tval *Tree, mval1 *reflect.V case reflect.Int32: val, err = strconv.ParseInt(opts.defaultValue, 10, 32) case reflect.Int64: - val, err = strconv.ParseInt(opts.defaultValue, 10, 64) + // Check if the provided number has a non-numeric extension. + var hasExtension bool + if len(opts.defaultValue) > 0 { + lastChar := opts.defaultValue[len(opts.defaultValue)-1] + if lastChar < '0' || lastChar > '9' { + hasExtension = true + } + } + // If the value is a time.Duration with extension, parse as duration. + // If the value is an int64 or a time.Duration without extension, parse as number. + if hasExtension && mvalf.Type().String() == "time.Duration" { + val, err = time.ParseDuration(opts.defaultValue) + } else { + val, err = strconv.ParseInt(opts.defaultValue, 10, 64) + } case reflect.Float32: val, err = strconv.ParseFloat(opts.defaultValue, 32) case reflect.Float64: diff --git a/marshal_test.go b/marshal_test.go index c61955d..f948de4 100644 --- a/marshal_test.go +++ b/marshal_test.go @@ -2286,20 +2286,22 @@ func TestUnmarshalDefault(t *testing.T) { type aliasUint uint var doc struct { - StringField string `default:"a"` - BoolField bool `default:"true"` - UintField uint `default:"1"` - Uint8Field uint8 `default:"8"` - Uint16Field uint16 `default:"16"` - Uint32Field uint32 `default:"32"` - Uint64Field uint64 `default:"64"` - IntField int `default:"-1"` - Int8Field int8 `default:"-8"` - Int16Field int16 `default:"-16"` - Int32Field int32 `default:"-32"` - Int64Field int64 `default:"-64"` - Float32Field float32 `default:"32.1"` - Float64Field float64 `default:"64.1"` + StringField string `default:"a"` + BoolField bool `default:"true"` + UintField uint `default:"1"` + Uint8Field uint8 `default:"8"` + Uint16Field uint16 `default:"16"` + Uint32Field uint32 `default:"32"` + Uint64Field uint64 `default:"64"` + IntField int `default:"-1"` + Int8Field int8 `default:"-8"` + Int16Field int16 `default:"-16"` + Int32Field int32 `default:"-32"` + Int64Field int64 `default:"-64"` + Float32Field float32 `default:"32.1"` + Float64Field float64 `default:"64.1"` + DurationField time.Duration `default:"120ms"` + DurationField2 time.Duration `default:"120000000"` NonEmbeddedStruct struct { StringField string `default:"b"` } @@ -2353,6 +2355,12 @@ func TestUnmarshalDefault(t *testing.T) { if doc.Float64Field != 64.1 { t.Errorf("Float64Field should be 64.1, not %f", doc.Float64Field) } + if doc.DurationField != 120*time.Millisecond { + t.Errorf("DurationField should be 120ms, not %s", doc.DurationField.String()) + } + if doc.DurationField2 != 120*time.Millisecond { + t.Errorf("DurationField2 should be 120000000, not %d", doc.DurationField2) + } if doc.NonEmbeddedStruct.StringField != "b" { t.Errorf("StringField should be \"b\", not %s", doc.NonEmbeddedStruct.StringField) } @@ -2408,6 +2416,17 @@ func TestUnmarshalDefaultFailureFloat64(t *testing.T) { } } +func TestUnmarshalDefaultFailureDuration(t *testing.T) { + var doc struct { + Field time.Duration `default:"blah"` + } + + err := Unmarshal([]byte(``), &doc) + if err == nil { + t.Fatal("should error") + } +} + func TestUnmarshalDefaultFailureUnsupported(t *testing.T) { var doc struct { Field struct{} `default:"blah"`