Apply gci import order changes

This commit is contained in:
github-actions[bot]
2025-09-16 15:30:57 +00:00
parent 1e01e30561
commit a7e9cdb28a
5 changed files with 215 additions and 215 deletions

View File

@ -21,11 +21,11 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
gtimeVal := gtime.NewFromTime(utcTime)
gtimePtr := gtimeVal
gtimeValue := *gtimeVal
// Set different local timezone for more realistic testing
shanghaiLocation, _ := time.LoadLocation("Asia/Shanghai")
time.Local = shanghaiLocation
// Benchmark 1: Direct type conversions (should be fastest)
b.Run("DirectGTimeToTime", func(b *testing.B) {
b.ResetTimer()
@ -33,21 +33,21 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.Time(gtimePtr)
}
})
b.Run("DirectGTimeValueToTime", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = gconv.Time(gtimeValue)
}
})
b.Run("DirectGTimeToGTime", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = gconv.GTime(gtimePtr)
}
})
// Benchmark 2: Builtin converter scenarios
b.Run("BuiltinGTimeStruct", func(b *testing.B) {
b.ResetTimer()
@ -56,7 +56,7 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.Struct(gtimePtr, &result)
}
})
b.Run("BuiltinGTimePtrStruct", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
@ -64,7 +64,7 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.Struct(gtimePtr, &result)
}
})
b.Run("BuiltinGTimeValueStruct", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
@ -72,7 +72,7 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.Struct(gtimeValue, &result)
}
})
// Benchmark 3: String conversion scenarios
b.Run("GTimeToString", func(b *testing.B) {
b.ResetTimer()
@ -80,14 +80,14 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.String(gtimePtr)
}
})
b.Run("GTimeValueToString", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = gconv.String(gtimeValue)
}
})
b.Run("StringToGTime", func(b *testing.B) {
timeStr := "2025-09-16T11:32:42.878465Z"
b.ResetTimer()
@ -95,7 +95,7 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.GTime(timeStr)
}
})
// Benchmark 4: Map conversion scenarios (problematic in original issue)
b.Run("MapToTime", func(b *testing.B) {
mapData := map[string]interface{}{"time": gtimePtr}
@ -104,7 +104,7 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.Time(mapData)
}
})
b.Run("MapToGTime", func(b *testing.B) {
mapData := map[string]interface{}{"time": gtimePtr}
b.ResetTimer()
@ -112,7 +112,7 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.GTime(mapData)
}
})
// Benchmark 5: Struct field conversion scenarios
b.Run("StructFieldConversion", func(b *testing.B) {
type TestStruct struct {
@ -125,7 +125,7 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.Struct(mapData, &result)
}
})
b.Run("StructGTimeFieldConversion", func(b *testing.B) {
type TestStruct struct {
Time gtime.Time `json:"time"`
@ -137,7 +137,7 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.Struct(mapData, &result)
}
})
// Benchmark 6: Slice conversion scenarios (the main issue scenario)
b.Run("SliceConversionToTime", func(b *testing.B) {
sliceData := []map[string]interface{}{{"time": gtimePtr}}
@ -147,7 +147,7 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.Structs(sliceData, &result)
}
})
b.Run("SliceConversionToGTime", func(b *testing.B) {
sliceData := []map[string]interface{}{{"time": gtimePtr}}
b.ResetTimer()
@ -156,7 +156,7 @@ func BenchmarkGTimeConverter_ComprehensiveScenarios(b *testing.B) {
_ = gconv.Structs(sliceData, &result)
}
})
b.Run("SliceConversionToGTimePtr", func(b *testing.B) {
sliceData := []map[string]interface{}{{"time": gtimePtr}}
b.ResetTimer()
@ -180,27 +180,27 @@ func BenchmarkGTimeConverter_TimezoneImpact(b *testing.B) {
{"London", mustLoadLocation("Europe/London")},
{"Tokyo", mustLoadLocation("Asia/Tokyo")},
}
baseTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
for _, tz := range timezones {
testTime := baseTime.In(tz.loc)
gtimeVal := gtime.NewFromTime(testTime)
b.Run("DirectConversion_"+tz.name, func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = gconv.Time(gtimeVal)
}
})
b.Run("StringConversion_"+tz.name, func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = gconv.String(gtimeVal)
}
})
b.Run("StructsConversion_"+tz.name, func(b *testing.B) {
sliceData := []map[string]interface{}{{"time": gtimeVal}}
b.ResetTimer()
@ -224,20 +224,20 @@ func BenchmarkGTimeConverter_PrecisionImpact(b *testing.B) {
{"Microseconds", 123456000},
{"Nanoseconds", 123456789},
}
baseTime := time.Date(2025, 9, 16, 11, 32, 42, 0, time.UTC)
for _, p := range precisions {
testTime := baseTime.Add(time.Duration(p.nanos))
gtimeVal := gtime.NewFromTime(testTime)
b.Run("Conversion_"+p.name, func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = gconv.Time(gtimeVal)
}
})
b.Run("StringRoundTrip_"+p.name, func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
@ -245,10 +245,10 @@ func BenchmarkGTimeConverter_PrecisionImpact(b *testing.B) {
_ = gconv.GTime(str)
}
})
b.Run("StructsConversion_"+p.name, func(b *testing.B) {
sliceData := []map[string]interface{}{{"time": gtimeVal}}
b.ResetTimer()
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result []time.Time
_ = gconv.Structs(sliceData, &result)
@ -261,7 +261,7 @@ func BenchmarkGTimeConverter_PrecisionImpact(b *testing.B) {
func BenchmarkGTimeConverter_MemoryAllocation(b *testing.B) {
utcTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
gtimeVal := gtime.NewFromTime(utcTime)
// Benchmark memory allocation for different conversion types
b.Run("DirectConversion_Allocs", func(b *testing.B) {
b.ReportAllocs()
@ -270,7 +270,7 @@ func BenchmarkGTimeConverter_MemoryAllocation(b *testing.B) {
_ = gconv.Time(gtimeVal)
}
})
b.Run("BuiltinConverter_Allocs", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
@ -279,7 +279,7 @@ func BenchmarkGTimeConverter_MemoryAllocation(b *testing.B) {
_ = gconv.Struct(gtimeVal, &result)
}
})
b.Run("StringConversion_Allocs", func(b *testing.B) {
b.ReportAllocs()
b.ResetTimer()
@ -287,7 +287,7 @@ func BenchmarkGTimeConverter_MemoryAllocation(b *testing.B) {
_ = gconv.String(gtimeVal)
}
})
b.Run("SliceConversion_Allocs", func(b *testing.B) {
sliceData := []map[string]interface{}{{"time": gtimeVal}}
b.ReportAllocs()
@ -304,7 +304,7 @@ func BenchmarkGTimeConverter_ComparisonWithStandard(b *testing.B) {
utcTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
gtimeVal := gtime.NewFromTime(utcTime)
timeStr := "2025-09-16T11:32:42.878465Z"
// Compare gconv performance with standard library operations
b.Run("GConv_TimeConversion", func(b *testing.B) {
b.ResetTimer()
@ -312,28 +312,28 @@ func BenchmarkGTimeConverter_ComparisonWithStandard(b *testing.B) {
_ = gconv.Time(gtimeVal)
}
})
b.Run("Standard_TimeParsing", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _ = time.Parse(time.RFC3339, timeStr)
}
})
b.Run("GConv_StringConversion", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = gconv.String(gtimeVal)
}
})
b.Run("Standard_TimeFormatting", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = utcTime.Format(time.RFC3339)
}
})
b.Run("GConv_StructConversion", func(b *testing.B) {
type TimeStruct struct {
Time time.Time `json:"time"`
@ -354,4 +354,4 @@ func mustLoadLocation(name string) *time.Location {
panic(err)
}
return loc
}
}

View File

@ -23,21 +23,21 @@ func TestBuiltinGTimeConverter_Issue4429(t *testing.T) {
defer func() {
time.Local = originalLocation
}()
// Simulate the issue environment: local timezone is Asia/Shanghai (+8)
shanghaiLocation, _ := time.LoadLocation("Asia/Shanghai")
time.Local = shanghaiLocation
// Test data that matches the exact issue scenario
// Database returns UTC time with microseconds
utcTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
gtimeVal := gtime.NewFromTime(utcTime)
originalName, originalOffset := gtimeVal.Zone()
t.Logf("Original gtimeVal: %s (zone: %s, offset: %d)",
t.Logf("Original gtimeVal: %s (zone: %s, offset: %d)",
gtimeVal.Time, originalName, originalOffset/3600)
t.Assert(originalOffset, 0) // Should be UTC (offset 0)
// Test the exact scenario from the issue: result.Structs(&nowResult)
// This simulates the ORM query result conversion
result := []map[string]interface{}{{"now": gtimeVal}}
@ -45,23 +45,23 @@ func TestBuiltinGTimeConverter_Issue4429(t *testing.T) {
err := gconv.Structs(result, &nowResult)
t.AssertNil(err)
t.Assert(len(nowResult), 1)
structsTime := nowResult[0]
structsName, structsOffset := structsTime.Zone()
t.Logf("Structs result: %s (zone: %s, offset: %d)",
t.Logf("Structs result: %s (zone: %s, offset: %d)",
structsTime, structsName, structsOffset/3600)
// The critical assertions that fix issue #4429
t.Assert(structsOffset, 0)
t.Assert(gtimeVal.Time.Equal(structsTime), true)
t.Assert(structsTime.Nanosecond(), utcTime.Nanosecond())
// Verify the issue is fixed: result should be +0000, not +0800
expectedUTCFormat := "2025-09-16 11:32:42.878465 +0000 UTC"
actualFormat := structsTime.String()
t.Assert(actualFormat, expectedUTCFormat)
t.Logf("✅ Issue #4429 FIXED: Original +0000 preserved (not converted to +0800)")
})
}
@ -74,71 +74,71 @@ func TestBuiltinGTimeConverter_DirectAssignment(t *testing.T) {
defer func() {
time.Local = originalLocation
}()
// Set different local timezone to test independence
parisLocation, _ := time.LoadLocation("Europe/Paris")
time.Local = parisLocation
// Test Case 1: gtime.Time to gtime.Time (value to value)
t.Logf("=== Test Case 1: gtime.Time to gtime.Time ===")
utcTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
sourceGTime := *gtime.NewFromTime(utcTime)
var targetGTime gtime.Time
err := gconv.Struct(sourceGTime, &targetGTime)
t.AssertNil(err)
// Verify direct assignment preserved everything
t.Assert(targetGTime.Equal(&sourceGTime), true)
t.Assert(targetGTime.Location().String(), sourceGTime.Location().String())
t.Assert(targetGTime.Nanosecond(), sourceGTime.Nanosecond())
_, sourceOffset := sourceGTime.Zone()
_, targetOffset := targetGTime.Zone()
t.Assert(targetOffset, sourceOffset)
t.Logf("Source: %s, Target: %s - ✅ DIRECT ASSIGNMENT", sourceGTime.Time, targetGTime.Time)
// Test Case 2: *gtime.Time to *gtime.Time (pointer to pointer)
t.Logf("=== Test Case 2: *gtime.Time to *gtime.Time ===")
sourcePtr := gtime.NewFromTime(utcTime)
var targetPtr *gtime.Time
err = gconv.Struct(sourcePtr, &targetPtr)
t.AssertNil(err)
t.AssertNE(targetPtr, nil)
// Verify pointer assignment
t.Assert(targetPtr.Equal(sourcePtr), true)
t.Assert(targetPtr.Location().String(), sourcePtr.Location().String())
t.Logf("Source Ptr: %s, Target Ptr: %s - ✅ DIRECT ASSIGNMENT", sourcePtr.Time, targetPtr.Time)
// Test Case 3: gtime.Time to *gtime.Time (value to pointer)
t.Logf("=== Test Case 3: gtime.Time to *gtime.Time ===")
var targetFromValue *gtime.Time
err = gconv.Struct(sourceGTime, &targetFromValue)
t.AssertNil(err)
t.AssertNE(targetFromValue, nil)
t.Assert(targetFromValue.Equal(&sourceGTime), true)
t.Assert(targetFromValue.Location().String(), sourceGTime.Location().String())
t.Logf("Source Value: %s, Target Ptr: %s - ✅ DIRECT ASSIGNMENT", sourceGTime.Time, targetFromValue.Time)
// Test Case 4: *gtime.Time to gtime.Time (pointer to value)
t.Logf("=== Test Case 4: *gtime.Time to gtime.Time ===")
var targetFromPtr gtime.Time
err = gconv.Struct(sourcePtr, &targetFromPtr)
t.AssertNil(err)
t.Assert(targetFromPtr.Equal(sourcePtr), true)
t.Assert(targetFromPtr.Location().String(), sourcePtr.Location().String())
t.Logf("Source Ptr: %s, Target Value: %s - ✅ DIRECT ASSIGNMENT", sourcePtr.Time, targetFromPtr.Time)
})
}
@ -147,40 +147,40 @@ func TestBuiltinGTimeConverter_DirectAssignment(t *testing.T) {
func TestBuiltinGTimeConverter_FallbackPaths(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
// Test scenarios where builtin converter falls back to general conversion
// Test 1: String to gtime.Time (should use general conversion)
t.Logf("=== Test 1: String to gtime.Time fallback ===")
timeStr := "2025-09-16T11:32:42Z"
var gtimeFromStr gtime.Time
err := gconv.Struct(timeStr, &gtimeFromStr)
t.AssertNil(err)
// Should still preserve timezone from RFC3339 format
_, offset := gtimeFromStr.Zone()
t.Assert(offset, 0) // UTC offset from Z suffix
t.Logf("String '%s' converted to gtime: %s - ✅ TIMEZONE PRESERVED", timeStr, gtimeFromStr.Time)
// Test 2: Integer timestamp to gtime.Time
t.Logf("=== Test 2: Integer timestamp to gtime.Time fallback ===")
timestamp := int64(1726488762) // Unix timestamp
var gtimeFromInt gtime.Time
err = gconv.Struct(timestamp, &gtimeFromInt)
t.AssertNil(err)
expectedTime := time.Unix(timestamp, 0).UTC()
t.Assert(gtimeFromInt.Unix(), expectedTime.Unix())
t.Logf("Timestamp %d converted to gtime: %s - ✅ CONVERSION SUCCESS", timestamp, gtimeFromInt.Time)
// Test 3: time.Time to gtime.Time (should use general conversion)
t.Logf("=== Test 3: time.Time to gtime.Time fallback ===")
goTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
var gtimeFromGoTime gtime.Time
err = gconv.Struct(goTime, &gtimeFromGoTime)
t.AssertNil(err)
t.Assert(gtimeFromGoTime.Time.Equal(goTime), true)
_, gtimeOffset := gtimeFromGoTime.Zone()
_, goTimeOffset := goTime.Zone()
@ -194,27 +194,27 @@ func TestBuiltinGTimeConverter_NilAndZeroHandling(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
// Test 1: Nil *gtime.Time to gtime.Time
t.Logf("=== Test 1: Nil *gtime.Time to gtime.Time ===")
var nilGTime *gtime.Time = nil
var resultGTime gtime.Time
err := gconv.Struct(nilGTime, &resultGTime)
t.AssertNil(err)
t.Assert(resultGTime.IsZero(), true)
t.Logf("Nil gtime converted to zero gtime: %s", resultGTime.Time)
// Test 2: Nil *gtime.Time to *gtime.Time
t.Logf("=== Test 2: Nil *gtime.Time to *gtime.Time ===")
var resultPtr *gtime.Time
err = gconv.Struct(nilGTime, &resultPtr)
t.AssertNil(err)
t.AssertNE(resultPtr, nil) // Should create new gtime.Time, not remain nil
t.Assert(resultPtr.IsZero(), true)
t.Logf("Nil gtime converted to zero gtime pointer: %s", resultPtr.Time)
// Test 3: Zero gtime.Time to gtime.Time
t.Logf("=== Test 3: Zero gtime.Time to gtime.Time ===")
zeroGTime := gtime.Time{}
var resultZero gtime.Time
err = gconv.Struct(zeroGTime, &resultZero)
@ -222,29 +222,29 @@ func TestBuiltinGTimeConverter_NilAndZeroHandling(t *testing.T) {
t.Assert(resultZero.IsZero(), true)
t.Assert(resultZero.Equal(&zeroGTime), true)
t.Logf("Zero gtime preserved: %s", resultZero.Time)
// Test 4: Zero gtime.Time in struct
t.Logf("=== Test 4: Zero gtime.Time in struct ===")
type TestStruct struct {
ZeroTime gtime.Time `json:"zero_time"`
NilTime *gtime.Time `json:"nil_time"`
}
inputData := map[string]interface{}{
"zero_time": gtime.Time{},
"nil_time": (*gtime.Time)(nil),
}
var resultStruct TestStruct
err = gconv.Struct(inputData, &resultStruct)
t.AssertNil(err)
t.Assert(resultStruct.ZeroTime.IsZero(), true)
t.AssertNE(resultStruct.NilTime, nil)
t.Assert(resultStruct.NilTime.IsZero(), true)
t.Logf("Struct with zero/nil times: ZeroTime=%s, NilTime=%s",
t.Logf("Struct with zero/nil times: ZeroTime=%s, NilTime=%s",
resultStruct.ZeroTime.Time, resultStruct.NilTime.Time)
})
}
}

View File

@ -23,22 +23,22 @@ func TestBuiltinGTimeConverter(t *testing.T) {
defer func() {
time.Local = originalLocation
}()
shanghaiLocation, _ := time.LoadLocation("Asia/Shanghai")
time.Local = shanghaiLocation
// Test data with various timezones
utcTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
gtimeUTC := gtime.NewFromTime(utcTime)
gmtLocation, _ := time.LoadLocation("GMT")
gmtTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, gmtLocation)
gtimeGMT := gtime.NewFromTime(gmtTime)
estLocation, _ := time.LoadLocation("America/New_York")
estTime := time.Date(2025, 9, 16, 7, 32, 42, 878465000, estLocation)
gtimeEST := gtime.NewFromTime(estTime)
// Test 1: Direct gtime.Time to gtime.Time conversion
t.Logf("=== Test 1: Direct gtime.Time to gtime.Time conversion ===")
var result1 gtime.Time
@ -47,7 +47,7 @@ func TestBuiltinGTimeConverter(t *testing.T) {
t.Assert(result1.Location().String(), gtimeUTC.Location().String())
t.Assert(result1.Equal(gtimeUTC), true)
t.Logf("Original: %s, Result: %s", gtimeUTC.Time, result1.Time)
// Test 2: *gtime.Time to *gtime.Time conversion
t.Logf("=== Test 2: *gtime.Time to *gtime.Time conversion ===")
var result2 *gtime.Time
@ -57,7 +57,7 @@ func TestBuiltinGTimeConverter(t *testing.T) {
t.Assert(result2.Location().String(), gtimeUTC.Location().String())
t.Assert(result2.Equal(gtimeUTC), true)
t.Logf("Original: %s, Result: %s", gtimeUTC.Time, result2.Time)
// Test 3: gtime.Time to *gtime.Time conversion
t.Logf("=== Test 3: gtime.Time to *gtime.Time conversion ===")
var result3 *gtime.Time
@ -67,7 +67,7 @@ func TestBuiltinGTimeConverter(t *testing.T) {
t.Assert(result3.Location().String(), gtimeUTC.Location().String())
t.Assert(result3.Equal(gtimeUTC), true)
t.Logf("Original: %s, Result: %s", gtimeUTC.Time, result3.Time)
// Test 4: Multiple timezone preservation
testCases := []struct {
name string
@ -78,19 +78,19 @@ func TestBuiltinGTimeConverter(t *testing.T) {
{"GMT", gtimeGMT, 0},
{"EST", gtimeEST, -4 * 3600}, // EST is UTC-4 in September
}
for _, tc := range testCases {
t.Logf("=== Test 4.%s: %s timezone preservation ===", tc.name, tc.name)
var result gtime.Time
err := gconv.Struct(tc.input, &result)
t.AssertNil(err)
_, inputOffset := tc.input.Zone()
_, resultOffset := result.Zone()
t.Assert(resultOffset, inputOffset)
t.Assert(result.Equal(tc.input), true)
t.Logf("%s - Original: %s (offset: %d), Result: %s (offset: %d)",
t.Logf("%s - Original: %s (offset: %d), Result: %s (offset: %d)",
tc.name, tc.input.Time, inputOffset, result.Time, resultOffset)
}
})
@ -103,7 +103,7 @@ func TestBuiltinGTimeConverter_EdgeCases(t *testing.T) {
// The test case `gconv.Struct(nil, &result)` creates edge cases with unaddressable values
// Core functionality is tested in other test cases
t.Logf("=== Test 1: Nil *gtime.Time conversion - SKIPPED ===")
// Test 2: Zero gtime.Time conversion
t.Logf("=== Test 2: Zero gtime.Time conversion ===")
zeroGtime := gtime.Time{}
@ -112,28 +112,28 @@ func TestBuiltinGTimeConverter_EdgeCases(t *testing.T) {
t.AssertNil(err)
t.Assert(result2.IsZero(), true)
t.Logf("Zero gtime preserved: %s", result2.Time)
// Test 3: Conversion with microsecond precision
t.Logf("=== Test 3: Microsecond precision preservation ===")
preciseTime := time.Date(2025, 9, 16, 11, 32, 42, 123456789, time.UTC)
gtimePrecise := gtime.NewFromTime(preciseTime)
var result3 gtime.Time
err = gconv.Struct(gtimePrecise, &result3)
t.AssertNil(err)
t.Assert(result3.Nanosecond(), preciseTime.Nanosecond())
t.Assert(result3.Equal(gtimePrecise), true)
t.Logf("Precision preserved - Original: %s, Result: %s", gtimePrecise.Time, result3.Time)
// Test 4: Conversion with different date components
t.Logf("=== Test 4: Date component preservation ===")
complexTime := time.Date(2025, 12, 31, 23, 59, 59, 999999999, time.UTC)
gtimeComplex := gtime.NewFromTime(complexTime)
var result4 gtime.Time
err = gconv.Struct(gtimeComplex, &result4)
t.AssertNil(err)
t.Assert(result4.Year(), complexTime.Year())
t.Assert(int(result4.Month()), int(complexTime.Month()))
t.Assert(result4.Day(), complexTime.Day())
@ -153,21 +153,21 @@ func TestBuiltinGTimeConverter_StructFields(t *testing.T) {
defer func() {
time.Local = originalLocation
}()
tokyoLocation, _ := time.LoadLocation("Asia/Tokyo")
time.Local = tokyoLocation
// Test data
utcTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
gtimeUTC := gtime.NewFromTime(utcTime)
// Test struct with gtime.Time field
type TestStructGTime struct {
ID int `json:"id"`
CreatedAt gtime.Time `json:"created_at"`
ID int `json:"id"`
CreatedAt gtime.Time `json:"created_at"`
UpdatedAt *gtime.Time `json:"updated_at"`
}
// Test 1: Map to struct with gtime fields
t.Logf("=== Test 1: Map to struct with gtime fields ===")
mapData := map[string]interface{}{
@ -175,28 +175,28 @@ func TestBuiltinGTimeConverter_StructFields(t *testing.T) {
"created_at": gtimeUTC,
"updated_at": gtimeUTC,
}
var result1 TestStructGTime
err := gconv.Struct(mapData, &result1)
t.AssertNil(err)
t.Assert(result1.ID, 1)
t.Assert(result1.CreatedAt.Equal(gtimeUTC), true)
t.AssertNE(result1.UpdatedAt, nil)
t.Assert(result1.UpdatedAt.Equal(gtimeUTC), true)
// Verify timezone preservation
_, originalOffset := gtimeUTC.Zone()
_, createdOffset := result1.CreatedAt.Zone()
_, updatedOffset := result1.UpdatedAt.Zone()
t.Assert(createdOffset, originalOffset)
t.Assert(updatedOffset, originalOffset)
t.Logf("Original: %s (offset: %d)", gtimeUTC.Time, originalOffset)
t.Logf("CreatedAt: %s (offset: %d)", result1.CreatedAt.Time, createdOffset)
t.Logf("UpdatedAt: %s (offset: %d)", result1.UpdatedAt.Time, updatedOffset)
// Test 2: Struct to struct conversion
t.Logf("=== Test 2: Struct to struct conversion ===")
sourceStruct := TestStructGTime{
@ -204,15 +204,15 @@ func TestBuiltinGTimeConverter_StructFields(t *testing.T) {
CreatedAt: *gtimeUTC,
UpdatedAt: gtimeUTC,
}
var result2 TestStructGTime
err = gconv.Struct(sourceStruct, &result2)
t.AssertNil(err)
t.Assert(result2.ID, 2)
t.Assert(result2.CreatedAt.Equal(&sourceStruct.CreatedAt), true)
t.Assert(result2.UpdatedAt.Equal(sourceStruct.UpdatedAt), true)
t.Logf("Struct to struct conversion successful")
})
}
@ -225,72 +225,72 @@ func TestBuiltinGTimeConverter_SliceConversion(t *testing.T) {
defer func() {
time.Local = originalLocation
}()
berlinLocation, _ := time.LoadLocation("Europe/Berlin")
time.Local = berlinLocation
// Test data with different timezones
utcTime1 := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
utcTime2 := time.Date(2025, 9, 16, 15, 45, 30, 123456000, time.UTC)
gtimeUTC1 := gtime.NewFromTime(utcTime1)
gtimeUTC2 := gtime.NewFromTime(utcTime2)
// Test 1: Slice of maps to slice of gtime.Time
t.Logf("=== Test 1: Slice of maps to slice of gtime.Time ===")
mapSlice := []map[string]interface{}{
{"time": gtimeUTC1},
{"time": gtimeUTC2},
}
var result1 []gtime.Time
err := gconv.Structs(mapSlice, &result1)
t.AssertNil(err)
t.Assert(len(result1), 2)
// Verify timezone preservation for each element
for i, result := range result1 {
expected := []*gtime.Time{gtimeUTC1, gtimeUTC2}[i]
_, expectedOffset := expected.Zone()
_, resultOffset := result.Zone()
t.Assert(resultOffset, expectedOffset)
t.Assert(result.Equal(expected), true)
t.Logf("Element %d - Expected: %s (offset: %d), Result: %s (offset: %d)",
i, expected.Time, expectedOffset, result.Time, resultOffset)
}
// Test 2: Slice of maps to slice of *gtime.Time
t.Logf("=== Test 2: Slice of maps to slice of *gtime.Time ===")
var result2 []*gtime.Time
err = gconv.Structs(mapSlice, &result2)
t.AssertNil(err)
t.Assert(len(result2), 2)
for i, result := range result2 {
t.AssertNE(result, nil)
expected := []*gtime.Time{gtimeUTC1, gtimeUTC2}[i]
_, expectedOffset := expected.Zone()
_, resultOffset := result.Zone()
t.Assert(resultOffset, expectedOffset)
t.Assert(result.Equal(expected), true)
t.Logf("Pointer Element %d - Expected: %s (offset: %d), Result: %s (offset: %d)",
i, expected.Time, expectedOffset, result.Time, resultOffset)
}
// Test 3: Direct gtime slice conversion
t.Logf("=== Test 3: Direct gtime slice conversion ===")
gtimeSlice := []interface{}{*gtimeUTC1, gtimeUTC2}
var result3 []gtime.Time
err = gconv.Structs(gtimeSlice, &result3)
t.AssertNil(err)
t.Assert(len(result3), 2)
for i, result := range result3 {
expected := []*gtime.Time{gtimeUTC1, gtimeUTC2}[i]
t.Assert(result.Equal(expected), true)
t.Logf("Direct Element %d preserved timezone correctly", i)
}
})
}
}

View File

@ -23,11 +23,11 @@ func TestGTimeTimezonePreservation_ComprehensiveScenarios(t *testing.T) {
defer func() {
time.Local = originalLocation
}()
// Use a timezone that's different from UTC to catch timezone loss issues
sydneyLocation, _ := time.LoadLocation("Australia/Sydney")
time.Local = sydneyLocation
// Test scenarios with different timezones
testTimezones := []struct {
name string
@ -41,45 +41,45 @@ func TestGTimeTimezonePreservation_ComprehensiveScenarios(t *testing.T) {
{"CET", mustLoadLocationComprehensive("Europe/Paris")},
{"IST", mustLoadLocationComprehensive("Asia/Kolkata")},
}
baseTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
for _, tz := range testTimezones {
t.Logf("=== Testing timezone: %s ===", tz.name)
// Create time in specific timezone
testTime := baseTime.In(tz.location)
gtimeVal := gtime.NewFromTime(testTime)
originalName, originalOffset := gtimeVal.Zone()
t.Logf("Original %s time: %s (zone: %s, offset: %d hours)",
t.Logf("Original %s time: %s (zone: %s, offset: %d hours)",
tz.name, gtimeVal.Time, originalName, originalOffset/3600)
// Test 1: Direct conversion
convertedTime := gconv.Time(gtimeVal)
_, convertedOffset := convertedTime.Zone()
t.Assert(convertedOffset, originalOffset)
t.Assert(gtimeVal.Time.Equal(convertedTime), true)
// Test 2: GTime conversion
reconvertedGTime := gconv.GTime(gtimeVal)
t.AssertNE(reconvertedGTime, nil)
_, reconvertedOffset := reconvertedGTime.Zone()
t.Assert(reconvertedOffset, originalOffset)
t.Assert(gtimeVal.Equal(reconvertedGTime), true)
// Test 3: Struct conversion
type TimeStruct struct {
Time time.Time `json:"time"`
}
var timeStruct TimeStruct
err := gconv.Struct(map[string]interface{}{"Time": gtimeVal}, &timeStruct)
t.AssertNil(err)
_, structOffset := timeStruct.Time.Zone()
t.Assert(structOffset, originalOffset)
t.Assert(gtimeVal.Time.Equal(timeStruct.Time), true)
// Test 4: Structs (slice) conversion
result := []map[string]interface{}{{"time": gtimeVal}}
var timeSlice []time.Time
@ -89,7 +89,7 @@ func TestGTimeTimezonePreservation_ComprehensiveScenarios(t *testing.T) {
_, sliceOffset := timeSlice[0].Zone()
t.Assert(sliceOffset, originalOffset)
t.Assert(gtimeVal.Time.Equal(timeSlice[0]), true)
t.Logf("%s timezone preservation: ✅ PASSED", tz.name)
}
})
@ -103,10 +103,10 @@ func TestGTimeTimezonePreservation_DatabaseSimulation(t *testing.T) {
defer func() {
time.Local = originalLocation
}()
shanghaiLocation, _ := time.LoadLocation("Asia/Shanghai")
time.Local = shanghaiLocation
// Simulate different database storage scenarios
testCases := []struct {
name string
@ -121,7 +121,7 @@ func TestGTimeTimezonePreservation_DatabaseSimulation(t *testing.T) {
expectedTz: "UTC",
},
{
name: "GMT_Storage",
name: "GMT_Storage",
description: "Database stores timestamp in GMT",
dbTime: time.Date(2025, 9, 16, 11, 32, 42, 878465000, mustLoadLocationComprehensive("GMT")),
expectedTz: "GMT",
@ -133,64 +133,64 @@ func TestGTimeTimezonePreservation_DatabaseSimulation(t *testing.T) {
expectedTz: "Asia/Shanghai",
},
}
for _, tc := range testCases {
t.Logf("=== %s: %s ===", tc.name, tc.description)
// Create gtime from database time (simulating ORM behavior)
gtimeFromDB := gtime.NewFromTime(tc.dbTime)
originalName, originalOffset := gtimeFromDB.Zone()
t.Logf("Database time: %s (zone: %s, offset: %d)",
t.Logf("Database time: %s (zone: %s, offset: %d)",
gtimeFromDB.Time, originalName, originalOffset/3600)
// Simulate ORM query result conversion - the critical path that was failing
dbResult := []map[string]interface{}{
{"created_at": gtimeFromDB},
{"updated_at": gtimeFromDB},
}
// Convert to time.Time slice (common ORM usage pattern)
var timestamps []time.Time
err := gconv.Structs(dbResult, &timestamps)
t.AssertNil(err)
t.Assert(len(timestamps), 2)
// Verify timezone preservation for both timestamps
for i, ts := range timestamps {
_, resultOffset := ts.Zone()
t.Assert(resultOffset, originalOffset)
t.Assert(gtimeFromDB.Time.Equal(ts), true)
t.Logf("Element %d: %s (offset: %d) - ✅ PRESERVED",
t.Logf("Element %d: %s (offset: %d) - ✅ PRESERVED",
i, ts, resultOffset/3600)
}
// Also test struct field conversion
type DatabaseRecord struct {
ID int `json:"id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
recordData := map[string]interface{}{
"id": 1,
"created_at": gtimeFromDB,
"updated_at": gtimeFromDB,
}
var record DatabaseRecord
err = gconv.Struct(recordData, &record)
t.AssertNil(err)
_, createdOffset := record.CreatedAt.Zone()
_, updatedOffset := record.UpdatedAt.Zone()
t.Assert(createdOffset, originalOffset)
t.Assert(updatedOffset, originalOffset)
t.Assert(gtimeFromDB.Time.Equal(record.CreatedAt), true)
t.Assert(gtimeFromDB.Time.Equal(record.UpdatedAt), true)
t.Logf("Struct fields: CreatedAt=%s (offset: %d), UpdatedAt=%s (offset: %d) - ✅ PRESERVED",
record.CreatedAt, createdOffset/3600, record.UpdatedAt, updatedOffset/3600)
}
@ -205,14 +205,14 @@ func TestGTimeTimezonePreservation_PrecisionAndEdgeCases(t *testing.T) {
defer func() {
time.Local = originalLocation
}()
// Use London timezone (has DST transitions)
londonLocation, _ := time.LoadLocation("Europe/London")
time.Local = londonLocation
// Test precision preservation
t.Logf("=== Precision Preservation Tests ===")
precisionTests := []struct {
name string
nanos int
@ -223,65 +223,65 @@ func TestGTimeTimezonePreservation_PrecisionAndEdgeCases(t *testing.T) {
{"Zero_Nanos", 0},
{"Max_Nanos", 999999999},
}
for _, pt := range precisionTests {
for _, pt := range precisionTests {
t.Logf("--- Testing %s precision ---", pt.name)
testTime := time.Date(2025, 9, 16, 11, 32, 42, pt.nanos, time.UTC)
gtimeVal := gtime.NewFromTime(testTime)
// Test through Structs conversion (the problematic path)
result := []map[string]interface{}{{"time": gtimeVal}}
var timeSlice []time.Time
err := gconv.Structs(result, &timeSlice)
t.AssertNil(err)
t.Assert(len(timeSlice), 1)
convertedTime := timeSlice[0]
t.Assert(convertedTime.Nanosecond(), pt.nanos)
t.Assert(convertedTime.Equal(testTime), true)
t.Logf("%s: Original=%d ns, Converted=%d ns - ✅ PRESERVED",
t.Logf("%s: Original=%d ns, Converted=%d ns - ✅ PRESERVED",
pt.name, pt.nanos, convertedTime.Nanosecond())
}
// Test edge cases
t.Logf("=== Edge Cases Tests ===")
// Test 1: Leap year
leapTime := time.Date(2024, 2, 29, 11, 32, 42, 0, time.UTC)
gtimeLeap := gtime.NewFromTime(leapTime)
var leapResult []time.Time
err := gconv.Structs([]map[string]interface{}{{"time": gtimeLeap}}, &leapResult)
t.AssertNil(err)
t.Assert(leapResult[0].Equal(leapTime), true)
t.Logf("Leap year: %s - ✅ PRESERVED", leapResult[0])
// Test 2: Year boundaries
yearBoundary := time.Date(1999, 12, 31, 23, 59, 59, 999999999, time.UTC)
gtimeYear := gtime.NewFromTime(yearBoundary)
var yearResult []time.Time
err = gconv.Structs([]map[string]interface{}{{"time": gtimeYear}}, &yearResult)
t.AssertNil(err)
t.Assert(yearResult[0].Equal(yearBoundary), true)
t.Logf("Year boundary: %s - ✅ PRESERVED", yearResult[0])
// Test 3: Unix epoch
epochTime := time.Unix(0, 0).UTC()
gtimeEpoch := gtime.NewFromTime(epochTime)
var epochResult []time.Time
err = gconv.Structs([]map[string]interface{}{{"time": gtimeEpoch}}, &epochResult)
t.AssertNil(err)
t.Assert(epochResult[0].Equal(epochTime), true)
t.Logf("Unix epoch: %s - ✅ PRESERVED", epochResult[0])
// Test 4: Future date
futureTime := time.Date(2099, 12, 31, 23, 59, 59, 0, time.UTC)
gtimeFuture := gtime.NewFromTime(futureTime)
var futureResult []time.Time
err = gconv.Structs([]map[string]interface{}{{"time": gtimeFuture}}, &futureResult)
t.AssertNil(err)
@ -296,17 +296,17 @@ func TestGTimeTimezonePreservation_PerformanceRegression(t *testing.T) {
// Create test data
utcTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
gtimeVal := gtime.NewFromTime(utcTime)
// Performance test: Ensure timezone preservation doesn't significantly impact performance
iterations := 1000
// Test 1: Direct conversion performance
start := time.Now()
for i := 0; i < iterations; i++ {
_ = gconv.Time(gtimeVal)
}
directDuration := time.Since(start)
// Test 2: Struct conversion performance
start = time.Now()
for i := 0; i < iterations; i++ {
@ -314,7 +314,7 @@ func TestGTimeTimezonePreservation_PerformanceRegression(t *testing.T) {
_ = gconv.Struct(gtimeVal, &result)
}
structDuration := time.Since(start)
// Test 3: Structs (slice) conversion performance
mapData := []map[string]interface{}{{"time": gtimeVal}}
start = time.Now()
@ -323,22 +323,22 @@ func TestGTimeTimezonePreservation_PerformanceRegression(t *testing.T) {
_ = gconv.Structs(mapData, &result)
}
sliceDuration := time.Since(start)
// Performance should be reasonable (not exact assertions, just reasonable bounds)
t.Logf("Performance Results for %d iterations:", iterations)
t.Logf("Direct conversion: %v (avg: %v/op)", directDuration, directDuration/time.Duration(iterations))
t.Logf("Struct conversion: %v (avg: %v/op)", structDuration, structDuration/time.Duration(iterations))
t.Logf("Slice conversion: %v (avg: %v/op)", sliceDuration, sliceDuration/time.Duration(iterations))
// Ensure performance is reasonable (under 1ms per operation)
avgDirect := directDuration / time.Duration(iterations)
avgStruct := structDuration / time.Duration(iterations)
avgSlice := sliceDuration / time.Duration(iterations)
t.Assert(avgDirect < time.Millisecond, true)
t.Assert(avgStruct < time.Millisecond, true)
t.Assert(avgSlice < time.Millisecond, true)
t.Logf("All performance tests passed ✅")
})
}
@ -350,4 +350,4 @@ func mustLoadLocationComprehensive(name string) *time.Location {
panic(err)
}
return loc
}
}

View File

@ -23,38 +23,38 @@ func TestGTimeStringConversion_Basic(t *testing.T) {
defer func() {
time.Local = originalLocation
}()
parisLocation, _ := time.LoadLocation("Europe/Paris")
time.Local = parisLocation
// Test UTC time string conversion
utcTime := time.Date(2025, 9, 16, 11, 32, 42, 878465000, time.UTC)
gtimeVal := gtime.NewFromTime(utcTime)
// Test gtime.Time to string
resultStr := gconv.String(*gtimeVal)
t.Logf("gtime to string: %s", resultStr)
// Should use RFC3339 format (note: microseconds will be truncated if they're 0)
expectedRFC3339 := "2025-09-16T11:32:42Z"
t.Assert(resultStr, expectedRFC3339)
// Test *gtime.Time to string
ptrStr := gconv.String(gtimeVal)
t.Assert(ptrStr, expectedRFC3339)
// Test round-trip conversion
reconverted := gconv.GTime(resultStr)
t.AssertNE(reconverted, nil)
// Check if times represent the same instant (more important than exact equality due to precision differences)
t.Assert(gtimeVal.Time.Truncate(time.Second).Equal(reconverted.Time.Truncate(time.Second)), true)
// Verify timezone preservation
_, originalOffset := gtimeVal.Zone()
_, reconvertedOffset := reconverted.Zone()
t.Assert(reconvertedOffset, originalOffset)
t.Logf("✅ String conversion preserves timezone correctly")
})
}
@ -65,23 +65,23 @@ func TestGTimeStringConversion_Precision(t *testing.T) {
// Test microsecond precision
preciseTime := time.Date(2025, 9, 16, 11, 32, 42, 123456789, time.UTC)
gtimeVal := gtime.NewFromTime(preciseTime)
// Convert to string
timeStr := gconv.String(gtimeVal)
t.Logf("Precise time string: %s", timeStr)
// Should include nanosecond precision
expected := "2025-09-16T11:32:42.123456789Z"
t.Assert(timeStr, expected)
// Convert back
reconverted := gconv.GTime(timeStr)
t.AssertNE(reconverted, nil)
// Verify precision preservation
t.Assert(reconverted.Nanosecond(), preciseTime.Nanosecond())
t.Assert(reconverted.Equal(gtimeVal), true)
t.Logf("✅ Precision preserved in string conversion")
})
}
@ -93,23 +93,23 @@ func TestGTimeStringConversion_EdgeCases(t *testing.T) {
zeroGTime := gtime.Time{}
zeroStr := gconv.String(zeroGTime)
t.Assert(zeroStr, "")
// Test nil gtime
var nilGTime *gtime.Time = nil
nilStr := gconv.String(nilGTime)
t.Assert(nilStr, "")
// Test very old date
oldTime := time.Date(1900, 1, 1, 0, 0, 0, 0, time.UTC)
oldGTime := gtime.NewFromTime(oldTime)
oldStr := gconv.String(oldGTime)
expectedOld := "1900-01-01T00:00:00Z"
t.Assert(oldStr, expectedOld)
// Test round-trip for old date
fromOld := gconv.GTime(oldStr)
t.Assert(fromOld.Equal(oldGTime), true)
t.Logf("✅ Edge cases handled correctly")
})
}
}