Repository: parquet-go/parquet-go (go)

Issue:
Allow delta encoding on time.Time
Currently adding the `delta` tag to a struct field of type `time.Time` panics with: `panic: delta is an invalid parquet tag: time time.Time [delta]`. I would like if delta was allowed on struct fields of type `time.Time.` This could have a big impact on the compressability of timeseries-like data, while allowing users to use language native data types.

Related: #87 

Pull request description:
Allow specifying delta on field of type time.Time
Fixes #112 

This allows specifying the delta tag on a `time.Time`.

I added a test to verify that it successfully creates a schema object, but have not verified that it actually uses the delta encoding.

Patch:
diff --git a/README.md b/README.md
index 1ea0a5a..7ac9553 100644
--- a/README.md
+++ b/README.md
@@ -557,7 +557,7 @@ for the full interface documentation.
 
 While initial design and development occurred at Twilio Segment, the project is now maintained by the open source community. We welcome external contributors.
 to participate in the form of discussions or code changes. Please review to the
-[Contribution](./CONTRIBUTING.md) guidelines as well as the [Code of Condution](./CODE_OF_CONDUCT.md)
+[Contribution](./CONTRIBUTING.md) guidelines as well as the [Code of Conduct](./CODE_OF_CONDUCT.md)
 before submitting contributions.
 
 ### Continuous Integration
diff --git a/go.mod b/go.mod
index bd2c9b0..d49a983 100644
--- a/go.mod
+++ b/go.mod
@@ -12,7 +12,7 @@ require (
 	github.com/segmentio/encoding v0.3.6
 	github.com/stretchr/testify v1.8.4
 	golang.org/x/sys v0.10.0
-	google.golang.org/protobuf v1.30.0
+	google.golang.org/protobuf v1.33.0
 )
 
 require (
diff --git a/go.sum b/go.sum
index 6b2fb10..a3a6eea 100644
--- a/go.sum
+++ b/go.sum
@@ -2,9 +2,7 @@ github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/
 github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
 github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
@@ -28,10 +26,8 @@ golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
 golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
-golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
-google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
+google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/schema.go b/schema.go
index ccd4202..176e840 100644
--- a/schema.go
+++ b/schema.go
@@ -818,7 +818,12 @@ func makeNodeOf(t reflect.Type, name string, tag []string) Node {
 					throwInvalidTag(t, name, option)
 				}
 			default:
-				throwInvalidTag(t, name, option)
+				switch t {
+				case reflect.TypeOf(time.Time{}):
+					setEncoding(&DeltaBinaryPacked)
+				default:
+					throwInvalidTag(t, name, option)
+				}
 			}
 
 		case "split":


Test patch:
diff --git a/parquet_test.go b/parquet_test.go
index 432df63..1bc5530 100644
--- a/parquet_test.go
+++ b/parquet_test.go
@@ -402,7 +402,6 @@ func TestIssue423(t *testing.T) {
 	}
 
 	schema := parquet.SchemaOf(new(Outer))
-	fmt.Println(schema.String())
 	buf := new(bytes.Buffer)
 	w := parquet.NewGenericWriter[Outer](buf, schema)
 	_, err := w.Write(writeRows)
diff --git a/schema_test.go b/schema_test.go
index f581d38..6fc4310 100644
--- a/schema_test.go
+++ b/schema_test.go
@@ -2,6 +2,7 @@ package parquet_test
 
 import (
 	"testing"
+	"time"
 
 	"github.com/parquet-go/parquet-go"
 )
@@ -202,6 +203,14 @@ func TestSchemaOf(t *testing.T) {
 	}
 	repeated binary d (STRING) = 4;
 	optional binary e (STRING) = 5;
+}`,
+		},
+		{
+			value: new(struct {
+				Time time.Time `parquet:"time,delta"`
+			}),
+			print: `message {
+	required int64 time (TIMESTAMP(isAdjustedToUTC=true,unit=NANOS));
 }`,
 		},
 	}