2
0

Truncate nanoseconds in EncodeText for Timestamptz and Timestamp

PostgreSQL has microsecond precision. If more than this precision is
supplied in the text format it is rounded. This was inconsistent with
the binary format.

See https://github.com/jackc/pgx/issues/699 for original issue.
This commit is contained in:
Jack Christensen
2020-03-27 15:59:54 -05:00
parent 9e700ff067
commit 523cdad66f
4 changed files with 92 additions and 2 deletions
+1 -1
View File
@@ -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:
+45
View File
@@ -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
+1 -1
View File
@@ -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:
+45
View File
@@ -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