This is an automated email from the ASF dual-hosted git repository.

zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-go.git


The following commit(s) were added to refs/heads/main by this push:
     new 4b94a0b2 fix(arrow/scalar): support same-width time casts (#1040)
4b94a0b2 is described below

commit 4b94a0b245cdb76b03ca812084c46b1988dcd6e7
Author: Minh Vu <[email protected]>
AuthorDate: Tue Jul 28 17:08:01 2026 +0200

    fix(arrow/scalar): support same-width time casts (#1040)
    
    ## What changed
    
    Extract temporal scalar values according to the source width before
    converting them to a destination `Time32` or `Time64` unit.
    
    ## Why
    
    The previous implementation chose the source value assertion from the
    destination type. Same-width conversions therefore asserted `Time32`
    values as `Time64`, or vice versa, and panicked.
    
    The regression matrix covers Time32-to-Time32, Time32-to-Time64,
    Time64-to-Time32, and Time64-to-Time64 conversions.
    
    ## Validation
    
    `go test ./arrow/scalar`
---
 arrow/scalar/scalar_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++
 arrow/scalar/temporal.go    | 12 ++++++++++--
 2 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/arrow/scalar/scalar_test.go b/arrow/scalar/scalar_test.go
index 78ec0c9a..8aa7aebe 100644
--- a/arrow/scalar/scalar_test.go
+++ b/arrow/scalar/scalar_test.go
@@ -366,6 +366,48 @@ func TestTimeScalarsMakeScalar(t *testing.T) {
        assert.Equal(t, "10:10:10.123456789", 
scalar.NewTime64Scalar(arrow.Time64(tententen), typ4).String())
 }
 
+func TestTimeScalarUnitConversions(t *testing.T) {
+       tests := []struct {
+               name string
+               from scalar.TimeScalar
+               to   arrow.DataType
+               want scalar.Scalar
+       }{
+               {
+                       name: "time32 to time32",
+                       from: scalar.NewTime32Scalar(2, 
arrow.FixedWidthTypes.Time32s),
+                       to:   arrow.FixedWidthTypes.Time32ms,
+                       want: scalar.NewTime32Scalar(2000, 
arrow.FixedWidthTypes.Time32ms),
+               },
+               {
+                       name: "time32 to time64",
+                       from: scalar.NewTime32Scalar(2, 
arrow.FixedWidthTypes.Time32s),
+                       to:   arrow.FixedWidthTypes.Time64us,
+                       want: scalar.NewTime64Scalar(2_000_000, 
arrow.FixedWidthTypes.Time64us),
+               },
+               {
+                       name: "time64 to time32",
+                       from: scalar.NewTime64Scalar(2_000_000, 
arrow.FixedWidthTypes.Time64us),
+                       to:   arrow.FixedWidthTypes.Time32ms,
+                       want: scalar.NewTime32Scalar(2000, 
arrow.FixedWidthTypes.Time32ms),
+               },
+               {
+                       name: "time64 to time64",
+                       from: scalar.NewTime64Scalar(2, 
arrow.FixedWidthTypes.Time64us),
+                       to:   arrow.FixedWidthTypes.Time64ns,
+                       want: scalar.NewTime64Scalar(2000, 
arrow.FixedWidthTypes.Time64ns),
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       got, err := tt.from.CastTo(tt.to)
+                       require.NoError(t, err)
+                       assert.True(t, scalar.Equals(tt.want, got))
+               })
+       }
+}
+
 func TestTimestampScalarBasics(t *testing.T) {
        typ1 := arrow.FixedWidthTypes.Timestamp_ms
        typ2 := arrow.FixedWidthTypes.Timestamp_s
diff --git a/arrow/scalar/temporal.go b/arrow/scalar/temporal.go
index 42a46738..26a6aeae 100644
--- a/arrow/scalar/temporal.go
+++ b/arrow/scalar/temporal.go
@@ -155,11 +155,19 @@ func castTemporal(from TemporalScalar, to arrow.DataType) 
(Scalar, error) {
                        return NewDate64Scalar(arrow.Date64(millis - 
millis%int64(millisecondsInDay))), nil
                }
        case TimeScalar:
+               var value int64
+               switch s := s.(type) {
+               case *Time32:
+                       value = int64(s.Value)
+               case *Time64:
+                       value = int64(s.Value)
+               }
+
                switch to := to.(type) {
                case *arrow.Time32Type:
-                       return 
NewTime32Scalar(arrow.Time32(arrow.ConvertTimestampValue(s.Unit(), to.Unit, 
int64(s.value().(arrow.Time64)))), to), nil
+                       return 
NewTime32Scalar(arrow.Time32(arrow.ConvertTimestampValue(s.Unit(), to.Unit, 
value)), to), nil
                case *arrow.Time64Type:
-                       return 
NewTime64Scalar(arrow.Time64(arrow.ConvertTimestampValue(s.Unit(), to.Unit, 
int64(s.value().(arrow.Time32)))), to), nil
+                       return 
NewTime64Scalar(arrow.Time64(arrow.ConvertTimestampValue(s.Unit(), to.Unit, 
value)), to), nil
                }
 
        case *Duration:

Reply via email to