diff --git a/timestamp.go b/timestamp.go index 35ac5143..de059f7e 100644 --- a/timestamp.go +++ b/timestamp.go @@ -158,7 +158,7 @@ func (src Timestamp) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) { switch src.InfinityModifier { case None: - s = src.Time.Format(pgTimestampFormat) + s = src.Time.Truncate(time.Microsecond).Format(pgTimestampFormat) case Infinity: s = "infinity" case NegativeInfinity: diff --git a/timestamp_test.go b/timestamp_test.go index eec0a52e..2fdc7171 100644 --- a/timestamp_test.go +++ b/timestamp_test.go @@ -32,6 +32,51 @@ func TestTimestampTranscode(t *testing.T) { }) } +func TestTimestampNanosecondsTruncated(t *testing.T) { + tests := []struct { + input time.Time + expected time.Time + }{ + {time.Date(2020, 1, 1, 0, 0, 0, 999999999, time.UTC), time.Date(2020, 1, 1, 0, 0, 0, 999999000, time.UTC)}, + {time.Date(2020, 1, 1, 0, 0, 0, 999999001, time.UTC), time.Date(2020, 1, 1, 0, 0, 0, 999999000, time.UTC)}, + } + for i, tt := range tests { + { + ts := pgtype.Timestamp{Time: tt.input, Status: pgtype.Present} + buf, err := ts.EncodeText(nil, nil) + if err != nil { + t.Errorf("%d. EncodeText failed - %v", i, err) + } + + ts.DecodeText(nil, buf) + if err != nil { + t.Errorf("%d. DecodeText failed - %v", i, err) + } + + if !(ts.Status == pgtype.Present && ts.Time.Equal(tt.expected)) { + t.Errorf("%d. EncodeText did not truncate nanoseconds", i) + } + } + + { + ts := pgtype.Timestamp{Time: tt.input, Status: pgtype.Present} + buf, err := ts.EncodeBinary(nil, nil) + if err != nil { + t.Errorf("%d. EncodeBinary failed - %v", i, err) + } + + ts.DecodeBinary(nil, buf) + if err != nil { + t.Errorf("%d. DecodeBinary failed - %v", i, err) + } + + if !(ts.Status == pgtype.Present && ts.Time.Equal(tt.expected)) { + t.Errorf("%d. EncodeBinary did not truncate nanoseconds", i) + } + } + } +} + func TestTimestampSet(t *testing.T) { type _time time.Time diff --git a/timestamptz.go b/timestamptz.go index d390d266..100f44a5 100644 --- a/timestamptz.go +++ b/timestamptz.go @@ -160,7 +160,7 @@ func (src Timestamptz) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) { switch src.InfinityModifier { case None: - s = src.Time.UTC().Format(pgTimestamptzSecondFormat) + s = src.Time.UTC().Truncate(time.Microsecond).Format(pgTimestamptzSecondFormat) case Infinity: s = "infinity" case NegativeInfinity: diff --git a/timestamptz_test.go b/timestamptz_test.go index a020b1ec..a088fc08 100644 --- a/timestamptz_test.go +++ b/timestamptz_test.go @@ -32,6 +32,51 @@ func TestTimestamptzTranscode(t *testing.T) { }) } +func TestTimestamptzNanosecondsTruncated(t *testing.T) { + tests := []struct { + input time.Time + expected time.Time + }{ + {time.Date(2020, 1, 1, 0, 0, 0, 999999999, time.Local), time.Date(2020, 1, 1, 0, 0, 0, 999999000, time.Local)}, + {time.Date(2020, 1, 1, 0, 0, 0, 999999001, time.Local), time.Date(2020, 1, 1, 0, 0, 0, 999999000, time.Local)}, + } + for i, tt := range tests { + { + tstz := pgtype.Timestamptz{Time: tt.input, Status: pgtype.Present} + buf, err := tstz.EncodeText(nil, nil) + if err != nil { + t.Errorf("%d. EncodeText failed - %v", i, err) + } + + tstz.DecodeText(nil, buf) + if err != nil { + t.Errorf("%d. DecodeText failed - %v", i, err) + } + + if !(tstz.Status == pgtype.Present && tstz.Time.Equal(tt.expected)) { + t.Errorf("%d. EncodeText did not truncate nanoseconds", i) + } + } + + { + tstz := pgtype.Timestamptz{Time: tt.input, Status: pgtype.Present} + buf, err := tstz.EncodeBinary(nil, nil) + if err != nil { + t.Errorf("%d. EncodeBinary failed - %v", i, err) + } + + tstz.DecodeBinary(nil, buf) + if err != nil { + t.Errorf("%d. DecodeBinary failed - %v", i, err) + } + + if !(tstz.Status == pgtype.Present && tstz.Time.Equal(tt.expected)) { + t.Errorf("%d. EncodeBinary did not truncate nanoseconds", i) + } + } + } +} + func TestTimestamptzSet(t *testing.T) { type _time time.Time