From 3bde1763c2465a3fcac4b06f8db9f041b4d132b2 Mon Sep 17 00:00:00 2001 From: youdie006 Date: Mon, 31 Aug 2026 08:43:04 +0900 Subject: [PATCH] Convert to time.Time before asserting in isNeField The struct branch admits any type convertible to time.Time, but isNeField asserted getValue(...) directly instead of converting first, so a named type with a time.Time underlying panicked. Every other comparison validator converts. --- baked_in.go | 4 ++-- validator_test.go | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/baked_in.go b/baked_in.go index cea97829..dfc26dae 100644 --- a/baked_in.go +++ b/baked_in.go @@ -1070,8 +1070,8 @@ func isNeField(fl FieldLevel) bool { fieldType := field.Type() if fieldType.ConvertibleTo(timeType) && currentField.Type().ConvertibleTo(timeType) { - t := getValue(currentField).(time.Time) - fieldTime := getValue(field).(time.Time) + t := getValue(currentField.Convert(timeType)).(time.Time) + fieldTime := getValue(field.Convert(timeType)).(time.Time) return !fieldTime.Equal(t) } diff --git a/validator_test.go b/validator_test.go index a1d444f2..4f631f44 100644 --- a/validator_test.go +++ b/validator_test.go @@ -1940,6 +1940,26 @@ func TestCrossStructNeFieldValidation(t *testing.T) { Equal(t, errs, nil) } +type namedTime time.Time + +func TestNeFieldNamedTimeValidation(t *testing.T) { + // nefield accepts any type convertible to time.Time, per its own guard. + type Test struct { + Start namedTime + End namedTime `validate:"nefield=Start"` + } + + validate := New() + now := namedTime(time.Now()) + + errs := validate.Struct(Test{Start: now, End: now}) + NotEqual(t, errs, nil) + AssertError(t, errs.(ValidationErrors), "Test.End", "Test.End", "End", "End", "nefield") + + errs = validate.Struct(Test{Start: now, End: namedTime(time.Now().Add(time.Hour))}) + Equal(t, errs, nil) +} + func TestCrossStructEqFieldValidation(t *testing.T) { var errs error validate := New()