Skip to content

Commit

Permalink
Set fractional precision to 9 if timestamp precision is TimestampPrec…
Browse files Browse the repository at this point in the history
…isionNanosecond

When we create a timestamp object from Golang's time object, we were specifying the precision = 9 if nanoseconds > 0. This is incorrect because according to Go time docs, time object represents an instant in time with nanosecond precision.

The change is to set fractional precision = 9 when creating a timestamp object from Go time object.

Another change added was to add a guard to timestamp creation functions and set fractional precision = 9 if timestamp precision =  TimestampPrecisionNanosecond. Otherwise set it to 0.
  • Loading branch information
Byron Lin committed Jun 3, 2021
1 parent 44e0b20 commit b3422b0
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 16 deletions.
2 changes: 1 addition & 1 deletion ion/binarywriter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func TestWriteBinaryTimestamp(t *testing.T) {
nowish, _ := NewTimestampFromStr("2019-08-04T18:15:43.863494+10:00", TimestampPrecisionNanosecond, TimezoneLocal)

testBinaryWriter(t, eval, func(w Writer) {
assert.NoError(t, w.WriteTimestamp(NewTimestamp(time.Time{}, TimestampPrecisionNanosecond, TimezoneUTC)))
assert.NoError(t, w.WriteTimestamp(NewTimestamp(time.Time{}, TimestampPrecisionSecond, TimezoneUTC)))
assert.NoError(t, w.WriteTimestamp(nowish))
})
}
Expand Down
10 changes: 1 addition & 9 deletions ion/marshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,16 +442,8 @@ func (m *Encoder) encodeTimeDate(v reflect.Value) error {
kind = TimezoneUnspecified
}

// Get number of fractional seconds precisions
ns := t.Nanosecond()
numFractionalSeconds := 0
// Go native time object will always have 9 precision units when nanoseconds > 0
if ns > 0 {
numFractionalSeconds = maxFractionalPrecision
}

// Time.Date has nano second component
timestamp := NewTimestampWithFractionalSeconds(t, TimestampPrecisionNanosecond, kind, uint8(numFractionalSeconds))
timestamp := NewTimestampWithFractionalSeconds(t, TimestampPrecisionNanosecond, kind, maxFractionalPrecision)
return m.w.WriteTimestamp(timestamp)
}

Expand Down
4 changes: 2 additions & 2 deletions ion/marshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ func TestMarshalText(t *testing.T) {
test(time.Date(2010, 1, 1, 0, 0, 0, 1, time.UTC), "2010-01-01T00:00:00.000000001Z")
test(time.Date(2010, 1, 1, 0, 0, 0, 770000000, time.UTC), "2010-01-01T00:00:00.770000000Z")
loc, _ := time.LoadLocation("EST")
test(time.Date(2010, 1, 1, 0, 0, 0, 0, loc), "2010-01-01T00:00:00-05:00")
test(time.Date(2010, 1, 1, 0, 0, 0, 0, loc), "2010-01-01T00:00:00.000000000-05:00")
loc = time.FixedZone("UTC+8", 8*60*60)
test(time.Date(2010, 1, 1, 0, 0, 0, 0, loc), "2010-01-01T00:00:00+08:00")
test(time.Date(2010, 1, 1, 0, 0, 0, 0, loc), "2010-01-01T00:00:00.000000000+08:00")

test("hello\tworld", "\"hello\\tworld\"")

Expand Down
19 changes: 15 additions & 4 deletions ion/timestamp.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,23 +133,34 @@ type Timestamp struct {

// NewDateTimestamp constructor meant for timestamps that only have a date portion (ie. no time portion).
func NewDateTimestamp(dateTime time.Time, precision TimestampPrecision) Timestamp {
return Timestamp{dateTime, precision, TimezoneUnspecified, 0}
numDecimalPlacesOfFractionalSeconds := uint8(0)
if precision >= TimestampPrecisionNanosecond {
numDecimalPlacesOfFractionalSeconds = maxFractionalPrecision
}
return Timestamp{dateTime, precision, TimezoneUnspecified, numDecimalPlacesOfFractionalSeconds}
}

// NewTimestamp constructor
func NewTimestamp(dateTime time.Time, precision TimestampPrecision, kind TimezoneKind) Timestamp {
numDecimalPlacesOfFractionalSeconds := uint8(0)

if precision <= TimestampPrecisionDay {
// Timestamps with Year, Month, or Day precision necessarily have TimezoneUnspecified timezone.
kind = TimezoneUnspecified
} else if precision >= TimestampPrecisionNanosecond {
numDecimalPlacesOfFractionalSeconds = maxFractionalPrecision
}
return Timestamp{dateTime, precision, kind, 0}
return Timestamp{dateTime, precision, kind, numDecimalPlacesOfFractionalSeconds}
}

// NewTimestampWithFractionalSeconds constructor
func NewTimestampWithFractionalSeconds(dateTime time.Time, precision TimestampPrecision, kind TimezoneKind, fractionPrecision uint8) Timestamp {
if fractionPrecision > 9 {
if fractionPrecision > maxFractionalPrecision {
// 9 is the max precision supported
fractionPrecision = 9
fractionPrecision = maxFractionalPrecision
}
if precision < TimestampPrecisionNanosecond {
fractionPrecision = 0
}
return Timestamp{dateTime, precision, kind, fractionPrecision}
}
Expand Down

0 comments on commit b3422b0

Please sign in to comment.