I'm trying to set the session timezone variable that Postgres allows in the connection string but I'm not familiar how to do it using pgx. I tried to do the following below but it did not work.
runtimeParams := make(map[string]string)
runtimeParams["timezone"] = "UTC"
config := pgx.ConnConfig{
Host: host,
Port: port,
User: user,
Password: password,
Database: database,
RuntimeParams: runtimeParams,
}
Works for me.
package main
import (
"log"
"os"
"github.com/jackc/pgx"
)
func main() {
config, err := pgx.ParseURI(os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal(err)
}
if s := os.Getenv("PGX_TIMEZONE"); s != "" {
config.RuntimeParams["timezone"] = s
}
conn, err := pgx.Connect(config)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
var tz string
err = conn.QueryRow("select current_setting('TIMEZONE')").Scan(&tz)
if err != nil {
log.Fatal(err)
}
log.Println("select current_setting('TIMEZONE') => ", tz)
}
Example runs:
jack@happy:~/go/src/github.com/jackc/pgx-520$ go run main.go
2019/03/23 12:03:20 select current_setting('TIMEZONE') => localtime
jack@happy:~/go/src/github.com/jackc/pgx-520$ PGX_TIMEZONE=UTC go run main.go
2019/03/23 12:03:31 select current_setting('TIMEZONE') => UTC
jack@happy:~/go/src/github.com/jackc/pgx-520$ PGX_TIMEZONE=Europe/Berlin go run main.go
2019/03/23 12:03:43 select current_setting('TIMEZONE') => Europe/Berlin
Works for me.
How to get correct timestamp with this setting?
package main
import (
"log"
"os"
"time"
"github.com/jackc/pgx"
)
func main() {
config, err := pgx.ParseURI(os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal(err)
}
if s := os.Getenv("PGX_TIMEZONE"); s != "" {
config.RuntimeParams["timezone"] = s
}
conn, err := pgx.Connect(config)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
var tz string
var tm time.Time
err = conn.QueryRow("select current_setting('TIMEZONE'), now()").Scan(&tz, &tm)
if err != nil {
log.Fatal(err)
}
log.Printf("TIMEZONE: %s, NOW %v\n", tz, tm)
}
Shows:
$ go run main.go
2019/04/03 23:43:11 TIMEZONE: UTC, NOW 2019-04-03 23:43:11.741484 +0300 MSK
$ PGX_TIMEZONE=Europe/Berlin go run main.go
2019/04/03 23:43:12 TIMEZONE: Europe/Berlin, NOW 2019-04-03 23:43:12.097781 +0300 MSK
Meanwhile this gives correct timestamp (but not setting):
TZ=Europe/Berlin go run main.go
2019/04/03 22:43:12 TIMEZONE: UTC, NOW 2019-04-03 22:43:12.454271 +0200 CEST
That is because of different time zones in Go and PostgreSQL. The timestamp with time zone type in PostgreSQL actually doesn't have time zone information. It converts from the client time zone to UTC on the way in and from UTC to the client time zone on the way out. But all it is internally is an int64 of the number of microseconds from 2000-01-01 00:00:00 UTC. And that is what pgx gets over the wire from PostgreSQL (using the binary protocol which is the default).
If you want to display it in a different time zone in Go you will need to convert it there. (e.g. https://golang.org/pkg/time/#Time.In).
Yes, Time.In() allows to change TZ per var, but how to change all of them?
With postgresql clients like psql I can set timezone once and get all of timestamptz values in that timezone.
With pgx I've found TZ=.. go run but might be there is a way better?
The TZ environment variable is probably what you want then.
So, there are 2 ways to show pgx result's timestamptz in some requested timezone:
and this problem is not related with RuntimeParams["timezone"]
Am I right?
Correct.
Ok, thank you.
Sorry if my posts were an offtopic for this issue
That is because of different time zones in Go and PostgreSQL. The
timestamp with time zonetype in PostgreSQL actually doesn't have time zone information. It converts from the client time zone to UTC on the way in and from UTC to the client time zone on the way out. But all it is internally is anint64of the number of microseconds from2000-01-01 00:00:00 UTC. And that is what pgx gets over the wire from PostgreSQL (using the binary protocol which is the default).If you want to display it in a different time zone in Go you will need to convert it there. (e.g. https://golang.org/pkg/time/#Time.In).
Does this mean that even if we explicitly query using AT TIME ZONE 'utc' i.e)
select valid_from AT TIME ZONE 'utc' FROM sometable;
pgx anyways scans and returns to me in my local timezone unless the appropriate environment variable is added?.
at time zone converts a timestamp with time zone to a timestamp without time zone in the specified zone.
e.g.
jack@[local:/private/tmp]:5432 jack=# select pg_typeof(now()), pg_typeof(now() AT TIME ZONE 'utc');
pg_typeof โ pg_typeof
โโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
timestamp with time zone โ timestamp without time zone
Thanks @jackc , makes sense now.
Most helpful comment
So, there are 2 ways to show pgx result's timestamptz in some requested timezone:
and this problem is not related with
RuntimeParams["timezone"]Am I right?