You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ze...@apache.org on 2023/05/25 14:20:37 UTC

[arrow] branch main updated: GH-35686:[Go] Add AppendTime to TimestampBuilder (#35687)

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.git


The following commit(s) were added to refs/heads/main by this push:
     new 2d32efeeda GH-35686:[Go] Add AppendTime to TimestampBuilder (#35687)
2d32efeeda is described below

commit 2d32efeedad88743dd635ff562c65e072cfb44f7
Author: Yevgeny Pats <ye...@gmail.com>
AuthorDate: Thu May 25 17:20:29 2023 +0300

    GH-35686:[Go] Add AppendTime to TimestampBuilder (#35687)
    
    
    
    ### Rationale for this change
    
    ### What changes are included in this PR?
    
    ### Are these changes tested?
    
    ### Are there any user-facing changes?
    
    * Closes: #35686
    
    Lead-authored-by: candiduslynx <ca...@gmail.com>
    Co-authored-by: Yevgeny Pats <16...@users.noreply.github.com>
    Signed-off-by: Matt Topol <zo...@gmail.com>
---
 go/arrow/_tools/tmpl/main.go              |   2 +-
 go/arrow/array/numeric.gen.go             |  90 --------
 go/arrow/array/numeric.gen.go.tmpl        |   8 +-
 go/arrow/array/numericbuilder.gen.go      | 229 -------------------
 go/arrow/array/numericbuilder.gen.go.tmpl |  14 +-
 go/arrow/array/numericbuilder.gen_test.go | 207 -----------------
 go/arrow/array/timestamp.go               | 360 ++++++++++++++++++++++++++++++
 go/arrow/array/timestamp_test.go          | 235 +++++++++++++++++++
 go/arrow/datatype_fixedwidth.go           |  39 ++--
 go/arrow/numeric.tmpldata                 |  12 -
 go/arrow/type_traits_numeric.gen.go       |  79 ++-----
 go/arrow/type_traits_numeric.gen_test.go  |  34 ---
 go/arrow/type_traits_test.go              |  35 +++
 go/arrow/type_traits_timestamp.go         |  71 ++++++
 14 files changed, 743 insertions(+), 672 deletions(-)

diff --git a/go/arrow/_tools/tmpl/main.go b/go/arrow/_tools/tmpl/main.go
index 0cabef3db2..436d48fb63 100644
--- a/go/arrow/_tools/tmpl/main.go
+++ b/go/arrow/_tools/tmpl/main.go
@@ -180,7 +180,7 @@ func process(data interface{}, specs []pathSpec) {
 			}
 		}
 
-		ioutil.WriteFile(spec.out, generated, fileMode(spec.in))
+		os.WriteFile(spec.out, generated, fileMode(spec.in))
 	}
 }
 
diff --git a/go/arrow/array/numeric.gen.go b/go/arrow/array/numeric.gen.go
index 1849d6531b..aa14ca0ea2 100644
--- a/go/arrow/array/numeric.gen.go
+++ b/go/arrow/array/numeric.gen.go
@@ -977,96 +977,6 @@ func arrayEqualUint8(left, right *Uint8) bool {
 	return true
 }
 
-// A type which represents an immutable sequence of arrow.Timestamp values.
-type Timestamp struct {
-	array
-	values []arrow.Timestamp
-}
-
-// NewTimestampData creates a new Timestamp.
-func NewTimestampData(data arrow.ArrayData) *Timestamp {
-	a := &Timestamp{}
-	a.refCount = 1
-	a.setData(data.(*Data))
-	return a
-}
-
-// Reset resets the array for re-use.
-func (a *Timestamp) Reset(data *Data) {
-	a.setData(data)
-}
-
-// Value returns the value at the specified index.
-func (a *Timestamp) Value(i int) arrow.Timestamp { return a.values[i] }
-
-// Values returns the values.
-func (a *Timestamp) TimestampValues() []arrow.Timestamp { return a.values }
-
-// String returns a string representation of the array.
-func (a *Timestamp) 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(NullValueStr)
-		default:
-			fmt.Fprintf(o, "%v", v)
-		}
-	}
-	o.WriteString("]")
-	return o.String()
-}
-
-func (a *Timestamp) setData(data *Data) {
-	a.array.setData(data)
-	vals := data.buffers[1]
-	if vals != nil {
-		a.values = arrow.TimestampTraits.CastFromBytes(vals.Bytes())
-		beg := a.array.data.offset
-		end := beg + a.array.data.length
-		a.values = a.values[beg:end]
-	}
-}
-
-func (a *Timestamp) ValueStr(i int) string {
-	if a.IsNull(i) {
-		return NullValueStr
-	}
-	return a.values[i].ToTime(a.DataType().(*arrow.TimestampType).Unit).Format("2006-01-02 15:04:05.999999999")
-}
-
-func (a *Timestamp) GetOneForMarshal(i int) interface{} {
-	if a.IsNull(i) {
-		return nil
-	}
-	return a.values[i].ToTime(a.DataType().(*arrow.TimestampType).Unit).Format("2006-01-02 15:04:05.999999999")
-}
-
-func (a *Timestamp) MarshalJSON() ([]byte, error) {
-	vals := make([]interface{}, a.Len())
-	for i := range a.values {
-		vals[i] = a.GetOneForMarshal(i)
-	}
-
-	return json.Marshal(vals)
-}
-
-func arrayEqualTimestamp(left, right *Timestamp) bool {
-	for i := 0; i < left.Len(); i++ {
-		if left.IsNull(i) {
-			continue
-		}
-		if left.Value(i) != right.Value(i) {
-			return false
-		}
-	}
-	return true
-}
-
 // A type which represents an immutable sequence of arrow.Time32 values.
 type Time32 struct {
 	array
diff --git a/go/arrow/array/numeric.gen.go.tmpl b/go/arrow/array/numeric.gen.go.tmpl
index adece058b8..b141276d75 100644
--- a/go/arrow/array/numeric.gen.go.tmpl
+++ b/go/arrow/array/numeric.gen.go.tmpl
@@ -90,9 +90,7 @@ func (a *{{.Name}}) ValueStr(i int) string {
   return a.values[i].FormattedString()
 {{else if or (eq .Name "Time32") (eq .Name "Time64") -}}
   return a.values[i].FormattedString(a.DataType().(*{{.QualifiedType}}Type).Unit)
-{{else if or (eq .Name "Timestamp") -}}
-	return a.values[i].ToTime(a.DataType().(*{{.QualifiedType}}Type).Unit).Format("2006-01-02 15:04:05.999999999")
-{{else if (eq .Name "Duration") -}}	
+{{else if (eq .Name "Duration") -}}
 	// return value and suffix as a string such as "12345ms"
 	return fmt.Sprintf("%d%s", a.values[i], a.DataType().(*{{.QualifiedType}}Type).Unit)	
 {{else if or (eq .Name "Int8") (eq .Name "Int16") (eq .Name "Int32") (eq .Name "Int64") -}}
@@ -116,9 +114,7 @@ func (a *{{.Name}}) GetOneForMarshal(i int) interface{} {
 	return a.values[i].ToTime().Format("2006-01-02")
 {{else if or (eq .Name "Time32") (eq .Name "Time64") -}}
 	return a.values[i].ToTime(a.DataType().(*{{.QualifiedType}}Type).Unit).Format("15:04:05.999999999")
-{{else if or (eq .Name "Timestamp") -}}
-	return a.values[i].ToTime(a.DataType().(*{{.QualifiedType}}Type).Unit).Format("2006-01-02 15:04:05.999999999")
-{{else if (eq .Name "Duration") -}}	
+{{else if (eq .Name "Duration") -}}
 	// return value and suffix as a string such as "12345ms"
 	return fmt.Sprintf("%d%s", a.values[i], a.DataType().(*{{.QualifiedType}}Type).Unit.String())	
 {{else if (eq .Size "1")}}
diff --git a/go/arrow/array/numericbuilder.gen.go b/go/arrow/array/numericbuilder.gen.go
index 17fee6688a..b76a7292d7 100644
--- a/go/arrow/array/numericbuilder.gen.go
+++ b/go/arrow/array/numericbuilder.gen.go
@@ -2264,232 +2264,6 @@ func (b *Uint8Builder) UnmarshalJSON(data []byte) error {
 	return b.Unmarshal(dec)
 }
 
-type TimestampBuilder struct {
-	builder
-
-	dtype   *arrow.TimestampType
-	data    *memory.Buffer
-	rawData []arrow.Timestamp
-}
-
-func NewTimestampBuilder(mem memory.Allocator, dtype *arrow.TimestampType) *TimestampBuilder {
-	return &TimestampBuilder{builder: builder{refCount: 1, mem: mem}, dtype: dtype}
-}
-
-func (b *TimestampBuilder) Type() arrow.DataType { return b.dtype }
-
-// Release decreases the reference count by 1.
-// When the reference count goes to zero, the memory is freed.
-func (b *TimestampBuilder) 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 *TimestampBuilder) Append(v arrow.Timestamp) {
-	b.Reserve(1)
-	b.UnsafeAppend(v)
-}
-
-func (b *TimestampBuilder) AppendNull() {
-	b.Reserve(1)
-	b.UnsafeAppendBoolToBitmap(false)
-}
-
-func (b *TimestampBuilder) AppendEmptyValue() {
-	b.Append(0)
-}
-
-func (b *TimestampBuilder) UnsafeAppend(v arrow.Timestamp) {
-	bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
-	b.rawData[b.length] = v
-	b.length++
-}
-
-func (b *TimestampBuilder) 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 *TimestampBuilder) AppendValues(v []arrow.Timestamp, valid []bool) {
-	if len(v) != len(valid) && len(valid) != 0 {
-		panic("len(v) != len(valid) && len(valid) != 0")
-	}
-
-	if len(v) == 0 {
-		return
-	}
-
-	b.Reserve(len(v))
-	arrow.TimestampTraits.Copy(b.rawData[b.length:], v)
-	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
-}
-
-func (b *TimestampBuilder) init(capacity int) {
-	b.builder.init(capacity)
-
-	b.data = memory.NewResizableBuffer(b.mem)
-	bytesN := arrow.TimestampTraits.BytesRequired(capacity)
-	b.data.Resize(bytesN)
-	b.rawData = arrow.TimestampTraits.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 *TimestampBuilder) 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 *TimestampBuilder) 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.TimestampTraits.BytesRequired(n))
-		b.rawData = arrow.TimestampTraits.CastFromBytes(b.data.Bytes())
-	}
-}
-
-// NewArray creates a Timestamp array from the memory buffers used by the builder and resets the TimestampBuilder
-// so it can be used to build a new array.
-func (b *TimestampBuilder) NewArray() arrow.Array {
-	return b.NewTimestampArray()
-}
-
-// NewTimestampArray creates a Timestamp array from the memory buffers used by the builder and resets the TimestampBuilder
-// so it can be used to build a new array.
-func (b *TimestampBuilder) NewTimestampArray() (a *Timestamp) {
-	data := b.newData()
-	a = NewTimestampData(data)
-	data.Release()
-	return
-}
-
-func (b *TimestampBuilder) newData() (data *Data) {
-	bytesRequired := arrow.TimestampTraits.BytesRequired(b.length)
-	if bytesRequired > 0 && bytesRequired < b.data.Len() {
-		// trim buffers
-		b.data.Resize(bytesRequired)
-	}
-	data = NewData(b.dtype, 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
-}
-
-func (b *TimestampBuilder) AppendValueFromString(s string) error {
-	if s == NullValueStr {
-		b.AppendNull()
-		return nil
-	}
-	v, err := arrow.TimestampFromString(s, b.dtype.Unit)
-	if err != nil {
-		b.AppendNull()
-		return err
-	}
-	b.Append(v)
-	return nil
-}
-
-func (b *TimestampBuilder) UnmarshalOne(dec *json.Decoder) error {
-	t, err := dec.Token()
-	if err != nil {
-		return err
-	}
-
-	switch v := t.(type) {
-	case nil:
-		b.AppendNull()
-	case string:
-		loc, _ := b.dtype.GetZone()
-		tm, _, err := arrow.TimestampFromStringInLocation(v, b.dtype.Unit, loc)
-
-		if err != nil {
-			return &json.UnmarshalTypeError{
-				Value:  v,
-				Type:   reflect.TypeOf(arrow.Timestamp(0)),
-				Offset: dec.InputOffset(),
-			}
-		}
-
-		b.Append(tm)
-	case json.Number:
-		n, err := v.Int64()
-		if err != nil {
-			return &json.UnmarshalTypeError{
-				Value:  v.String(),
-				Type:   reflect.TypeOf(arrow.Timestamp(0)),
-				Offset: dec.InputOffset(),
-			}
-		}
-		b.Append(arrow.Timestamp(n))
-	case float64:
-		b.Append(arrow.Timestamp(v))
-
-	default:
-		return &json.UnmarshalTypeError{
-			Value:  fmt.Sprint(t),
-			Type:   reflect.TypeOf(arrow.Timestamp(0)),
-			Offset: dec.InputOffset(),
-		}
-	}
-
-	return nil
-}
-
-func (b *TimestampBuilder) Unmarshal(dec *json.Decoder) error {
-	for dec.More() {
-		if err := b.UnmarshalOne(dec); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-func (b *TimestampBuilder) UnmarshalJSON(data []byte) error {
-	dec := json.NewDecoder(bytes.NewReader(data))
-	t, err := dec.Token()
-	if err != nil {
-		return err
-	}
-
-	if delim, ok := t.(json.Delim); !ok || delim != '[' {
-		return fmt.Errorf("binary builder must unpack from json array, found %s", delim)
-	}
-
-	return b.Unmarshal(dec)
-}
-
 type Time32Builder struct {
 	builder
 
@@ -2658,7 +2432,6 @@ func (b *Time32Builder) UnmarshalOne(dec *json.Decoder) error {
 		b.AppendNull()
 	case string:
 		tm, err := arrow.Time32FromString(v, b.dtype.Unit)
-
 		if err != nil {
 			return &json.UnmarshalTypeError{
 				Value:  v,
@@ -2883,7 +2656,6 @@ func (b *Time64Builder) UnmarshalOne(dec *json.Decoder) error {
 		b.AppendNull()
 	case string:
 		tm, err := arrow.Time64FromString(v, b.dtype.Unit)
-
 		if err != nil {
 			return &json.UnmarshalTypeError{
 				Value:  v,
@@ -3644,7 +3416,6 @@ var (
 	_ Builder = (*Uint16Builder)(nil)
 	_ Builder = (*Int8Builder)(nil)
 	_ Builder = (*Uint8Builder)(nil)
-	_ Builder = (*TimestampBuilder)(nil)
 	_ Builder = (*Time32Builder)(nil)
 	_ Builder = (*Time64Builder)(nil)
 	_ Builder = (*Date32Builder)(nil)
diff --git a/go/arrow/array/numericbuilder.gen.go.tmpl b/go/arrow/array/numericbuilder.gen.go.tmpl
index d18829b2f0..6eb12b5aeb 100644
--- a/go/arrow/array/numericbuilder.gen.go.tmpl
+++ b/go/arrow/array/numericbuilder.gen.go.tmpl
@@ -217,13 +217,6 @@ func (b *{{.Name}}Builder) AppendValueFromString(s string) error {
       return err
     }
     b.Append(val)
-  {{else if or (eq .Name "Timestamp") -}}
-  	v, err := arrow.TimestampFromString(s, b.dtype.Unit)
-    if err != nil {
-      b.AppendNull()
-      return err
-    }
-    b.Append(v)
   {{else if (eq .Name "Duration") -}}
 	dur, err := time.ParseDuration(s)
 	if err != nil {
@@ -289,14 +282,9 @@ func (b *{{.Name}}Builder) UnmarshalOne(dec *json.Decoder) error {
 		b.Append({{.QualifiedType}}(n))
 	case float64:
 		b.Append({{.QualifiedType}}(v))
-{{else if or (eq .Name "Time32") (eq .Name "Time64") (eq .Name "Timestamp") -}}
+{{else if or (eq .Name "Time32") (eq .Name "Time64") -}}
 	case string:
-{{if (eq .Name "Timestamp") -}}
-		loc, _ := b.dtype.GetZone()
-		tm, _, err := arrow.TimestampFromStringInLocation(v, b.dtype.Unit, loc)
-{{else -}}
 		tm, err := {{.QualifiedType}}FromString(v, b.dtype.Unit)
-{{end}}
 		if err != nil {
 			return &json.UnmarshalTypeError{
 				Value: v,
diff --git a/go/arrow/array/numericbuilder.gen_test.go b/go/arrow/array/numericbuilder.gen_test.go
index 90c5a7f452..246d3a7cda 100644
--- a/go/arrow/array/numericbuilder.gen_test.go
+++ b/go/arrow/array/numericbuilder.gen_test.go
@@ -2047,213 +2047,6 @@ func TestUint8Builder_Resize(t *testing.T) {
 	assert.Equal(t, 5, ab.Len())
 }
 
-func TestTimestampStringRoundTrip(t *testing.T) {
-	// 1. create array
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dt := &arrow.TimestampType{Unit: arrow.Second}
-	b := array.NewTimestampBuilder(mem, dt)
-	defer b.Release()
-
-	b.Append(1)
-	b.Append(2)
-	b.Append(3)
-	b.AppendNull()
-	b.Append(5)
-	b.Append(6)
-	b.AppendNull()
-	b.Append(8)
-	b.Append(9)
-	b.Append(10)
-
-	arr := b.NewArray().(*array.Timestamp)
-	defer arr.Release()
-
-	// 2. create array via AppendValueFromString
-	b1 := array.NewTimestampBuilder(mem, dt)
-	defer b1.Release()
-
-	for i := 0; i < arr.Len(); i++ {
-		assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
-	}
-
-	arr1 := b1.NewArray().(*array.Timestamp)
-	defer arr1.Release()
-
-	assert.True(t, array.Equal(arr, arr1))
-}
-
-func TestNewTimestampBuilder(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.TimestampType{Unit: arrow.Second}
-	ab := array.NewTimestampBuilder(mem, dtype)
-	defer ab.Release()
-
-	ab.Retain()
-	ab.Release()
-
-	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 NewTimestampArray
-	assert.Equal(t, 10, ab.Len(), "unexpected Len()")
-	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
-
-	a := ab.NewTimestampArray()
-
-	// check state of builder after NewTimestampArray
-	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewTimestampArray did not reset state")
-	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewTimestampArray did not reset state")
-	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewTimestampArray did not reset state")
-
-	// check state of array
-	assert.Equal(t, 2, a.NullN(), "unexpected null count")
-	assert.Equal(t, []arrow.Timestamp{1, 2, 3, 0, 5, 6, 0, 8, 9, 10}, a.TimestampValues(), "unexpected TimestampValues")
-	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
-	assert.Len(t, a.TimestampValues(), 10, "unexpected length of TimestampValues")
-
-	a.Release()
-
-	ab.Append(7)
-	ab.Append(8)
-
-	a = ab.NewTimestampArray()
-
-	assert.Equal(t, 0, a.NullN())
-	assert.Equal(t, []arrow.Timestamp{7, 8}, a.TimestampValues())
-	assert.Len(t, a.TimestampValues(), 2)
-
-	a.Release()
-
-	var (
-		want   = []arrow.Timestamp{1, 2, 3, 4}
-		valids = []bool{true, true, false, true}
-	)
-
-	ab.AppendValues(want, valids)
-	a = ab.NewTimestampArray()
-
-	sub := array.MakeFromData(a.Data())
-	defer sub.Release()
-
-	if got, want := sub.DataType().ID(), a.DataType().ID(); got != want {
-		t.Fatalf("invalid type: got=%q, want=%q", got, want)
-	}
-
-	if _, ok := sub.(*array.Timestamp); !ok {
-		t.Fatalf("could not type-assert to array.Timestamp")
-	}
-
-	if got, want := a.String(), `[1 2 (null) 4]`; got != want {
-		t.Fatalf("got=%q, want=%q", got, want)
-	}
-
-	slice := array.NewSliceData(a.Data(), 2, 4)
-	defer slice.Release()
-
-	sub1 := array.MakeFromData(slice)
-	defer sub1.Release()
-
-	v, ok := sub1.(*array.Timestamp)
-	if !ok {
-		t.Fatalf("could not type-assert to array.Timestamp")
-	}
-
-	if got, want := v.String(), `[(null) 4]`; got != want {
-		t.Fatalf("got=%q, want=%q", got, want)
-	}
-
-	a.Release()
-}
-
-func TestTimestampBuilder_AppendValues(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.TimestampType{Unit: arrow.Second}
-	ab := array.NewTimestampBuilder(mem, dtype)
-	defer ab.Release()
-
-	exp := []arrow.Timestamp{0, 1, 2, 3}
-	ab.AppendValues(exp, nil)
-	a := ab.NewTimestampArray()
-	assert.Equal(t, exp, a.TimestampValues())
-
-	a.Release()
-}
-
-func TestTimestampBuilder_Empty(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.TimestampType{Unit: arrow.Second}
-	ab := array.NewTimestampBuilder(mem, dtype)
-	defer ab.Release()
-
-	exp := []arrow.Timestamp{0, 1, 2, 3}
-
-	ab.AppendValues([]arrow.Timestamp{}, nil)
-	a := ab.NewTimestampArray()
-	assert.Zero(t, a.Len())
-	a.Release()
-
-	ab.AppendValues(nil, nil)
-	a = ab.NewTimestampArray()
-	assert.Zero(t, a.Len())
-	a.Release()
-
-	ab.AppendValues([]arrow.Timestamp{}, nil)
-	ab.AppendValues(exp, nil)
-	a = ab.NewTimestampArray()
-	assert.Equal(t, exp, a.TimestampValues())
-	a.Release()
-
-	ab.AppendValues(exp, nil)
-	ab.AppendValues([]arrow.Timestamp{}, nil)
-	a = ab.NewTimestampArray()
-	assert.Equal(t, exp, a.TimestampValues())
-	a.Release()
-}
-
-func TestTimestampBuilder_Resize(t *testing.T) {
-	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
-	defer mem.AssertSize(t, 0)
-
-	dtype := &arrow.TimestampType{Unit: arrow.Second}
-	ab := array.NewTimestampBuilder(mem, dtype)
-	defer ab.Release()
-
-	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())
-}
-
 func TestTime32StringRoundTrip(t *testing.T) {
 	// 1. create array
 	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
diff --git a/go/arrow/array/timestamp.go b/go/arrow/array/timestamp.go
new file mode 100644
index 0000000000..b508006274
--- /dev/null
+++ b/go/arrow/array/timestamp.go
@@ -0,0 +1,360 @@
+// 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
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"strings"
+	"sync/atomic"
+	"time"
+
+	"github.com/apache/arrow/go/v13/arrow"
+	"github.com/apache/arrow/go/v13/arrow/bitutil"
+	"github.com/apache/arrow/go/v13/arrow/internal/debug"
+	"github.com/apache/arrow/go/v13/arrow/memory"
+	"github.com/goccy/go-json"
+)
+
+// Timestamp represents an immutable sequence of arrow.Timestamp values.
+type Timestamp struct {
+	array
+	values []arrow.Timestamp
+}
+
+// NewTimestampData creates a new Timestamp from Data.
+func NewTimestampData(data arrow.ArrayData) *Timestamp {
+	a := &Timestamp{}
+	a.refCount = 1
+	a.setData(data.(*Data))
+	return a
+}
+
+// Reset resets the array for re-use.
+func (a *Timestamp) Reset(data *Data) {
+	a.setData(data)
+}
+
+// Value returns the value at the specified index.
+func (a *Timestamp) Value(i int) arrow.Timestamp { return a.values[i] }
+
+// TimestampValues returns the values.
+func (a *Timestamp) TimestampValues() []arrow.Timestamp { return a.values }
+
+// String returns a string representation of the array.
+func (a *Timestamp) 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(NullValueStr)
+		default:
+			fmt.Fprintf(o, "%v", v)
+		}
+	}
+	o.WriteString("]")
+	return o.String()
+}
+
+func (a *Timestamp) setData(data *Data) {
+	a.array.setData(data)
+	vals := data.buffers[1]
+	if vals != nil {
+		a.values = arrow.TimestampTraits.CastFromBytes(vals.Bytes())
+		beg := a.array.data.offset
+		end := beg + a.array.data.length
+		a.values = a.values[beg:end]
+	}
+}
+
+func (a *Timestamp) ValueStr(i int) string {
+	if a.IsNull(i) {
+		return NullValueStr
+	}
+	return a.values[i].ToTime(a.DataType().(*arrow.TimestampType).Unit).Format("2006-01-02 15:04:05.999999999")
+}
+
+func (a *Timestamp) GetOneForMarshal(i int) interface{} {
+	if a.IsNull(i) {
+		return nil
+	}
+	return a.values[i].ToTime(a.DataType().(*arrow.TimestampType).Unit).Format("2006-01-02 15:04:05.999999999")
+}
+
+func (a *Timestamp) MarshalJSON() ([]byte, error) {
+	vals := make([]interface{}, a.Len())
+	for i := range a.values {
+		vals[i] = a.GetOneForMarshal(i)
+	}
+
+	return json.Marshal(vals)
+}
+
+func arrayEqualTimestamp(left, right *Timestamp) bool {
+	for i := 0; i < left.Len(); i++ {
+		if left.IsNull(i) {
+			continue
+		}
+		if left.Value(i) != right.Value(i) {
+			return false
+		}
+	}
+	return true
+}
+
+type TimestampBuilder struct {
+	builder
+
+	dtype   *arrow.TimestampType
+	data    *memory.Buffer
+	rawData []arrow.Timestamp
+}
+
+func NewTimestampBuilder(mem memory.Allocator, dtype *arrow.TimestampType) *TimestampBuilder {
+	return &TimestampBuilder{builder: builder{refCount: 1, mem: mem}, dtype: dtype}
+}
+
+func (b *TimestampBuilder) Type() arrow.DataType { return b.dtype }
+
+// Release decreases the reference count by 1.
+// When the reference count goes to zero, the memory is freed.
+func (b *TimestampBuilder) 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 *TimestampBuilder) AppendTime(t time.Time) {
+	ts, err := arrow.TimestampFromTime(t, b.dtype.Unit)
+	if err != nil {
+		panic(err)
+	}
+	b.Append(ts)
+}
+
+func (b *TimestampBuilder) Append(v arrow.Timestamp) {
+	b.Reserve(1)
+	b.UnsafeAppend(v)
+}
+
+func (b *TimestampBuilder) AppendNull() {
+	b.Reserve(1)
+	b.UnsafeAppendBoolToBitmap(false)
+}
+
+func (b *TimestampBuilder) AppendEmptyValue() {
+	b.Append(0)
+}
+
+func (b *TimestampBuilder) UnsafeAppend(v arrow.Timestamp) {
+	bitutil.SetBit(b.nullBitmap.Bytes(), b.length)
+	b.rawData[b.length] = v
+	b.length++
+}
+
+func (b *TimestampBuilder) 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 *TimestampBuilder) AppendValues(v []arrow.Timestamp, valid []bool) {
+	if len(v) != len(valid) && len(valid) != 0 {
+		panic("len(v) != len(valid) && len(valid) != 0")
+	}
+
+	if len(v) == 0 {
+		return
+	}
+
+	b.Reserve(len(v))
+	arrow.TimestampTraits.Copy(b.rawData[b.length:], v)
+	b.builder.unsafeAppendBoolsToBitmap(valid, len(v))
+}
+
+func (b *TimestampBuilder) init(capacity int) {
+	b.builder.init(capacity)
+
+	b.data = memory.NewResizableBuffer(b.mem)
+	bytesN := arrow.TimestampTraits.BytesRequired(capacity)
+	b.data.Resize(bytesN)
+	b.rawData = arrow.TimestampTraits.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 *TimestampBuilder) 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 *TimestampBuilder) 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.TimestampTraits.BytesRequired(n))
+		b.rawData = arrow.TimestampTraits.CastFromBytes(b.data.Bytes())
+	}
+}
+
+// NewArray creates a Timestamp array from the memory buffers used by the builder and resets the TimestampBuilder
+// so it can be used to build a new array.
+func (b *TimestampBuilder) NewArray() arrow.Array {
+	return b.NewTimestampArray()
+}
+
+// NewTimestampArray creates a Timestamp array from the memory buffers used by the builder and resets the TimestampBuilder
+// so it can be used to build a new array.
+func (b *TimestampBuilder) NewTimestampArray() (a *Timestamp) {
+	data := b.newData()
+	a = NewTimestampData(data)
+	data.Release()
+	return
+}
+
+func (b *TimestampBuilder) newData() (data *Data) {
+	bytesRequired := arrow.TimestampTraits.BytesRequired(b.length)
+	if bytesRequired > 0 && bytesRequired < b.data.Len() {
+		// trim buffers
+		b.data.Resize(bytesRequired)
+	}
+	data = NewData(b.dtype, 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
+}
+
+func (b *TimestampBuilder) AppendValueFromString(s string) error {
+	if s == NullValueStr {
+		b.AppendNull()
+		return nil
+	}
+	v, err := arrow.TimestampFromString(s, b.dtype.Unit)
+	if err != nil {
+		b.AppendNull()
+		return err
+	}
+	b.Append(v)
+	return nil
+}
+
+func (b *TimestampBuilder) UnmarshalOne(dec *json.Decoder) error {
+	t, err := dec.Token()
+	if err != nil {
+		return err
+	}
+
+	switch v := t.(type) {
+	case nil:
+		b.AppendNull()
+	case string:
+		loc, _ := b.dtype.GetZone()
+		tm, _, err := arrow.TimestampFromStringInLocation(v, b.dtype.Unit, loc)
+		if err != nil {
+			return &json.UnmarshalTypeError{
+				Value:  v,
+				Type:   reflect.TypeOf(arrow.Timestamp(0)),
+				Offset: dec.InputOffset(),
+			}
+		}
+
+		b.Append(tm)
+	case json.Number:
+		n, err := v.Int64()
+		if err != nil {
+			return &json.UnmarshalTypeError{
+				Value:  v.String(),
+				Type:   reflect.TypeOf(arrow.Timestamp(0)),
+				Offset: dec.InputOffset(),
+			}
+		}
+		b.Append(arrow.Timestamp(n))
+	case float64:
+		b.Append(arrow.Timestamp(v))
+
+	default:
+		return &json.UnmarshalTypeError{
+			Value:  fmt.Sprint(t),
+			Type:   reflect.TypeOf(arrow.Timestamp(0)),
+			Offset: dec.InputOffset(),
+		}
+	}
+
+	return nil
+}
+
+func (b *TimestampBuilder) Unmarshal(dec *json.Decoder) error {
+	for dec.More() {
+		if err := b.UnmarshalOne(dec); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (b *TimestampBuilder) UnmarshalJSON(data []byte) error {
+	dec := json.NewDecoder(bytes.NewReader(data))
+	t, err := dec.Token()
+	if err != nil {
+		return err
+	}
+
+	if delim, ok := t.(json.Delim); !ok || delim != '[' {
+		return fmt.Errorf("binary builder must unpack from json array, found %s", delim)
+	}
+
+	return b.Unmarshal(dec)
+}
+
+var (
+	_ arrow.Array = (*Timestamp)(nil)
+	_ Builder     = (*TimestampBuilder)(nil)
+)
diff --git a/go/arrow/array/timestamp_test.go b/go/arrow/array/timestamp_test.go
new file mode 100644
index 0000000000..27978976db
--- /dev/null
+++ b/go/arrow/array/timestamp_test.go
@@ -0,0 +1,235 @@
+// 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"
+	"time"
+
+	"github.com/apache/arrow/go/v13/arrow"
+	"github.com/apache/arrow/go/v13/arrow/array"
+	"github.com/apache/arrow/go/v13/arrow/memory"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestTimestampStringRoundTrip(t *testing.T) {
+	// 1. create array
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dt := &arrow.TimestampType{Unit: arrow.Second}
+	b := array.NewTimestampBuilder(mem, dt)
+	defer b.Release()
+
+	b.Append(1)
+	b.Append(2)
+	b.Append(3)
+	b.AppendNull()
+	b.Append(5)
+	b.Append(6)
+	b.AppendNull()
+	b.Append(8)
+	b.Append(9)
+	b.Append(10)
+
+	arr := b.NewArray().(*array.Timestamp)
+	defer arr.Release()
+
+	// 2. create array via AppendValueFromString
+	b1 := array.NewTimestampBuilder(mem, dt)
+	defer b1.Release()
+
+	for i := 0; i < arr.Len(); i++ {
+		assert.NoError(t, b1.AppendValueFromString(arr.ValueStr(i)))
+	}
+
+	arr1 := b1.NewArray().(*array.Timestamp)
+	defer arr1.Release()
+
+	assert.True(t, array.Equal(arr, arr1))
+}
+
+func TestNewTimestampBuilder(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+	timestamp := time.Now()
+	dtype := &arrow.TimestampType{Unit: arrow.Second}
+	ab := array.NewTimestampBuilder(mem, dtype)
+	defer ab.Release()
+
+	ab.Retain()
+	ab.Release()
+
+	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)
+	ab.AppendTime(timestamp)
+
+	// check state of builder before NewTimestampArray
+	assert.Equal(t, 11, ab.Len(), "unexpected Len()")
+	assert.Equal(t, 2, ab.NullN(), "unexpected NullN()")
+
+	a := ab.NewTimestampArray()
+
+	// check state of builder after NewTimestampArray
+	assert.Zero(t, ab.Len(), "unexpected ArrayBuilder.Len(), NewTimestampArray did not reset state")
+	assert.Zero(t, ab.Cap(), "unexpected ArrayBuilder.Cap(), NewTimestampArray did not reset state")
+	assert.Zero(t, ab.NullN(), "unexpected ArrayBuilder.NullN(), NewTimestampArray did not reset state")
+
+	// check state of array
+	assert.Equal(t, 2, a.NullN(), "unexpected null count")
+	assert.Equal(t, []arrow.Timestamp{1, 2, 3, 0, 5, 6, 0, 8, 9, 10, arrow.Timestamp(timestamp.Unix())}, a.TimestampValues(), "unexpected TimestampValues")
+	assert.Equal(t, []byte{0xb7}, a.NullBitmapBytes()[:1]) // 4 bytes due to minBuilderCapacity
+	assert.Len(t, a.TimestampValues(), 11, "unexpected length of TimestampValues")
+
+	a.Release()
+
+	ab.Append(7)
+	ab.Append(8)
+
+	a = ab.NewTimestampArray()
+
+	assert.Equal(t, 0, a.NullN())
+	assert.Equal(t, []arrow.Timestamp{7, 8}, a.TimestampValues())
+	assert.Len(t, a.TimestampValues(), 2)
+
+	a.Release()
+
+	var (
+		want   = []arrow.Timestamp{1, 2, 3, 4}
+		valids = []bool{true, true, false, true}
+	)
+
+	ab.AppendValues(want, valids)
+	a = ab.NewTimestampArray()
+
+	sub := array.MakeFromData(a.Data())
+	defer sub.Release()
+
+	if got, want := sub.DataType().ID(), a.DataType().ID(); got != want {
+		t.Fatalf("invalid type: got=%q, want=%q", got, want)
+	}
+
+	if _, ok := sub.(*array.Timestamp); !ok {
+		t.Fatalf("could not type-assert to array.Timestamp")
+	}
+
+	if got, want := a.String(), `[1 2 (null) 4]`; got != want {
+		t.Fatalf("got=%q, want=%q", got, want)
+	}
+
+	slice := array.NewSliceData(a.Data(), 2, 4)
+	defer slice.Release()
+
+	sub1 := array.MakeFromData(slice)
+	defer sub1.Release()
+
+	v, ok := sub1.(*array.Timestamp)
+	if !ok {
+		t.Fatalf("could not type-assert to array.Timestamp")
+	}
+
+	if got, want := v.String(), `[(null) 4]`; got != want {
+		t.Fatalf("got=%q, want=%q", got, want)
+	}
+
+	a.Release()
+}
+
+func TestTimestampBuilder_AppendValues(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.TimestampType{Unit: arrow.Second}
+	ab := array.NewTimestampBuilder(mem, dtype)
+	defer ab.Release()
+
+	exp := []arrow.Timestamp{0, 1, 2, 3}
+	ab.AppendValues(exp, nil)
+	a := ab.NewTimestampArray()
+	assert.Equal(t, exp, a.TimestampValues())
+
+	a.Release()
+}
+
+func TestTimestampBuilder_Empty(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.TimestampType{Unit: arrow.Second}
+	ab := array.NewTimestampBuilder(mem, dtype)
+	defer ab.Release()
+
+	exp := []arrow.Timestamp{0, 1, 2, 3}
+
+	ab.AppendValues([]arrow.Timestamp{}, nil)
+	a := ab.NewTimestampArray()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues(nil, nil)
+	a = ab.NewTimestampArray()
+	assert.Zero(t, a.Len())
+	a.Release()
+
+	ab.AppendValues([]arrow.Timestamp{}, nil)
+	ab.AppendValues(exp, nil)
+	a = ab.NewTimestampArray()
+	assert.Equal(t, exp, a.TimestampValues())
+	a.Release()
+
+	ab.AppendValues(exp, nil)
+	ab.AppendValues([]arrow.Timestamp{}, nil)
+	a = ab.NewTimestampArray()
+	assert.Equal(t, exp, a.TimestampValues())
+	a.Release()
+}
+
+func TestTimestampBuilder_Resize(t *testing.T) {
+	mem := memory.NewCheckedAllocator(memory.NewGoAllocator())
+	defer mem.AssertSize(t, 0)
+
+	dtype := &arrow.TimestampType{Unit: arrow.Second}
+	ab := array.NewTimestampBuilder(mem, dtype)
+	defer ab.Release()
+
+	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())
+}
diff --git a/go/arrow/datatype_fixedwidth.go b/go/arrow/datatype_fixedwidth.go
index 2a2bbc77a8..9f60149616 100644
--- a/go/arrow/datatype_fixedwidth.go
+++ b/go/arrow/datatype_fixedwidth.go
@@ -106,7 +106,7 @@ func (d Date64) FormattedString() string {
 }
 
 // TimestampFromStringInLocation is like TimestampFromString, but treats the time instant
-// as if it were in the passed timezone before converting to UTC for internal representation.
+// as if it were in the provided timezone before converting to UTC for internal representation.
 func TimestampFromStringInLocation(val string, unit TimeUnit, loc *time.Location) (Timestamp, bool, error) {
 	if len(val) < 10 {
 		return 0, false, fmt.Errorf("%w: invalid timestamp string", ErrInvalid)
@@ -167,17 +167,8 @@ func TimestampFromStringInLocation(val string, unit TimeUnit, loc *time.Location
 		out = out.In(loc).UTC()
 	}
 
-	switch unit {
-	case Second:
-		return Timestamp(out.Unix()), zoneFmt != "", nil
-	case Millisecond:
-		return Timestamp(out.Unix()*1e3 + int64(out.Nanosecond())/1e6), zoneFmt != "", nil
-	case Microsecond:
-		return Timestamp(out.Unix()*1e6 + int64(out.Nanosecond())/1e3), zoneFmt != "", nil
-	case Nanosecond:
-		return Timestamp(out.UnixNano()), zoneFmt != "", nil
-	}
-	return 0, zoneFmt != "", fmt.Errorf("%w: unexpected timestamp unit: %s", ErrInvalid, unit)
+	ts, err := TimestampFromTime(out, unit)
+	return ts, zoneFmt != "", err
 }
 
 // TimestampFromString parses a string and returns a timestamp for the given unit
@@ -187,10 +178,10 @@ func TimestampFromStringInLocation(val string, unit TimeUnit, loc *time.Location
 // or a space, and [.zzzzzzzzz] can be either left out or up to 9 digits of
 // fractions of a second.
 //
-//	 YYYY-MM-DD
-//	 YYYY-MM-DD[T]HH
-//   YYYY-MM-DD[T]HH:MM
-//   YYYY-MM-DD[T]HH:MM:SS[.zzzzzzzz]
+//	YYYY-MM-DD
+//	YYYY-MM-DD[T]HH
+//	YYYY-MM-DD[T]HH:MM
+//	YYYY-MM-DD[T]HH:MM:SS[.zzzzzzzz]
 //
 // You can also optionally have an ending Z to indicate UTC or indicate a specific
 // timezone using ±HH, ±HHMM or ±HH:MM at the end of the string.
@@ -206,6 +197,22 @@ func (t Timestamp) ToTime(unit TimeUnit) time.Time {
 	return time.Unix(0, int64(t)*int64(unit.Multiplier())).UTC()
 }
 
+// TimestampFromTime allows converting time.Time to Timestamp
+func TimestampFromTime(val time.Time, unit TimeUnit) (Timestamp, error) {
+	switch unit {
+	case Second:
+		return Timestamp(val.Unix()), nil
+	case Millisecond:
+		return Timestamp(val.Unix()*1e3 + int64(val.Nanosecond())/1e6), nil
+	case Microsecond:
+		return Timestamp(val.Unix()*1e6 + int64(val.Nanosecond())/1e3), nil
+	case Nanosecond:
+		return Timestamp(val.UnixNano()), nil
+	default:
+		return 0, fmt.Errorf("%w: unexpected timestamp unit: %s", ErrInvalid, unit)
+	}
+}
+
 // Time32FromString parses a string to return a Time32 value in the given unit,
 // unit needs to be only seconds or milliseconds and the string should be in the
 // form of HH:MM or HH:MM:SS[.zzz] where the fractions of a second are optional.
diff --git a/go/arrow/numeric.tmpldata b/go/arrow/numeric.tmpldata
index 92cd48ba10..3c2d63b7cb 100644
--- a/go/arrow/numeric.tmpldata
+++ b/go/arrow/numeric.tmpldata
@@ -78,18 +78,6 @@
     "Default": "0",
     "Size": "1"
   },
-  {
-    "Name": "Timestamp",
-    "name": "timestamp",
-    "Type": "Timestamp",
-    "QualifiedType": "arrow.Timestamp",
-    "InternalType": "int64",
-    "Default": "0",
-    "Size": "8",
-    "Opt": {
-      "Parametric": true
-    }
-  },
   {
     "Name": "Time32",
     "name": "time32",
diff --git a/go/arrow/type_traits_numeric.gen.go b/go/arrow/type_traits_numeric.gen.go
index 4eac715895..ba394b67e8 100644
--- a/go/arrow/type_traits_numeric.gen.go
+++ b/go/arrow/type_traits_numeric.gen.go
@@ -27,22 +27,21 @@ import (
 )
 
 var (
-	Int64Traits     int64Traits
-	Uint64Traits    uint64Traits
-	Float64Traits   float64Traits
-	Int32Traits     int32Traits
-	Uint32Traits    uint32Traits
-	Float32Traits   float32Traits
-	Int16Traits     int16Traits
-	Uint16Traits    uint16Traits
-	Int8Traits      int8Traits
-	Uint8Traits     uint8Traits
-	TimestampTraits timestampTraits
-	Time32Traits    time32Traits
-	Time64Traits    time64Traits
-	Date32Traits    date32Traits
-	Date64Traits    date64Traits
-	DurationTraits  durationTraits
+	Int64Traits    int64Traits
+	Uint64Traits   uint64Traits
+	Float64Traits  float64Traits
+	Int32Traits    int32Traits
+	Uint32Traits   uint32Traits
+	Float32Traits  float32Traits
+	Int16Traits    int16Traits
+	Uint16Traits   uint16Traits
+	Int8Traits     int8Traits
+	Uint8Traits    uint8Traits
+	Time32Traits   time32Traits
+	Time64Traits   time64Traits
+	Date32Traits   date32Traits
+	Date64Traits   date64Traits
+	DurationTraits durationTraits
 )
 
 // Int64 traits
@@ -525,54 +524,6 @@ func (uint8Traits) CastToBytes(b []uint8) []byte {
 // Copy copies src to dst.
 func (uint8Traits) Copy(dst, src []uint8) { copy(dst, src) }
 
-// Timestamp traits
-
-const (
-	// TimestampSizeBytes specifies the number of bytes required to store a single Timestamp in memory
-	TimestampSizeBytes = int(unsafe.Sizeof(Timestamp(0)))
-)
-
-type timestampTraits struct{}
-
-// BytesRequired returns the number of bytes required to store n elements in memory.
-func (timestampTraits) BytesRequired(n int) int { return TimestampSizeBytes * n }
-
-// PutValue
-func (timestampTraits) PutValue(b []byte, v Timestamp) {
-	endian.Native.PutUint64(b, uint64(v))
-}
-
-// CastFromBytes reinterprets the slice b to a slice of type Timestamp.
-//
-// NOTE: len(b) must be a multiple of TimestampSizeBytes.
-func (timestampTraits) CastFromBytes(b []byte) []Timestamp {
-	h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-
-	var res []Timestamp
-	s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
-	s.Data = h.Data
-	s.Len = h.Len / TimestampSizeBytes
-	s.Cap = h.Cap / TimestampSizeBytes
-
-	return res
-}
-
-// CastToBytes reinterprets the slice b to a slice of bytes.
-func (timestampTraits) CastToBytes(b []Timestamp) []byte {
-	h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
-
-	var res []byte
-	s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
-	s.Data = h.Data
-	s.Len = h.Len * TimestampSizeBytes
-	s.Cap = h.Cap * TimestampSizeBytes
-
-	return res
-}
-
-// Copy copies src to dst.
-func (timestampTraits) Copy(dst, src []Timestamp) { copy(dst, src) }
-
 // Time32 traits
 
 const (
diff --git a/go/arrow/type_traits_numeric.gen_test.go b/go/arrow/type_traits_numeric.gen_test.go
index 9c6cfaadd5..abcc2aca92 100644
--- a/go/arrow/type_traits_numeric.gen_test.go
+++ b/go/arrow/type_traits_numeric.gen_test.go
@@ -365,40 +365,6 @@ func TestUint8Traits(t *testing.T) {
 	}
 }
 
-func TestTimestampTraits(t *testing.T) {
-	const N = 10
-	b1 := arrow.TimestampTraits.CastToBytes([]arrow.Timestamp{
-		0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
-	})
-
-	b2 := make([]byte, arrow.TimestampTraits.BytesRequired(N))
-	for i := 0; i < N; i++ {
-		beg := i * arrow.TimestampSizeBytes
-		end := (i + 1) * arrow.TimestampSizeBytes
-		arrow.TimestampTraits.PutValue(b2[beg:end], arrow.Timestamp(i))
-	}
-
-	if !reflect.DeepEqual(b1, b2) {
-		v1 := arrow.TimestampTraits.CastFromBytes(b1)
-		v2 := arrow.TimestampTraits.CastFromBytes(b2)
-		t.Fatalf("invalid values:\nb1=%v\nb2=%v\nv1=%v\nv2=%v\n", b1, b2, v1, v2)
-	}
-
-	v1 := arrow.TimestampTraits.CastFromBytes(b1)
-	for i, v := range v1 {
-		if got, want := v, arrow.Timestamp(i); got != want {
-			t.Fatalf("invalid value[%d]. got=%v, want=%v", i, got, want)
-		}
-	}
-
-	v2 := make([]arrow.Timestamp, N)
-	arrow.TimestampTraits.Copy(v2, v1)
-
-	if !reflect.DeepEqual(v1, v2) {
-		t.Fatalf("invalid values:\nv1=%v\nv2=%v\n", v1, v2)
-	}
-}
-
 func TestTime32Traits(t *testing.T) {
 	const N = 10
 	b1 := arrow.Time32Traits.CastToBytes([]arrow.Time32{
diff --git a/go/arrow/type_traits_test.go b/go/arrow/type_traits_test.go
index df6335dc69..3b9571d3d3 100644
--- a/go/arrow/type_traits_test.go
+++ b/go/arrow/type_traits_test.go
@@ -17,6 +17,7 @@
 package arrow_test
 
 import (
+	"bytes"
 	"fmt"
 	"reflect"
 	"testing"
@@ -233,3 +234,37 @@ func TestMonthDayNanoIntervalTraits(t *testing.T) {
 		t.Fatalf("invalid values:\nv1=%v\nv2=%v\n", v1, v2)
 	}
 }
+
+func TestTimestampTraits(t *testing.T) {
+	const N = 10
+	b1 := arrow.TimestampTraits.CastToBytes([]arrow.Timestamp{
+		0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
+	})
+
+	b2 := make([]byte, arrow.TimestampTraits.BytesRequired(N))
+	for i := 0; i < N; i++ {
+		beg := i * arrow.TimestampSizeBytes
+		end := (i + 1) * arrow.TimestampSizeBytes
+		arrow.TimestampTraits.PutValue(b2[beg:end], arrow.Timestamp(i))
+	}
+
+	if !bytes.Equal(b1, b2) {
+		v1 := arrow.TimestampTraits.CastFromBytes(b1)
+		v2 := arrow.TimestampTraits.CastFromBytes(b2)
+		t.Fatalf("invalid values:\nb1=%v\nb2=%v\nv1=%v\nv2=%v\n", b1, b2, v1, v2)
+	}
+
+	v1 := arrow.TimestampTraits.CastFromBytes(b1)
+	for i, v := range v1 {
+		if got, want := v, arrow.Timestamp(i); got != want {
+			t.Fatalf("invalid value[%d]. got=%v, want=%v", i, got, want)
+		}
+	}
+
+	v2 := make([]arrow.Timestamp, N)
+	arrow.TimestampTraits.Copy(v2, v1)
+
+	if !reflect.DeepEqual(v1, v2) {
+		t.Fatalf("invalid values:\nv1=%v\nv2=%v\n", v1, v2)
+	}
+}
diff --git a/go/arrow/type_traits_timestamp.go b/go/arrow/type_traits_timestamp.go
new file mode 100644
index 0000000000..ade215e629
--- /dev/null
+++ b/go/arrow/type_traits_timestamp.go
@@ -0,0 +1,71 @@
+// 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 arrow
+
+import (
+	"reflect"
+	"unsafe"
+
+	"github.com/apache/arrow/go/v13/arrow/endian"
+)
+
+var TimestampTraits timestampTraits
+
+const (
+	// TimestampSizeBytes specifies the number of bytes required to store a single Timestamp in memory
+	TimestampSizeBytes = int(unsafe.Sizeof(Timestamp(0)))
+)
+
+type timestampTraits struct{}
+
+// BytesRequired returns the number of bytes required to store n elements in memory.
+func (timestampTraits) BytesRequired(n int) int { return TimestampSizeBytes * n }
+
+func (timestampTraits) PutValue(b []byte, v Timestamp) {
+	endian.Native.PutUint64(b, uint64(v))
+}
+
+// CastFromBytes reinterprets the slice b to a slice of type Timestamp.
+//
+// NOTE: len(b) must be a multiple of TimestampSizeBytes.
+func (timestampTraits) CastFromBytes(b []byte) []Timestamp {
+	h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+
+	var res []Timestamp
+	s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
+	s.Data = h.Data
+	s.Len = h.Len / TimestampSizeBytes
+	s.Cap = h.Cap / TimestampSizeBytes
+
+	return res
+}
+
+// CastToBytes reinterprets the slice b to a slice of bytes.
+func (timestampTraits) CastToBytes(b []Timestamp) []byte {
+	h := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+
+	var res []byte
+	s := (*reflect.SliceHeader)(unsafe.Pointer(&res))
+	s.Data = h.Data
+	s.Len = h.Len * TimestampSizeBytes
+	s.Cap = h.Cap * TimestampSizeBytes
+
+	return res
+}
+
+// Copy copies src to dst.
+func (timestampTraits) Copy(dst, src []Timestamp) { copy(dst, src) }