Repository: jackc/pgx (go)

Issue:
Invalid json unmarshal for pgtype.Timestamp
**Describe the bug**
`pgtype.Timestamp` use `time.RFC3338Nano` which expects timezone information. However, postgres don't return timezone information from a timestamp without time zone. As such:
```sql
select to_json(now()::timestamp without time zone) ;
           to_json            
------------------------------
 "2024-09-23T16:14:51.152496"
```

**To Reproduce**
Steps to reproduce the behavior:

```go
package main

import (
	"context"
	"log"
	"os"

	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/pgtype"
)

func main() {
	conn, err := pgx.Connect(context.Background(), os.Getenv("DATABASE_URL"))
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close(context.Background())

	row := conn.QueryRow(context.Background(), "select to_json(now()::timestamp)")
	var strTime string
	if err := row.Scan(&strTime); err != nil {
		panic(err)
	}

	var t pgtype.Timestamp
	if err := json.Unmarshal([]byte(strTime), &t); err != nil {
		panic(err) <-- panic here
	}
}
```

**Expected behavior**
`pgtype.Timestamp` parse the format of the timestamp returned by postgres

**Actual behavior**
`pgtype.Timestamp` expect timezone information from the string, but `timestamp` don't have timezone information.
```
panic: parsing time "2024-09-23T16:07:53.607446" as "2006-01-02T15:04:05.999999999Z07:00": cannot parse "" as "Z07:00"
```

**Version**
 - Go: go version go1.23.1 linux/amd64
 - PostgreSQL: PostgreSQL 16.3 on x86_64-pc-linux-gnu, compiled by Debian clang version 12.0.1, 64-bit
 - pgx: 5.7.1



Pull request:
Fix pgtype.Timestamp json unmarshal
Add the missing 'Z' at the end of the timestamp string, so it can be parsed as timestamp in the RFC3339 format.

Fix #2128 

Patch:
diff --git a/pgtype/timestamp.go b/pgtype/timestamp.go
index 677a2c6e..ff2739d6 100644
--- a/pgtype/timestamp.go
+++ b/pgtype/timestamp.go
@@ -104,8 +104,8 @@ func (ts *Timestamp) UnmarshalJSON(b []byte) error {
 	case "-infinity":
 		*ts = Timestamp{Valid: true, InfinityModifier: -Infinity}
 	default:
-		// PostgreSQL uses ISO 8601 for to_json function and casting from a string to timestamptz
-		tim, err := time.Parse(time.RFC3339Nano, *s)
+		// PostgreSQL uses ISO 8601 wihout timezone for to_json function and casting from a string to timestampt
+		tim, err := time.Parse(time.RFC3339Nano, *s+"Z")
 		if err != nil {
 			return err
 		}
@@ -225,7 +225,6 @@ func discardTimeZone(t time.Time) time.Time {
 }
 
 func (c *TimestampCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan {
-
 	switch format {
 	case BinaryFormatCode:
 		switch target.(type) {


Test patch:
diff --git a/pgtype/timestamp_test.go b/pgtype/timestamp_test.go
index 31b3ad82..345da819 100644
--- a/pgtype/timestamp_test.go
+++ b/pgtype/timestamp_test.go
@@ -128,8 +128,8 @@ func TestTimestampUnmarshalJSON(t *testing.T) {
 		result pgtype.Timestamp
 	}{
 		{source: "null", result: pgtype.Timestamp{}},
-		{source: "\"2012-03-29T10:05:45Z\"", result: pgtype.Timestamp{Time: time.Date(2012, 3, 29, 10, 5, 45, 0, time.UTC), Valid: true}},
-		{source: "\"2012-03-29T10:05:45.555Z\"", result: pgtype.Timestamp{Time: time.Date(2012, 3, 29, 10, 5, 45, 555*1000*1000, time.UTC), Valid: true}},
+		{source: "\"2012-03-29T10:05:45\"", result: pgtype.Timestamp{Time: time.Date(2012, 3, 29, 10, 5, 45, 0, time.UTC), Valid: true}},
+		{source: "\"2012-03-29T10:05:45.555\"", result: pgtype.Timestamp{Time: time.Date(2012, 3, 29, 10, 5, 45, 555*1000*1000, time.UTC), Valid: true}},
 		{source: "\"infinity\"", result: pgtype.Timestamp{InfinityModifier: pgtype.Infinity, Valid: true}},
 		{source: "\"-infinity\"", result: pgtype.Timestamp{InfinityModifier: pgtype.NegativeInfinity, Valid: true}},
 	}