Skip to content

Commit

Permalink
Merge branch 'master' into refactor-parse-value
Browse files Browse the repository at this point in the history
  • Loading branch information
Tang8330 authored Oct 22, 2024
2 parents d178c41 + 0ce6f48 commit 200475b
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 37 deletions.
26 changes: 10 additions & 16 deletions lib/debezium/converters/time.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,31 +118,25 @@ func (ZonedTimestamp) Convert(value any) (any, error) {
return nil, fmt.Errorf("failed to parse %q, err: %w", valString, err)
}

var SupportedTimeWithTimezoneFormats = []string{
"15:04:05Z", // w/o fractional seconds
"15:04:05.000Z", // ms
"15:04:05.000000Z", // microseconds
}

type TimeWithTimezone struct{}

func (TimeWithTimezone) ToKindDetails() typing.KindDetails {
return typing.NewExtendedTimeDetails(typing.ETime, ext.TimeKindType, "")
func (t TimeWithTimezone) layout() string {
return "15:04:05.999999Z"
}

func (t TimeWithTimezone) ToKindDetails() typing.KindDetails {
return typing.NewExtendedTimeDetails(typing.ETime, ext.TimeKindType, t.layout())
}

func (TimeWithTimezone) Convert(value any) (any, error) {
func (t TimeWithTimezone) Convert(value any) (any, error) {
valString, isOk := value.(string)
if !isOk {
return nil, fmt.Errorf("expected string got '%v' with type %T", value, value)
}

var err error
var ts time.Time
for _, supportedTimeFormat := range SupportedTimeWithTimezoneFormats {
ts, err = ext.ParseTimeExactMatch(supportedTimeFormat, valString)
if err == nil {
return ext.NewExtendedTime(ts, ext.TimeKindType, supportedTimeFormat), nil
}
ts, err := time.Parse(t.layout(), valString)
if err == nil {
return ext.NewExtendedTime(ts, ext.TimeKindType, t.layout()), nil
}

return nil, fmt.Errorf("failed to parse %q: %w", valString, err)
Expand Down
52 changes: 35 additions & 17 deletions lib/debezium/converters/time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,29 +165,47 @@ func TestMicroTime_Converter(t *testing.T) {
func TestConvertTimeWithTimezone(t *testing.T) {
{
// Invalid
ts, err := TimeWithTimezone{}.Convert("23:02")
assert.Nil(t, ts)
assert.ErrorContains(t, err, `failed to parse "23:02": parsing time`)
{
// Malformed
_, err := TimeWithTimezone{}.Convert("23:02")
assert.ErrorContains(t, err, `failed to parse "23:02": parsing time`)
}
{
// Non UTC
_, err := TimeWithTimezone{}.Convert("23:02:06.745116")
assert.ErrorContains(t, err, `failed to parse "23:02:06.745116"`)
}
{
// Providing timezone offset
_, err := TimeWithTimezone{}.Convert("23:02:06.745116Z-07:00")
assert.ErrorContains(t, err, `failed to parse "23:02:06.745116Z-07:00": parsing time "23:02:06.745116Z-07:00": extra text: "-07:00"`)
}
}
{
// What Debezium + Reader would produce
// What Debezium + Reader would produce (microsecond precision)
val, err := TimeWithTimezone{}.Convert("23:02:06.745116Z")
ts, isOk := val.(*ext.ExtendedTime)
assert.True(t, isOk)
assert.NoError(t, err)

expectedTs := ext.NewExtendedTime(time.Date(0, 1, 1, 23, 2, 6, 745116000, time.UTC), ext.TimeKindType, "15:04:05.000000Z")
assert.Equal(t, expectedTs, ts)
expectedTs := ext.NewExtendedTime(time.Date(0, 1, 1, 23, 2, 6, 745116000, time.UTC), ext.TimeKindType, "15:04:05.999999Z")
assert.Equal(t, expectedTs, val.(*ext.ExtendedTime))
assert.Equal(t, "23:02:06.745116Z", val.(*ext.ExtendedTime).String(""))
}
{
// Non UTC
ts, err := TimeWithTimezone{}.Convert("23:02:06.745116")
assert.ErrorContains(t, err, `failed to parse "23:02:06.745116"`)
assert.Nil(t, ts)

// Providing timezone offset
ts, err = TimeWithTimezone{}.Convert("23:02:06.745116Z-07:00")
assert.ErrorContains(t, err, `failed to parse "23:02:06.745116Z-07:00": parsing time "23:02:06.745116Z-07:00": extra text: "-07:00"`)
assert.Nil(t, ts)
// ms precision
val, err := TimeWithTimezone{}.Convert("23:02:06.745Z")
assert.NoError(t, err)

expectedTs := ext.NewExtendedTime(time.Date(0, 1, 1, 23, 2, 6, 745000000, time.UTC), ext.TimeKindType, "15:04:05.999999Z")
assert.Equal(t, expectedTs, val.(*ext.ExtendedTime))
assert.Equal(t, "23:02:06.745Z", val.(*ext.ExtendedTime).String(""))
}
{
// no fractional seconds
val, err := TimeWithTimezone{}.Convert("23:02:06Z")
assert.NoError(t, err)

expectedTs := ext.NewExtendedTime(time.Date(0, 1, 1, 23, 2, 6, 0, time.UTC), ext.TimeKindType, "15:04:05.999999Z")
assert.Equal(t, expectedTs, val.(*ext.ExtendedTime))
assert.Equal(t, "23:02:06Z", val.(*ext.ExtendedTime).String(""))
}
}
10 changes: 6 additions & 4 deletions lib/debezium/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,12 @@ func TestField_ToKindDetails(t *testing.T) {
}
{
{
// Time with timezone
kd, err := Field{DebeziumType: TimeWithTimezone}.ToKindDetails()
assert.NoError(t, err)
assert.Equal(t, typing.NewExtendedTimeDetails(typing.ETime, ext.TimeKindType, ""), kd)
// Time with time zone
for _, dbzType := range []SupportedDebeziumType{TimeWithTimezone} {
kd, err := Field{DebeziumType: dbzType}.ToKindDetails()
assert.NoError(t, err)
assert.Equal(t, typing.NewExtendedTimeDetails(typing.ETime, ext.TimeKindType, "15:04:05.999999Z"), kd, dbzType)
}
}
{
// Time
Expand Down

0 comments on commit 200475b

Please sign in to comment.