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 3fad2ad4 fix(array): format date arrays in String (#1068)
3fad2ad4 is described below
commit 3fad2ad4ced30a7e293e4703c56b74c882eb811a
Author: Minh Vu <[email protected]>
AuthorDate: Wed Aug 5 20:33:25 2026 +0200
fix(array): format date arrays in String (#1068)
Fixes #63
## Problem
Date32 and Date64 arrays inherited the numeric array `String`
implementation, so their values were rendered as raw integers instead of
dates. This was inconsistent with their existing `ValueStr` and JSON
formatting.
## Change
Give date arrays a `String` implementation that formats each non-null
value through `ValueStr`. Null markers, slice behavior, and the
established array layout are preserved.
## Coverage
The tests cover Date32, Date64, null values, negative dates, and sliced
arrays. Generated builder expectations are updated to match the
user-visible date representation.
## Validation
`go test ./arrow/array`
---
arrow/array/date_string_test.go | 56 +++++++++++++++++++++++++++++
arrow/array/numeric_generic.go | 13 +++++++
arrow/array/numericbuilder.gen_test.go | 8 ++---
arrow/array/numericbuilder.gen_test.go.tmpl | 6 ++--
arrow/csv/reader_test.go | 8 ++---
arrow/ipc/cmd/arrow-cat/main_test.go | 36 +++++++++----------
6 files changed, 97 insertions(+), 30 deletions(-)
diff --git a/arrow/array/date_string_test.go b/arrow/array/date_string_test.go
new file mode 100644
index 00000000..e0a28845
--- /dev/null
+++ b/arrow/array/date_string_test.go
@@ -0,0 +1,56 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package array_test
+
+import (
+ "testing"
+
+ "github.com/apache/arrow-go/v18/arrow"
+ "github.com/apache/arrow-go/v18/arrow/array"
+ "github.com/apache/arrow-go/v18/arrow/memory"
+)
+
+func TestDateArrayString(t *testing.T) {
+ tests := []struct {
+ name string
+ build func() arrow.Array
+ want string
+ }{
+ {"date32", func() arrow.Array {
+ b := array.NewDate32Builder(memory.DefaultAllocator)
+ defer b.Release()
+ b.AppendValues([]arrow.Date32{1, 2, 3}, []bool{true,
false, true})
+ return b.NewArray()
+ }, "[1970-01-02 (null) 1970-01-04]"},
+ {"date64", func() arrow.Array {
+ b := array.NewDate64Builder(memory.DefaultAllocator)
+ defer b.Release()
+ b.AppendValues([]arrow.Date64{-86400000, 0, 86400000},
nil)
+ return b.NewArray()
+ }, "[1969-12-31 1970-01-01 1970-01-02]"},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ arr := tt.build()
+ defer arr.Release()
+ if got := arr.String(); got != tt.want {
+ t.Fatalf("unexpected string: got %q, want %q",
got, tt.want)
+ }
+ })
+ }
+}
diff --git a/arrow/array/numeric_generic.go b/arrow/array/numeric_generic.go
index 1b671fc7..24edd549 100644
--- a/arrow/array/numeric_generic.go
+++ b/arrow/array/numeric_generic.go
@@ -173,6 +173,19 @@ type dateArray[T interface {
numericArray[T]
}
+func (d *dateArray[T]) String() string {
+ var b strings.Builder
+ b.WriteByte('[')
+ for i := range d.values {
+ if i > 0 {
+ b.WriteByte(' ')
+ }
+ b.WriteString(d.ValueStr(i))
+ }
+ b.WriteByte(']')
+ return b.String()
+}
+
func (d *dateArray[T]) MarshalJSON() ([]byte, error) {
vals := make([]any, d.Len())
for i := range d.values {
diff --git a/arrow/array/numericbuilder.gen_test.go
b/arrow/array/numericbuilder.gen_test.go
index c54d8cf2..dccadcfe 100644
--- a/arrow/array/numericbuilder.gen_test.go
+++ b/arrow/array/numericbuilder.gen_test.go
@@ -3012,7 +3012,7 @@ func TestNewDate32Builder(t *testing.T) {
t.Fatalf("could not type-assert to array.Date32")
}
- if got, want := a.String(), `[1 2 (null) 4]`; got != want {
+ if got, want := a.String(), `[1970-01-02 1970-01-03 (null)
1970-01-05]`; got != want {
t.Fatalf("got=%q, want=%q", got, want)
}
@@ -3027,7 +3027,7 @@ func TestNewDate32Builder(t *testing.T) {
t.Fatalf("could not type-assert to array.Date32")
}
- if got, want := v.String(), `[(null) 4]`; got != want {
+ if got, want := v.String(), `[(null) 1970-01-05]`; got != want {
t.Fatalf("got=%q, want=%q", got, want)
}
@@ -3258,7 +3258,7 @@ func TestNewDate64Builder(t *testing.T) {
t.Fatalf("could not type-assert to array.Date64")
}
- if got, want := a.String(), `[1 2 (null) 4]`; got != want {
+ if got, want := a.String(), `[1970-01-01 1970-01-01 (null)
1970-01-01]`; got != want {
t.Fatalf("got=%q, want=%q", got, want)
}
@@ -3273,7 +3273,7 @@ func TestNewDate64Builder(t *testing.T) {
t.Fatalf("could not type-assert to array.Date64")
}
- if got, want := v.String(), `[(null) 4]`; got != want {
+ if got, want := v.String(), `[(null) 1970-01-01]`; got != want {
t.Fatalf("got=%q, want=%q", got, want)
}
diff --git a/arrow/array/numericbuilder.gen_test.go.tmpl
b/arrow/array/numericbuilder.gen_test.go.tmpl
index e3422496..c655b764 100644
--- a/arrow/array/numericbuilder.gen_test.go.tmpl
+++ b/arrow/array/numericbuilder.gen_test.go.tmpl
@@ -161,7 +161,7 @@ func TestNew{{.Name}}Builder(t *testing.T) {
t.Fatalf("could not type-assert to array.{{.Name}}")
}
- if got, want := a.String(), `[1 2 (null) 4]`; got != want {
+ if got, want := a.String(), `{{if eq .Name "Date32"}}[1970-01-02
1970-01-03 (null) 1970-01-05]{{else if eq .Name "Date64"}}[1970-01-01
1970-01-01 (null) 1970-01-01]{{else}}[1 2 (null) 4]{{end}}`; got != want {
t.Fatalf("got=%q, want=%q", got, want)
}
@@ -176,7 +176,7 @@ func TestNew{{.Name}}Builder(t *testing.T) {
t.Fatalf("could not type-assert to array.{{.Name}}")
}
- if got, want := v.String(), `[(null) 4]`; got != want {
+ if got, want := v.String(), `{{if eq .Name "Date32"}}[(null)
1970-01-05]{{else if eq .Name "Date64"}}[(null) 1970-01-01]{{else}}[(null)
4]{{end}}`; got != want {
t.Fatalf("got=%q, want=%q", got, want)
}
@@ -339,5 +339,3 @@ func Test{{.Name}}BuilderUnmarshalJSON(t *testing.T) {
}
{{end}}
-
-
diff --git a/arrow/csv/reader_test.go b/arrow/csv/reader_test.go
index acc516aa..80c78482 100644
--- a/arrow/csv/reader_test.go
+++ b/arrow/csv/reader_test.go
@@ -422,8 +422,8 @@ rec[0]["binary"]: ["\x00\x01\x02"]
rec[0]["large_binary"]: ["\x00\x01\x02"]
rec[0]["fixed_size_binary"]: ["\x00\x01\x02"]
rec[0]["uuid"]: ["00000000-0000-0000-0000-000000000001"]
-rec[0]["date32"]: [19121]
-rec[0]["date64"]: [1652054400000]
+rec[0]["date32"]: [2022-05-09]
+rec[0]["date64"]: [2022-05-09]
rec[1]["bool"]: [false]
rec[1]["i8"]: [-2]
rec[1]["i16"]: [-2]
@@ -446,8 +446,8 @@ rec[1]["binary"]: [(null)]
rec[1]["large_binary"]: [(null)]
rec[1]["fixed_size_binary"]: [(null)]
rec[1]["uuid"]: ["00000000-0000-0000-0000-000000000002"]
-rec[1]["date32"]: [19121]
-rec[1]["date64"]: [1652054400000]
+rec[1]["date32"]: [2022-05-09]
+rec[1]["date64"]: [2022-05-09]
rec[2]["bool"]: [(null)]
rec[2]["i8"]: [(null)]
rec[2]["i16"]: [(null)]
diff --git a/arrow/ipc/cmd/arrow-cat/main_test.go
b/arrow/ipc/cmd/arrow-cat/main_test.go
index 78b3853c..7c8bcea0 100644
--- a/arrow/ipc/cmd/arrow-cat/main_test.go
+++ b/arrow/ipc/cmd/arrow-cat/main_test.go
@@ -131,8 +131,8 @@ record 3...
col[6] "timestamp_ms": [0 (null) (null) 3 4]
col[7] "timestamp_us": [0 (null) (null) 3 4]
col[8] "timestamp_ns": [0 (null) (null) 3 4]
- col[9] "date32s": [-2 (null) (null) 1 2]
- col[10] "date64s": [-2 (null) (null) 1 2]
+ col[9] "date32s": [1969-12-30 (null) (null) 1970-01-02 1970-01-03]
+ col[10] "date64s": [1970-01-01 (null) (null) 1970-01-01 1970-01-01]
record 2...
col[0] "float16s": [11 (null) (null) 14 15]
col[1] "time32ms": [-12 (null) (null) 11 12]
@@ -143,8 +143,8 @@ record 2...
col[6] "timestamp_ms": [10 (null) (null) 13 14]
col[7] "timestamp_us": [10 (null) (null) 13 14]
col[8] "timestamp_ns": [10 (null) (null) 13 14]
- col[9] "date32s": [-12 (null) (null) 11 12]
- col[10] "date64s": [-12 (null) (null) 11 12]
+ col[9] "date32s": [1969-12-20 (null) (null) 1970-01-12 1970-01-13]
+ col[10] "date64s": [1970-01-01 (null) (null) 1970-01-01 1970-01-01]
record 3...
col[0] "float16s": [21 (null) (null) 24 25]
col[1] "time32ms": [-22 (null) (null) 21 22]
@@ -155,8 +155,8 @@ record 3...
col[6] "timestamp_ms": [20 (null) (null) 23 24]
col[7] "timestamp_us": [20 (null) (null) 23 24]
col[8] "timestamp_ns": [20 (null) (null) 23 24]
- col[9] "date32s": [-22 (null) (null) 21 22]
- col[10] "date64s": [-22 (null) (null) 21 22]
+ col[9] "date32s": [1969-12-10 (null) (null) 1970-01-22 1970-01-23]
+ col[10] "date64s": [1970-01-01 (null) (null) 1970-01-01 1970-01-01]
`,
},
{
@@ -448,8 +448,8 @@ record 3/3...
col[6] "timestamp_ms": [0 (null) (null) 3 4]
col[7] "timestamp_us": [0 (null) (null) 3 4]
col[8] "timestamp_ns": [0 (null) (null) 3 4]
- col[9] "date32s": [-2 (null) (null) 1 2]
- col[10] "date64s": [-2 (null) (null) 1 2]
+ col[9] "date32s": [1969-12-30 (null) (null) 1970-01-02 1970-01-03]
+ col[10] "date64s": [1970-01-01 (null) (null) 1970-01-01 1970-01-01]
record 2...
col[0] "float16s": [11 (null) (null) 14 15]
col[1] "time32ms": [-12 (null) (null) 11 12]
@@ -460,8 +460,8 @@ record 2...
col[6] "timestamp_ms": [10 (null) (null) 13 14]
col[7] "timestamp_us": [10 (null) (null) 13 14]
col[8] "timestamp_ns": [10 (null) (null) 13 14]
- col[9] "date32s": [-12 (null) (null) 11 12]
- col[10] "date64s": [-12 (null) (null) 11 12]
+ col[9] "date32s": [1969-12-20 (null) (null) 1970-01-12 1970-01-13]
+ col[10] "date64s": [1970-01-01 (null) (null) 1970-01-01 1970-01-01]
record 3...
col[0] "float16s": [21 (null) (null) 24 25]
col[1] "time32ms": [-22 (null) (null) 21 22]
@@ -472,8 +472,8 @@ record 3...
col[6] "timestamp_ms": [20 (null) (null) 23 24]
col[7] "timestamp_us": [20 (null) (null) 23 24]
col[8] "timestamp_ns": [20 (null) (null) 23 24]
- col[9] "date32s": [-22 (null) (null) 21 22]
- col[10] "date64s": [-22 (null) (null) 21 22]
+ col[9] "date32s": [1969-12-10 (null) (null) 1970-01-22 1970-01-23]
+ col[10] "date64s": [1970-01-01 (null) (null) 1970-01-01 1970-01-01]
`,
},
{
@@ -489,8 +489,8 @@ record 1/3...
col[6] "timestamp_ms": [0 (null) (null) 3 4]
col[7] "timestamp_us": [0 (null) (null) 3 4]
col[8] "timestamp_ns": [0 (null) (null) 3 4]
- col[9] "date32s": [-2 (null) (null) 1 2]
- col[10] "date64s": [-2 (null) (null) 1 2]
+ col[9] "date32s": [1969-12-30 (null) (null) 1970-01-02 1970-01-03]
+ col[10] "date64s": [1970-01-01 (null) (null) 1970-01-01 1970-01-01]
record 2/3...
col[0] "float16s": [11 (null) (null) 14 15]
col[1] "time32ms": [-12 (null) (null) 11 12]
@@ -501,8 +501,8 @@ record 2/3...
col[6] "timestamp_ms": [10 (null) (null) 13 14]
col[7] "timestamp_us": [10 (null) (null) 13 14]
col[8] "timestamp_ns": [10 (null) (null) 13 14]
- col[9] "date32s": [-12 (null) (null) 11 12]
- col[10] "date64s": [-12 (null) (null) 11 12]
+ col[9] "date32s": [1969-12-20 (null) (null) 1970-01-12 1970-01-13]
+ col[10] "date64s": [1970-01-01 (null) (null) 1970-01-01 1970-01-01]
record 3/3...
col[0] "float16s": [21 (null) (null) 24 25]
col[1] "time32ms": [-22 (null) (null) 21 22]
@@ -513,8 +513,8 @@ record 3/3...
col[6] "timestamp_ms": [20 (null) (null) 23 24]
col[7] "timestamp_us": [20 (null) (null) 23 24]
col[8] "timestamp_ns": [20 (null) (null) 23 24]
- col[9] "date32s": [-22 (null) (null) 21 22]
- col[10] "date64s": [-22 (null) (null) 21 22]
+ col[9] "date32s": [1969-12-10 (null) (null) 1970-01-22 1970-01-23]
+ col[10] "date64s": [1970-01-01 (null) (null) 1970-01-01 1970-01-01]
`,
},
{