You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by we...@apache.org on 2018/12/17 16:09:37 UTC

[arrow] branch master updated: ARROW-3674: [Go] Implement Date32 and Date64 array types

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

wesm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git


The following commit(s) were added to refs/heads/master by this push:
     new a236464  ARROW-3674: [Go] Implement Date32 and Date64 array types
a236464 is described below

commit a236464551df9427af3f5750a1630100d086d178
Author: Dustin Long <me...@dustmop.io>
AuthorDate: Mon Dec 17 10:09:30 2018 -0600

    ARROW-3674: [Go] Implement Date32 and Date64 array types
    
    Implement both Date32 and Date64 types for arrays. Also resolves ARROW-3675. Unit tests follow the same pattern as the existing float64 and Time{32,64} tests.
    
    Author: Dustin Long <me...@dustmop.io>
    
    Closes #3170 from dustmop/date-types and squashes the following commits:
    
    29ae27474 <Dustin Long> ARROW-3674:  Date{32,64} as primitive fixed-width types, not parametric
    07a261047 <Dustin Long> ARROW-3674:  Implement Date32 and Date64 array types
---
 go/arrow/array/array.go                   |   4 +-
 go/arrow/array/numeric.gen.go             |  90 ++++++++++
 go/arrow/array/numeric_test.go            | 220 ++++++++++++++++++++++++
 go/arrow/array/numericbuilder.gen.go      | 270 ++++++++++++++++++++++++++++++
 go/arrow/array/numericbuilder_test.go     | 220 ++++++++++++++++++++++++
 go/arrow/datatype_fixedwidth.go           |   2 +
 go/arrow/datatype_numeric.gen.go          |  16 ++
 go/arrow/datatype_numeric.gen.go.tmpldata |  10 ++
 go/arrow/numeric.tmpldata                 |  20 ++-
 go/arrow/type_traits_numeric.gen.go       |  98 +++++++++++
 10 files changed, 947 insertions(+), 3 deletions(-)

diff --git a/go/arrow/array/array.go b/go/arrow/array/array.go
index b188dcd..ef37aef 100644
--- a/go/arrow/array/array.go
+++ b/go/arrow/array/array.go
@@ -180,8 +180,8 @@ func init() {
 		arrow.STRING:            func(data *Data) Interface { return NewStringData(data) },
 		arrow.BINARY:            func(data *Data) Interface { return NewBinaryData(data) },
 		arrow.FIXED_SIZE_BINARY: func(data *Data) Interface { return NewFixedSizeBinaryData(data) },
-		arrow.DATE32:            unsupportedArrayType,
-		arrow.DATE64:            unsupportedArrayType,
+		arrow.DATE32:            func(data *Data) Interface { return NewDate32Data(data) },
+		arrow.DATE64:            func(data *Data) Interface { return NewDate64Data(data) },
 		arrow.TIMESTAMP:         func(data *Data) Interface { return NewTimestampData(data) },
 		arrow.TIME32:            func(data *Data) Interface { return NewTime32Data(data) },
 		arrow.TIME64:            func(data *Data) Interface { return NewTime64Data(data) },
diff --git a/go/arrow/array/numeric.gen.go b/go/arrow/array/numeric.gen.go
index 1f734c0..1fb8257 100644
--- a/go/arrow/array/numeric.gen.go
+++ b/go/arrow/array/numeric.gen.go
@@ -609,3 +609,93 @@ func (a *Time64) setData(data *Data) {
 		a.values = a.values[beg:end]
 	}
 }
+
+// A type which represents an immutable sequence of arrow.Date32 values.
+type Date32 struct {
+	array
+	values []arrow.Date32
+}
+
+func NewDate32Data(data *Data) *Date32 {
+	a := &Date32{}
+	a.refCount = 1
+	a.setData(data)
+	return a
+}
+
+func (a *Date32) Value(i int) arrow.Date32     { return a.values[i] }
+func (a *Date32) Date32Values() []arrow.Date32 { return a.values }
+
+func (a *Date32) String() string {
+	o := new(strings.Builder)
+	o.WriteString("[")
+	for i, v := range a.values {
+		if i > 0 {
+			fmt.Fprintf(o, " ")
+		}
+		switch {
+		case a.IsNull(i):
+			o.WriteString("(null)")
+		default:
+			fmt.Fprintf(o, "%v", v)
+		}
+	}
+	o.WriteString("]")
+	return o.String()
+}
+
+func (a *Date32) setData(data *Data) {
+	a.array.setData(data)
+	vals := data.buffers[1]
+	if vals != nil {
+		a.values = arrow.Date32Traits.CastFromBytes(vals.Bytes())
+		beg := a.array.data.offset
+		end := beg + a.array.data.length
+		a.values = a.values[beg:end]
+	}
+}
+
+// A type which represents an immutable sequence of arrow.Date64 values.
+type Date64 struct {
+	array
+	values []arrow.Date64
+}
+
+func NewDate64Data(data *Data) *Date64 {
+	a := &Date64{}
+	a.refCount = 1
+	a.setData(data)
+	return a
+}
+
+func (a *Date64) Value(i int) arrow.Date64     { return a.values[i] }
+func (a *Date64) Date64Values() []arrow.Date64 { return a.values }
+
+func (a *Date64) String() string {
+	o := new(strings.Builder)
+	o.WriteString("[")
+	for i, v := range a.values {
+		if i > 0 {
+			fmt.Fprintf(o, " ")
+		}
+		switch {
+		case a.IsNull(i):
+			o.WriteString("(null)")
+		default:
+			fmt.Fprintf(o, "%v", v)
+		}
+	}
+	o.WriteString("]")
+	return o.String()
+}
+
+func (a *Date64) setData(data *Data) {
+	a.array.setData(data)
+	vals := data.buffers[1]
+	if vals != nil {
+		a.values = arrow.Date64Traits.CastFromBytes(vals.Bytes())
+		beg := a.array.data.offset
+		end := beg + a.array.data.length
+		a.values = a.values[beg:end]
+	}
+}
diff --git a/go/arrow/array/numeric_test.go b/go/arrow/array/numeric_test.go
index 9e8267a..fc7f04a 100644
--- a/go/arrow/array/numeric_test.go
+++ b/go/arrow/array/numeric_test.go
@@ -394,3 +394,223 @@ func TestTime64SliceDataWithNull(t *testing.T) {
 		t.Fatalf("got=%v, want=%v", got, want)
 	}
 }
+
+func TestNewDate32Data(t *testing.T) {
+	exp := []arrow.Date32{1, 2, 4, 8, 16}
+
+	dtype := &arrow.Date32Type{}
+	ad := array.NewData(
+		dtype, len(exp),
+		[]*memory.Buffer{nil, memory.NewBufferBytes(arrow.Date32Traits.CastToBytes(exp))},
+		nil, 0, 0,
+	)
+	fa := array.NewDate32Data(ad)
+
+	assert.Equal(t, len(exp), fa.Len(), "unexpected Len()")
+	assert.Equal(t, exp, fa.Date32Values(), "unexpected Date32Values()")
+}
+
+func TestDate32SliceData(t *testing.T) {
+	pool := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer pool.AssertSize(t, 0)
+
+	const (
+		beg = 2
+		end = 4
+	)
+
+	var (
+		vs  = []arrow.Date32{1, 2, 3, 4, 5}
+		sub = vs[beg:end]
+	)
+
+	b := array.NewDate32Builder(pool)
+	defer b.Release()
+
+	for _, v := range vs {
+		b.Append(v)
+	}
+
+	arr := b.NewArray().(*array.Date32)
+	defer arr.Release()
+
+	if got, want := arr.Len(), len(vs); got != want {
+		t.Fatalf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := arr.Date32Values(), vs; !reflect.DeepEqual(got, want) {
+		t.Fatalf("got=%v, want=%v", got, want)
+	}
+
+	slice := array.NewSlice(arr, beg, end).(*array.Date32)
+	defer slice.Release()
+
+	if got, want := slice.Len(), len(sub); got != want {
+		t.Fatalf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := slice.Date32Values(), sub; !reflect.DeepEqual(got, want) {
+		t.Fatalf("got=%v, want=%v", got, want)
+	}
+}
+
+func TestDate32SliceDataWithNull(t *testing.T) {
+	pool := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer pool.AssertSize(t, 0)
+
+	const (
+		beg = 2
+		end = 5
+	)
+
+	var (
+		valids = []bool{true, true, true, false, true, true}
+		vs     = []arrow.Date32{1, 2, 3, 0, 4, 5}
+		sub    = vs[beg:end]
+	)
+
+	b := array.NewDate32Builder(pool)
+	defer b.Release()
+
+	b.AppendValues(vs, valids)
+
+	arr := b.NewArray().(*array.Date32)
+	defer arr.Release()
+
+	if got, want := arr.Len(), len(valids); got != want {
+		t.Fatalf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := arr.NullN(), 1; got != want {
+		t.Fatalf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := arr.Date32Values(), vs; !reflect.DeepEqual(got, want) {
+		t.Fatalf("got=%v, want=%v", got, want)
+	}
+
+	slice := array.NewSlice(arr, beg, end).(*array.Date32)
+	defer slice.Release()
+
+	if got, want := slice.NullN(), 1; got != want {
+		t.Errorf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := slice.Len(), len(sub); got != want {
+		t.Fatalf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := slice.Date32Values(), sub; !reflect.DeepEqual(got, want) {
+		t.Fatalf("got=%v, want=%v", got, want)
+	}
+}
+
+func TestNewDate64Data(t *testing.T) {
+	exp := []arrow.Date64{1, 2, 4, 8, 16}
+
+	dtype := &arrow.Date64Type{}
+	ad := array.NewData(
+		dtype, len(exp),
+		[]*memory.Buffer{nil, memory.NewBufferBytes(arrow.Date64Traits.CastToBytes(exp))},
+		nil, 0, 0,
+	)
+	fa := array.NewDate64Data(ad)
+
+	assert.Equal(t, len(exp), fa.Len(), "unexpected Len()")
+	assert.Equal(t, exp, fa.Date64Values(), "unexpected Date64Values()")
+}
+
+func TestDate64SliceData(t *testing.T) {
+	pool := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer pool.AssertSize(t, 0)
+
+	const (
+		beg = 2
+		end = 4
+	)
+
+	var (
+		vs  = []arrow.Date64{1, 2, 3, 4, 5}
+		sub = vs[beg:end]
+	)
+
+	b := array.NewDate64Builder(pool)
+	defer b.Release()
+
+	for _, v := range vs {
+		b.Append(v)
+	}
+
+	arr := b.NewArray().(*array.Date64)
+	defer arr.Release()
+
+	if got, want := arr.Len(), len(vs); got != want {
+		t.Fatalf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := arr.Date64Values(), vs; !reflect.DeepEqual(got, want) {
+		t.Fatalf("got=%v, want=%v", got, want)
+	}
+
+	slice := array.NewSlice(arr, beg, end).(*array.Date64)
+	defer slice.Release()
+
+	if got, want := slice.Len(), len(sub); got != want {
+		t.Fatalf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := slice.Date64Values(), sub; !reflect.DeepEqual(got, want) {
+		t.Fatalf("got=%v, want=%v", got, want)
+	}
+}
+
+func TestDate64SliceDataWithNull(t *testing.T) {
+	pool := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer pool.AssertSize(t, 0)
+
+	const (
+		beg = 2
+		end = 5
+	)
+
+	var (
+		valids = []bool{true, true, true, false, true, true}
+		vs     = []arrow.Date64{1, 2, 3, 0, 4, 5}
+		sub    = vs[beg:end]
+	)
+
+	b := array.NewDate64Builder(pool)
+	defer b.Release()
+
+	b.AppendValues(vs, valids)
+
+	arr := b.NewArray().(*array.Date64)
+	defer arr.Release()
+
+	if got, want := arr.Len(), len(valids); got != want {
+		t.Fatalf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := arr.NullN(), 1; got != want {
+		t.Fatalf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := arr.Date64Values(), vs; !reflect.DeepEqual(got, want) {
+		t.Fatalf("got=%v, want=%v", got, want)
+	}
+
+	slice := array.NewSlice(arr, beg, end).(*array.Date64)
+	defer slice.Release()
+
+	if got, want := slice.NullN(), 1; got != want {
+		t.Errorf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := slice.Len(), len(sub); got != want {
+		t.Fatalf("got=%d, want=%d", got, want)
+	}
+
+	if got, want := slice.Date64Values(), sub; !reflect.DeepEqual(got, want) {
+		t.Fatalf("got=%v, want=%v", got, want)
+	}
+}
diff --git a/go/arrow/array/numericbuilder.gen.go b/go/arrow/array/numericbuilder.gen.go
index 3a7dc16..946c5ba 100644
--- a/go/arrow/array/numericbuilder.gen.go
+++ b/go/arrow/array/numericbuilder.gen.go
@@ -1772,6 +1772,274 @@ func (b *Time64Builder) newData() (data *Data) {
 	return
 }
 
+type Date32Builder struct {
+	builder
+
+	data    *memory.Buffer
+	rawData []arrow.Date32
+}
+
+func NewDate32Builder(mem memory.Allocator) *Date32Builder {
+	return &Date32Builder{builder: builder{refCount: 1, mem: mem}}
+}
+
+// Release decreases the reference count by 1.
+// When the reference count goes to zero, the memory is freed.
+func (b *Date32Builder) Release() {
+	debug.Assert(atomic.LoadInt64(&b.refCount) > 0, "too many releases")
+
+	if atomic.AddInt64(&b.refCount, -1) == 0 {
+		if b.nullBitmap != nil {
+			b.nullBitmap.Release()
+			b.nullBitmap = nil
+		}
+		if b.data != nil {
+			b.data.Release()
+			b.data = nil
+			b.rawData = nil
+		}
+	}
+}
+
+func (b *Date32Builder) Append(v arrow.Date32) {
+	b.Reserve(1)
+	b.UnsafeAppend(v)
+}
+
+func (b *Date32Builder) AppendNull() {
+	b.Reserve(1)
+	b.UnsafeAppendBoolToBitmap(false)
+}
+
+func (b *Date32Builder) UnsafeAppend(v arrow.Date32) {
+	bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
+	b.rawData[b.length] = v
+	b.length++
+}
+
+func (b *Date32Builder) UnsafeAppendBoolToBitmap(isValid bool) {
+	if isValid {
+		bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
+	} else {
+		b.nulls++
+	}
+	b.length++
+}
+
+// AppendValues will append the values in the v slice. The valid slice determines which values
+// in v are valid (not null). The valid slice must either be empty or be equal in length to v. If empty,
+// all values in v are appended and considered valid.
+func (b *Date32Builder) AppendValues(v []arrow.Date32, valid []bool) {
+	if len(v) != len(valid) && len(valid) != 0 {
+		panic("len(v) != len(valid) && len(valid) != 0")
+	}
+
+	b.Reserve(len(v))
+	if len(v) > 0 {
+		arrow.Date32Traits.Copy(b.rawData[b.length:], v)
+	}
+	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
+}
+
+func (b *Date32Builder) init(capacity int) {
+	b.builder.init(capacity)
+
+	b.data = memory.NewResizableBuffer(b.mem)
+	bytesN := arrow.Date32Traits.BytesRequired(capacity)
+	b.data.Resize(bytesN)
+	b.rawData = arrow.Date32Traits.CastFromBytes(b.data.Bytes())
+}
+
+// Reserve ensures there is enough space for appending n elements
+// by checking the capacity and calling Resize if necessary.
+func (b *Date32Builder) Reserve(n int) {
+	b.builder.reserve(n, b.Resize)
+}
+
+// Resize adjusts the space allocated by b to n elements. If n is greater than b.Cap(),
+// additional memory will be allocated. If n is smaller, the allocated memory may reduced.
+func (b *Date32Builder) Resize(n int) {
+	nBuilder := n
+	if n < minBuilderCapacity {
+		n = minBuilderCapacity
+	}
+
+	if b.capacity == 0 {
+		b.init(n)
+	} else {
+		b.builder.resize(nBuilder, b.init)
+		b.data.Resize(arrow.Date32Traits.BytesRequired(n))
+		b.rawData = arrow.Date32Traits.CastFromBytes(b.data.Bytes())
+	}
+}
+
+// NewArray creates a Date32 array from the memory buffers used by the builder and resets the Date32Builder
+// so it can be used to build a new array.
+func (b *Date32Builder) NewArray() Interface {
+	return b.NewDate32Array()
+}
+
+// NewDate32Array creates a Date32 array from the memory buffers used by the builder and resets the Date32Builder
+// so it can be used to build a new array.
+func (b *Date32Builder) NewDate32Array() (a *Date32) {
+	data := b.newData()
+	a = NewDate32Data(data)
+	data.Release()
+	return
+}
+
+func (b *Date32Builder) newData() (data *Data) {
+	bytesRequired := arrow.Date32Traits.BytesRequired(b.length)
+	if bytesRequired > 0 && bytesRequired < b.data.Len() {
+		// trim buffers
+		b.data.Resize(bytesRequired)
+	}
+	data = NewData(arrow.PrimitiveTypes.Date32, b.length, []*memory.Buffer{b.nullBitmap, b.data}, nil, b.nulls, 0)
+	b.reset()
+
+	if b.data != nil {
+		b.data.Release()
+		b.data = nil
+		b.rawData = nil
+	}
+
+	return
+}
+
+type Date64Builder struct {
+	builder
+
+	data    *memory.Buffer
+	rawData []arrow.Date64
+}
+
+func NewDate64Builder(mem memory.Allocator) *Date64Builder {
+	return &Date64Builder{builder: builder{refCount: 1, mem: mem}}
+}
+
+// Release decreases the reference count by 1.
+// When the reference count goes to zero, the memory is freed.
+func (b *Date64Builder) Release() {
+	debug.Assert(atomic.LoadInt64(&b.refCount) > 0, "too many releases")
+
+	if atomic.AddInt64(&b.refCount, -1) == 0 {
+		if b.nullBitmap != nil {
+			b.nullBitmap.Release()
+			b.nullBitmap = nil
+		}
+		if b.data != nil {
+			b.data.Release()
+			b.data = nil
+			b.rawData = nil
+		}
+	}
+}
+
+func (b *Date64Builder) Append(v arrow.Date64) {
+	b.Reserve(1)
+	b.UnsafeAppend(v)
+}
+
+func (b *Date64Builder) AppendNull() {
+	b.Reserve(1)
+	b.UnsafeAppendBoolToBitmap(false)
+}
+
+func (b *Date64Builder) UnsafeAppend(v arrow.Date64) {
+	bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
+	b.rawData[b.length] = v
+	b.length++
+}
+
+func (b *Date64Builder) UnsafeAppendBoolToBitmap(isValid bool) {
+	if isValid {
+		bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
+	} else {
+		b.nulls++
+	}
+	b.length++
+}
+
+// AppendValues will append the values in the v slice. The valid slice determines which values
+// in v are valid (not null). The valid slice must either be empty or be equal in length to v. If empty,
+// all values in v are appended and considered valid.
+func (b *Date64Builder) AppendValues(v []arrow.Date64, valid []bool) {
+	if len(v) != len(valid) && len(valid) != 0 {
+		panic("len(v) != len(valid) && len(valid) != 0")
+	}
+
+	b.Reserve(len(v))
+	if len(v) > 0 {
+		arrow.Date64Traits.Copy(b.rawData[b.length:], v)
+	}
+	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
+}
+
+func (b *Date64Builder) init(capacity int) {
+	b.builder.init(capacity)
+
+	b.data = memory.NewResizableBuffer(b.mem)
+	bytesN := arrow.Date64Traits.BytesRequired(capacity)
+	b.data.Resize(bytesN)
+	b.rawData = arrow.Date64Traits.CastFromBytes(b.data.Bytes())
+}
+
+// Reserve ensures there is enough space for appending n elements
+// by checking the capacity and calling Resize if necessary.
+func (b *Date64Builder) Reserve(n int) {
+	b.builder.reserve(n, b.Resize)
+}
+
+// Resize adjusts the space allocated by b to n elements. If n is greater than b.Cap(),
+// additional memory will be allocated. If n is smaller, the allocated memory may reduced.
+func (b *Date64Builder) Resize(n int) {
+	nBuilder := n
+	if n < minBuilderCapacity {
+		n = minBuilderCapacity
+	}
+
+	if b.capacity == 0 {
+		b.init(n)
+	} else {
+		b.builder.resize(nBuilder, b.init)
+		b.data.Resize(arrow.Date64Traits.BytesRequired(n))
+		b.rawData = arrow.Date64Traits.CastFromBytes(b.data.Bytes())
+	}
+}
+
+// NewArray creates a Date64 array from the memory buffers used by the builder and resets the Date64Builder
+// so it can be used to build a new array.
+func (b *Date64Builder) NewArray() Interface {
+	return b.NewDate64Array()
+}
+
+// NewDate64Array creates a Date64 array from the memory buffers used by the builder and resets the Date64Builder
+// so it can be used to build a new array.
+func (b *Date64Builder) NewDate64Array() (a *Date64) {
+	data := b.newData()
+	a = NewDate64Data(data)
+	data.Release()
+	return
+}
+
+func (b *Date64Builder) newData() (data *Data) {
+	bytesRequired := arrow.Date64Traits.BytesRequired(b.length)
+	if bytesRequired > 0 && bytesRequired < b.data.Len() {
+		// trim buffers
+		b.data.Resize(bytesRequired)
+	}
+	data = NewData(arrow.PrimitiveTypes.Date64, b.length, []*memory.Buffer{b.nullBitmap, b.data}, nil, b.nulls, 0)
+	b.reset()
+
+	if b.data != nil {
+		b.data.Release()
+		b.data = nil
+		b.rawData = nil
+	}
+
+	return
+}
+
 var (
 	_ Builder = (*Int64Builder)(nil)
 	_ Builder = (*Uint64Builder)(nil)
@@ -1786,4 +2054,6 @@ var (
 	_ Builder = (*TimestampBuilder)(nil)
 	_ Builder = (*Time32Builder)(nil)
 	_ Builder = (*Time64Builder)(nil)
+	_ Builder = (*Date32Builder)(nil)
+	_ Builder = (*Date64Builder)(nil)
 )
diff --git a/go/arrow/array/numericbuilder_test.go b/go/arrow/array/numericbuilder_test.go
index 65f3c86..3bb49a3 100644
--- a/go/arrow/array/numericbuilder_test.go
+++ b/go/arrow/array/numericbuilder_test.go
@@ -362,3 +362,223 @@ func TestTime64Builder_Resize(t *testing.T) {
 
 	ab.Release()
 }
+
+func TestNewDate32Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate32Builder(mem)
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewDate32Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewDate32Array()
+
+	// check state of builder after NewDate32Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewDate32Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewDate32Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewDate32Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []arrow.Date32{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Date32Values(), "unexpected Date32Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Date32Values(), 10, "unexpected length of Date32Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewDate32Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []arrow.Date32{7, 8}, a.Date32Values())
+	assert.Len(t, a.Date32Values(), 2)
+
+	a.Release()
+}
+
+func TestDate32Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate32Builder(mem)
+
+	exp := []arrow.Date32{1, 2, 3, 4}
+	ab.AppendValues(exp, nil)
+	a := ab.NewDate32Array()
+	assert.Equal(t, exp, a.Date32Values())
+
+	a.Release()
+	ab.Release()
+}
+
+func TestDate32Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate32Builder(mem)
+
+	exp := []arrow.Date32{1, 2, 3, 4}
+	ab.AppendValues(exp, nil)
+	a := ab.NewDate32Array()
+	assert.Equal(t, exp, a.Date32Values())
+	a.Release()
+
+	a = ab.NewDate32Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.Release()
+}
+
+func TestDate32Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate32Builder(mem)
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Release()
+}
+
+func TestNewDate64Builder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate64Builder(mem)
+
+	ab.Append(1)
+	ab.Append(2)
+	ab.Append(3)
+	ab.AppendNull()
+	ab.Append(5)
+	ab.Append(6)
+	ab.AppendNull()
+	ab.Append(8)
+	ab.Append(9)
+	ab.Append(10)
+
+	// check state of builder before NewDate64Array
+	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewDate64Array()
+
+	// check state of builder after NewDate64Array
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewDate64Array did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewDate64Array did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewDate64Array did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []arrow.Date64{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.Date64Values(), "unexpected Date64Values")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.Date64Values(), 10, "unexpected length of Date64Values")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewDate64Array()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []arrow.Date64{7, 8}, a.Date64Values())
+	assert.Len(t, a.Date64Values(), 2)
+
+	a.Release()
+}
+
+func TestDate64Builder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate64Builder(mem)
+
+	exp := []arrow.Date64{1, 2, 3, 4}
+	ab.AppendValues(exp, nil)
+	a := ab.NewDate64Array()
+	assert.Equal(t, exp, a.Date64Values())
+
+	a.Release()
+	ab.Release()
+}
+
+func TestDate64Builder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate64Builder(mem)
+
+	exp := []arrow.Date64{1, 2, 3, 4}
+	ab.AppendValues(exp, nil)
+	a := ab.NewDate64Array()
+	assert.Equal(t, exp, a.Date64Values())
+	a.Release()
+
+	a = ab.NewDate64Array()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.Release()
+}
+
+func TestDate64Builder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	ab := array.NewDate64Builder(mem)
+
+	assert.Equal(t, 0, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	ab.Reserve(63)
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 0, ab.Len())
+
+	for i := 0; i < 63; i++ {
+		ab.Append(0)
+	}
+	assert.Equal(t, 64, ab.Cap())
+	assert.Equal(t, 63, ab.Len())
+
+	ab.Resize(5)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Resize(32)
+	assert.Equal(t, 5, ab.Len())
+
+	ab.Release()
+}
diff --git a/go/arrow/datatype_fixedwidth.go b/go/arrow/datatype_fixedwidth.go
index 60cc98a..4444950 100644
--- a/go/arrow/datatype_fixedwidth.go
+++ b/go/arrow/datatype_fixedwidth.go
@@ -37,6 +37,8 @@ type (
 	Time32    int32
 	Time64    int64
 	TimeUnit  int
+	Date32    int32
+	Date64    int64
 )
 
 const (
diff --git a/go/arrow/datatype_numeric.gen.go b/go/arrow/datatype_numeric.gen.go
index 2ec4c40..9b5dc83 100644
--- a/go/arrow/datatype_numeric.gen.go
+++ b/go/arrow/datatype_numeric.gen.go
@@ -78,6 +78,18 @@ func (t *Float64Type) ID() Type      { return FLOAT64 }
 func (t *Float64Type) Name() string  { return "float64" }
 func (t *Float64Type) BitWidth() int { return 64 }
 
+type Date32Type struct{}
+
+func (t *Date32Type) ID() Type      { return DATE32 }
+func (t *Date32Type) Name() string  { return "date32" }
+func (t *Date32Type) BitWidth() int { return 32 }
+
+type Date64Type struct{}
+
+func (t *Date64Type) ID() Type      { return DATE64 }
+func (t *Date64Type) Name() string  { return "date64" }
+func (t *Date64Type) BitWidth() int { return 64 }
+
 var (
 	PrimitiveTypes = struct {
 		Int8    DataType
@@ -90,6 +102,8 @@ var (
 		Uint64  DataType
 		Float32 DataType
 		Float64 DataType
+		Date32  DataType
+		Date64  DataType
 	}{
 
 		Int8:    &Int8Type{},
@@ -102,5 +116,7 @@ var (
 		Uint64:  &Uint64Type{},
 		Float32: &Float32Type{},
 		Float64: &Float64Type{},
+		Date32:  &Date32Type{},
+		Date64:  &Date64Type{},
 	}
 )
diff --git a/go/arrow/datatype_numeric.gen.go.tmpldata b/go/arrow/datatype_numeric.gen.go.tmpldata
index 415b51b..9badc6e 100644
--- a/go/arrow/datatype_numeric.gen.go.tmpldata
+++ b/go/arrow/datatype_numeric.gen.go.tmpldata
@@ -48,5 +48,15 @@
     "Name": "Float64",
     "Type": "float64",
     "Size": 64
+  },
+  {
+    "Name": "Date32",
+    "Type": "date32",
+    "Size": 32
+  },
+  {
+    "Name": "Date64",
+    "Type": "date64",
+    "Size": 64
   }
 ]
diff --git a/go/arrow/numeric.tmpldata b/go/arrow/numeric.tmpldata
index b9e976e..45452ab 100644
--- a/go/arrow/numeric.tmpldata
+++ b/go/arrow/numeric.tmpldata
@@ -107,5 +107,23 @@
     "Opt": {
       "Parametric": true
     }
+  },
+  {
+    "Name": "Date32",
+    "name": "date32",
+    "Type": "Date32",
+    "QualifiedType": "arrow.Date32",
+    "InternalType": "int32",
+    "Default": "0",
+    "Size": "4"
+  },
+  {
+    "Name": "Date64",
+    "name": "date64",
+    "Type": "Date64",
+    "QualifiedType": "arrow.Date64",
+    "InternalType": "int64",
+    "Default": "0",
+    "Size": "8"
   }
-]
\ No newline at end of file
+]
diff --git a/go/arrow/type_traits_numeric.gen.go b/go/arrow/type_traits_numeric.gen.go
index 59ed13f..14fafbc 100644
--- a/go/arrow/type_traits_numeric.gen.go
+++ b/go/arrow/type_traits_numeric.gen.go
@@ -38,6 +38,8 @@ var (
 	TimestampTraits timestampTraits
 	Time32Traits    time32Traits
 	Time64Traits    time64Traits
+	Date32Traits    date32Traits
+	Date64Traits    date64Traits
 )
 
 // Int64 traits
@@ -663,3 +665,99 @@ func (time64Traits) CastToBytes(b []Time64) []byte {
 
 // Copy copies src to dst.
 func (time64Traits) Copy(dst, src []Time64) { copy(dst, src) }
+
+// Date32 traits
+
+const (
+	// Date32SizeBytes specifies the number of bytes required to store a single Date32 in memory
+	Date32SizeBytes = int(unsafe.Sizeof(Date32(0)))
+)
+
+type date32Traits struct{}
+
+// BytesRequired returns the number of bytes required to store n elements in memory.
+func (date32Traits) BytesRequired(n int) int { return Date32SizeBytes * n }
+
+// PutValue
+func (date32Traits) PutValue(b []byte, v Date32) {
+	binary.LittleEndian.PutUint32(b, uint32(v))
+}
+
+// CastFromBytes reinterprets the slice b to a slice of type Date32.
+//
+// NOTE: len(b) must be a multiple of Date32SizeBytes.
+func (date32Traits) CastFromBytes(b []byte) []Date32 {
+	h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+
+	var res []Date32
+	s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
+	s.Data = h.Data
+	s.Len = h.Len / Date32SizeBytes
+	s.Cap = h.Cap / Date32SizeBytes
+
+	return res
+}
+
+// CastToBytes reinterprets the slice b to a slice of bytes.
+func (date32Traits) CastToBytes(b []Date32) []byte {
+	h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+
+	var res []byte
+	s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
+	s.Data = h.Data
+	s.Len = h.Len * Date32SizeBytes
+	s.Cap = h.Cap * Date32SizeBytes
+
+	return res
+}
+
+// Copy copies src to dst.
+func (date32Traits) Copy(dst, src []Date32) { copy(dst, src) }
+
+// Date64 traits
+
+const (
+	// Date64SizeBytes specifies the number of bytes required to store a single Date64 in memory
+	Date64SizeBytes = int(unsafe.Sizeof(Date64(0)))
+)
+
+type date64Traits struct{}
+
+// BytesRequired returns the number of bytes required to store n elements in memory.
+func (date64Traits) BytesRequired(n int) int { return Date64SizeBytes * n }
+
+// PutValue
+func (date64Traits) PutValue(b []byte, v Date64) {
+	binary.LittleEndian.PutUint64(b, uint64(v))
+}
+
+// CastFromBytes reinterprets the slice b to a slice of type Date64.
+//
+// NOTE: len(b) must be a multiple of Date64SizeBytes.
+func (date64Traits) CastFromBytes(b []byte) []Date64 {
+	h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+
+	var res []Date64
+	s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
+	s.Data = h.Data
+	s.Len = h.Len / Date64SizeBytes
+	s.Cap = h.Cap / Date64SizeBytes
+
+	return res
+}
+
+// CastToBytes reinterprets the slice b to a slice of bytes.
+func (date64Traits) CastToBytes(b []Date64) []byte {
+	h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+
+	var res []byte
+	s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
+	s.Data = h.Data
+	s.Len = h.Len * Date64SizeBytes
+	s.Cap = h.Cap * Date64SizeBytes
+
+	return res
+}
+
+// Copy copies src to dst.
+func (date64Traits) Copy(dst, src []Date64) { copy(dst, src) }