Skip to content

Commit

Permalink
Date/Time Types and Serializers [API-1230] (#741)
Browse files Browse the repository at this point in the history
Added new date/time types
  • Loading branch information
yuce authored Mar 2, 2022
1 parent 2cc57fd commit f83ff07
Show file tree
Hide file tree
Showing 14 changed files with 532 additions and 150 deletions.
21 changes: 19 additions & 2 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -207,10 +207,27 @@ The names in parantheses correspond to SQL types:
- float32 (real)
- float64 (double)
- types.Decimal (decimal)
- types.LocalDate (date)
- types.LocalTime (time)
- types.LocalDateTime (timestamp)
- types.OffsetDateTime (timestamp with time zone)
- time.Time (date) Detected by checking: hour == minute == second == nanoseconds = 0
- time.Time (time) Detected by checking: year == 0, month == day == 1
- time.Time (timestamp) Detected by checking: hour == minute == second == nanoseconds = 0, timezone == time.Local
- time.Time (timestamp with time zone) Detected by checking: hour == minute == second == nanoseconds = 0, timezone != time.Local
- time.Time (timestamp) Detected by checking: not time, timezone == time.Local
- time.Time (timestamp with time zone) Detected by checking: not time, timezone != time.Local
- serialization.JSON (json)
Using Date/Time
time.Time values are automatically serialized to the correct type.
In order to force using a specific date/time type, create a time.Time value and cast it to the target type:
t := time.Now()
dateValue := types.LocalDate(t)
timeValue := types.LocalTime(t)
dateTimeValue := types.LocalDateTime(t)
dateTimeWithTimezoneValue := types.OffsetDateTime(t)
Management Center Integration
Expand Down
16 changes: 8 additions & 8 deletions internal/proto/codec/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,31 +460,31 @@ func (fixSizedTypesCodec) DecodeDouble(buffer []byte, offset int32) float64 {
return math.Float64frombits(binary.LittleEndian.Uint64(buffer[offset:]))
}

func (fixSizedTypesCodec) DecodeLocalDate(buffer []byte, offset int32) time.Time {
func (fixSizedTypesCodec) DecodeLocalDate(buffer []byte, offset int32) types.LocalDate {
y, m, d := decodeLocalDate(buffer, offset)
return time.Date(y, m, d, 0, 0, 0, 0, time.Local)
return types.LocalDate(time.Date(y, m, d, 0, 0, 0, 0, time.Local))
}

func (fixSizedTypesCodec) DecodeLocalTime(buffer []byte, offset int32) time.Time {
func (fixSizedTypesCodec) DecodeLocalTime(buffer []byte, offset int32) types.LocalTime {
h, m, s, nanos := decodeLocalTime(buffer, offset)
return time.Date(0, 1, 1, h, m, s, nanos, time.Local)
return types.LocalTime(time.Date(0, 1, 1, h, m, s, nanos, time.Local))
}

func (fixSizedTypesCodec) DecodeLocalDateTime(buffer []byte, offset int32) time.Time {
func (fixSizedTypesCodec) DecodeLocalDateTime(buffer []byte, offset int32) types.LocalDateTime {
y, m, d := decodeLocalDate(buffer, offset)
offset += proto.LocalDateSizeInBytes
h, mn, s, nanos := decodeLocalTime(buffer, offset)
return time.Date(y, m, d, h, mn, s, nanos, time.Local)
return types.LocalDateTime(time.Date(y, m, d, h, mn, s, nanos, time.Local))
}

func (fixSizedTypesCodec) DecodeDateTimeWithTimeZone(buffer []byte, offset int32) time.Time {
func (fixSizedTypesCodec) DecodeDateTimeWithTimeZone(buffer []byte, offset int32) types.OffsetDateTime {
y, m, d := decodeLocalDate(buffer, offset)
offset += proto.LocalDateSizeInBytes
h, mn, s, nanos := decodeLocalTime(buffer, offset)
offset += proto.LocalTimeSizeInBytes
offsetSecs := int(FixSizedTypesCodec.DecodeInt(buffer, offset))
tz := time.FixedZone("", offsetSecs)
return time.Date(y, m, d, h, mn, s, nanos, tz)
return types.OffsetDateTime(time.Date(y, m, d, h, mn, s, nanos, tz))
}

func (fixSizedTypesCodec) EncodeUUID(buffer []byte, offset int32, uuid types.UUID) {
Expand Down
18 changes: 8 additions & 10 deletions internal/serialization/class_definition_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@
package serialization

import (
"time"

ihzerrors "github.com/hazelcast/hazelcast-go-client/internal/hzerrors"
"github.com/hazelcast/hazelcast-go-client/serialization"
"github.com/hazelcast/hazelcast-go-client/types"
Expand Down Expand Up @@ -127,35 +125,35 @@ func (cdw *ClassDefinitionWriter) WriteStringArray(fieldName string, value []str
must(cdw.classDefinition.AddStringArrayField(fieldName))
}

func (cdw *ClassDefinitionWriter) WriteDate(fieldName string, value *time.Time) {
func (cdw *ClassDefinitionWriter) WriteDate(fieldName string, value *types.LocalDate) {
must(cdw.classDefinition.AddDateField(fieldName))
}

func (cdw *ClassDefinitionWriter) WriteTime(fieldName string, value *time.Time) {
func (cdw *ClassDefinitionWriter) WriteTime(fieldName string, value *types.LocalTime) {
must(cdw.classDefinition.AddTimeField(fieldName))
}

func (cdw *ClassDefinitionWriter) WriteTimestamp(fieldName string, value *time.Time) {
func (cdw *ClassDefinitionWriter) WriteTimestamp(fieldName string, value *types.LocalDateTime) {
must(cdw.classDefinition.AddTimestampField(fieldName))
}

func (cdw *ClassDefinitionWriter) WriteTimestampWithTimezone(fieldName string, value *time.Time) {
func (cdw *ClassDefinitionWriter) WriteTimestampWithTimezone(fieldName string, value *types.OffsetDateTime) {
must(cdw.classDefinition.AddTimestampWithTimezoneField(fieldName))
}

func (cdw *ClassDefinitionWriter) WriteDateArray(fieldName string, value []time.Time) {
func (cdw *ClassDefinitionWriter) WriteDateArray(fieldName string, value []types.LocalDate) {
must(cdw.classDefinition.AddDateArrayField(fieldName))
}

func (cdw *ClassDefinitionWriter) WriteTimeArray(fieldName string, value []time.Time) {
func (cdw *ClassDefinitionWriter) WriteTimeArray(fieldName string, value []types.LocalTime) {
must(cdw.classDefinition.AddTimeArrayField(fieldName))
}

func (cdw *ClassDefinitionWriter) WriteTimestampArray(fieldName string, value []time.Time) {
func (cdw *ClassDefinitionWriter) WriteTimestampArray(fieldName string, value []types.LocalDateTime) {
must(cdw.classDefinition.AddTimestampArrayField(fieldName))
}

func (cdw *ClassDefinitionWriter) WriteTimestampWithTimezoneArray(fieldName string, value []time.Time) {
func (cdw *ClassDefinitionWriter) WriteTimestampWithTimezoneArray(fieldName string, value []types.OffsetDateTime) {
must(cdw.classDefinition.AddTimestampWithTimezoneArrayField(fieldName))
}

Expand Down
57 changes: 31 additions & 26 deletions internal/serialization/default_portable_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package serialization
import (
"fmt"
"time"
"unsafe"

ihzerrors "github.com/hazelcast/hazelcast-go-client/internal/hzerrors"
"github.com/hazelcast/hazelcast-go-client/serialization"
Expand Down Expand Up @@ -94,22 +95,22 @@ func TypeByID(fieldType serialization.FieldDefinitionType) string {
return "types.Decimal"
case serialization.TypeDecimalArray:
return "[]types.Decimal"
case serialization.TypeTime:
return "time.Time (time)"
case serialization.TypeTimeArray:
return "[]time.Time (time)"
case serialization.TypeDate:
return "time.Time (date)"
return "types.LocalDate"
case serialization.TypeDateArray:
return "[]time.Time (date)"
return "[]types.LocalDate"
case serialization.TypeTime:
return "types.LocalTime"
case serialization.TypeTimeArray:
return "[]types.LocalTime"
case serialization.TypeTimestamp:
return "time.Time (timestamp)"
return "types.LocalDateTime"
case serialization.TypeTimestampArray:
return "[]time.Time (timestamp)"
return "[]types.LocalDateTime"
case serialization.TypeTimestampWithTimezone:
return "time.Time (timestamp with timezone)"
return "types.OffsetDateTime"
case serialization.TypeTimestampWithTimezoneArray:
return "[]time.Time (timestamp with timezone)"
return "[]types.OffsetDateTime"
}
return "UNKNOWN"
}
Expand Down Expand Up @@ -346,66 +347,70 @@ func (pr *DefaultPortableReader) GetRawDataInput() serialization.DataInput {
return pr.input
}

func (pr *DefaultPortableReader) ReadDate(fieldName string) (t *time.Time) {
func (pr *DefaultPortableReader) ReadDate(fieldName string) (t *types.LocalDate) {
pr.readNullable(fieldName, serialization.TypeDate, func() {
v := ReadPortableDate(pr.input)
t = &v
t = (*types.LocalDate)(&v)
})
return
}

func (pr *DefaultPortableReader) ReadTime(fieldName string) (t *time.Time) {
func (pr *DefaultPortableReader) ReadTime(fieldName string) (t *types.LocalTime) {
pr.readNullable(fieldName, serialization.TypeTime, func() {
v := ReadPortableTime(pr.input)
t = &v
t = (*types.LocalTime)(&v)
})
return
}

func (pr *DefaultPortableReader) ReadTimestamp(fieldName string) (t *time.Time) {
func (pr *DefaultPortableReader) ReadTimestamp(fieldName string) (t *types.LocalDateTime) {
pr.readNullable(fieldName, serialization.TypeTimestamp, func() {
v := ReadPortableTimestamp(pr.input)
t = &v
t = (*types.LocalDateTime)(&v)
})
return
}

func (pr *DefaultPortableReader) ReadTimestampWithTimezone(fieldName string) (t *time.Time) {
func (pr *DefaultPortableReader) ReadTimestampWithTimezone(fieldName string) (t *types.OffsetDateTime) {
pr.readNullable(fieldName, serialization.TypeTimestampWithTimezone, func() {
v := ReadPortableTimestampWithTimezone(pr.input)
t = &v
t = (*types.OffsetDateTime)(&v)
})
return
}

func (pr *DefaultPortableReader) ReadDateArray(fieldName string) (t []time.Time) {
func (pr *DefaultPortableReader) ReadDateArray(fieldName string) (t []types.LocalDate) {
pos := pr.positionByField(fieldName, serialization.TypeDateArray)
pr.runAtPosition(pos, func() {
t = readArrayOfTime(pr.input, ReadPortableDate)
v := readArrayOfTime(pr.input, ReadPortableDate)
t = *(*[]types.LocalDate)(unsafe.Pointer(&v))
})
return
}

func (pr *DefaultPortableReader) ReadTimeArray(fieldName string) (t []time.Time) {
func (pr *DefaultPortableReader) ReadTimeArray(fieldName string) (t []types.LocalTime) {
pos := pr.positionByField(fieldName, serialization.TypeTimeArray)
pr.runAtPosition(pos, func() {
t = readArrayOfTime(pr.input, ReadPortableTime)
v := readArrayOfTime(pr.input, ReadPortableTime)
t = *(*[]types.LocalTime)(unsafe.Pointer(&v))
})
return
}

func (pr *DefaultPortableReader) ReadTimestampArray(fieldName string) (t []time.Time) {
func (pr *DefaultPortableReader) ReadTimestampArray(fieldName string) (t []types.LocalDateTime) {
pos := pr.positionByField(fieldName, serialization.TypeTimestampArray)
pr.runAtPosition(pos, func() {
t = readArrayOfTime(pr.input, ReadPortableTimestamp)
v := readArrayOfTime(pr.input, ReadPortableTimestamp)
t = *(*[]types.LocalDateTime)(unsafe.Pointer(&v))
})
return
}

func (pr *DefaultPortableReader) ReadTimestampWithTimezoneArray(fieldName string) (t []time.Time) {
func (pr *DefaultPortableReader) ReadTimestampWithTimezoneArray(fieldName string) (t []types.OffsetDateTime) {
pos := pr.positionByField(fieldName, serialization.TypeTimestampWithTimezoneArray)
pr.runAtPosition(pos, func() {
t = readArrayOfTime(pr.input, ReadPortableTimestampWithTimezone)
v := readArrayOfTime(pr.input, ReadPortableTimestampWithTimezone)
t = *(*[]types.OffsetDateTime)(unsafe.Pointer(&v))
})
return
}
Expand Down
41 changes: 25 additions & 16 deletions internal/serialization/default_portable_writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package serialization
import (
"fmt"
"time"
"unsafe"

ihzerrors "github.com/hazelcast/hazelcast-go-client/internal/hzerrors"
"github.com/hazelcast/hazelcast-go-client/serialization"
Expand Down Expand Up @@ -184,48 +185,56 @@ func (pw *DefaultPortableWriter) WritePortableArray(fieldName string, portableAr
}
}

func (pw *DefaultPortableWriter) WriteDate(fieldName string, t *time.Time) {
func (pw *DefaultPortableWriter) WriteDate(fieldName string, t *types.LocalDate) {
pw.writeNullableField(fieldName, serialization.TypeDate, t == nil, func() {
WritePortableDate(pw.output.ObjectDataOutput, *t)
tt := (*time.Time)(t)
WritePortableDate(pw.output.ObjectDataOutput, *tt)
})
}

func (pw *DefaultPortableWriter) WriteTime(fieldName string, t *time.Time) {
func (pw *DefaultPortableWriter) WriteTime(fieldName string, t *types.LocalTime) {
pw.writeNullableField(fieldName, serialization.TypeTime, t == nil, func() {
WritePortableTime(pw.output.ObjectDataOutput, *t)
tt := (*time.Time)(t)
WritePortableTime(pw.output.ObjectDataOutput, *tt)
})
}

func (pw *DefaultPortableWriter) WriteTimestamp(fieldName string, t *time.Time) {
func (pw *DefaultPortableWriter) WriteTimestamp(fieldName string, t *types.LocalDateTime) {
pw.writeNullableField(fieldName, serialization.TypeTimestamp, t == nil, func() {
WritePortableTimestamp(pw.output.ObjectDataOutput, *t)
tt := (*time.Time)(t)
WritePortableTimestamp(pw.output.ObjectDataOutput, *tt)
})
}

func (pw *DefaultPortableWriter) WriteTimestampWithTimezone(fieldName string, t *time.Time) {
func (pw *DefaultPortableWriter) WriteTimestampWithTimezone(fieldName string, t *types.OffsetDateTime) {
pw.writeNullableField(fieldName, serialization.TypeTimestampWithTimezone, t == nil, func() {
WritePortableTimestampWithTimezone(pw.output.ObjectDataOutput, *t)
tt := (*time.Time)(t)
WritePortableTimestampWithTimezone(pw.output.ObjectDataOutput, *tt)
})
}

func (pw *DefaultPortableWriter) WriteDateArray(fieldName string, ts []time.Time) {
func (pw *DefaultPortableWriter) WriteDateArray(fieldName string, a []types.LocalDate) {
pw.setPosition(fieldName, int32(serialization.TypeDateArray))
writeArrayOfTime(pw.output.ObjectDataOutput, ts, WritePortableDate)
ts := (*([]time.Time))(unsafe.Pointer(&a))
writeArrayOfTime(pw.output.ObjectDataOutput, *ts, WritePortableDate)
}

func (pw *DefaultPortableWriter) WriteTimeArray(fieldName string, ts []time.Time) {
func (pw *DefaultPortableWriter) WriteTimeArray(fieldName string, a []types.LocalTime) {
pw.setPosition(fieldName, int32(serialization.TypeTimeArray))
writeArrayOfTime(pw.output.ObjectDataOutput, ts, WritePortableTime)
ts := (*([]time.Time))(unsafe.Pointer(&a))
writeArrayOfTime(pw.output.ObjectDataOutput, *ts, WritePortableTime)
}

func (pw *DefaultPortableWriter) WriteTimestampArray(fieldName string, ts []time.Time) {
func (pw *DefaultPortableWriter) WriteTimestampArray(fieldName string, a []types.LocalDateTime) {
pw.setPosition(fieldName, int32(serialization.TypeTimestampArray))
writeArrayOfTime(pw.output.ObjectDataOutput, ts, WritePortableTimestamp)
ts := (*([]time.Time))(unsafe.Pointer(&a))
writeArrayOfTime(pw.output.ObjectDataOutput, *ts, WritePortableTimestamp)
}

func (pw *DefaultPortableWriter) WriteTimestampWithTimezoneArray(fieldName string, ts []time.Time) {
func (pw *DefaultPortableWriter) WriteTimestampWithTimezoneArray(fieldName string, a []types.OffsetDateTime) {
pw.setPosition(fieldName, int32(serialization.TypeTimestampWithTimezoneArray))
writeArrayOfTime(pw.output.ObjectDataOutput, ts, WritePortableTimestampWithTimezone)
ts := (*([]time.Time))(unsafe.Pointer(&a))
writeArrayOfTime(pw.output.ObjectDataOutput, *ts, WritePortableTimestampWithTimezone)
}

func (pw *DefaultPortableWriter) WriteDecimal(fieldName string, d *types.Decimal) {
Expand Down
Loading

0 comments on commit f83ff07

Please sign in to comment.