Go语言 如何设置pgx从数据库中获取UTC值?

f1tvaqid  于 2023-06-27  发布在  Go
关注(0)|答案(2)|浏览(119)

我使用EntPgx
Postgres中创建的列为:

used_at timestamp with time zone NOT NULL,

Postgres中的值保存时不带时区(UTC):

2022-06-30 22:49:03.970913+00

使用此查询:

show timezone

我得到:

Etc/UTC

但是从Ent(使用pgxstdlib)我得到了值:

2022-07-01T00:49:03.970913+02:00

使用pgdriver/pq从DB获取UTC值。
如何设置pgx以获取UTC值?
我也试着在下面的代码中使用这个连接字符串:

import (
    "database/sql"
    _ "github.com/jackc/pgx/v4/stdlib"
)

conn, err := sql.Open("pgx", "postgres://postgres:postgres@localhost/project?sslmode=disable&timezone=UTC")
//handle err

问题还在这里。

    • 我需要一种方法来从数据库中获取UTC值(已存储在数据库中)。**
8fq7wneg

8fq7wneg1#

timezone不是有效的 * 参数关键字 *。
但是,您可以使用options关键字指定在连接开始时发送到服务器的命令行选项。请记住,您需要percent encode其中的值。
如何设置TimeZone的示例:

package main

import (
    "context"
    "fmt"
    "github.com/jackc/pgx/v4"
)

func main() {
    ctx := context.Background()

    c1, err := pgx.Connect(ctx, "postgres:///?sslmode=disable")
    if err != nil {
        panic(err)
    }
    defer c1.Close(ctx)

    // sends "-c TimeZone=UTC" to server at connection start
    c2, err := pgx.Connect(ctx, "postgres:///?sslmode=disable&options=-c%20TimeZone%3DUTC")
    if err != nil {
        panic(err)
    }
    defer c2.Close(ctx)

    var tz1, tz2 string
    if err := c1.QueryRow(ctx, "SHOW timezone").Scan(&tz1); err != nil {
        panic(err)
    }
    if err := c2.QueryRow(ctx, "SHOW timezone").Scan(&tz2); err != nil {
        panic(err)
    }
    fmt.Println(tz1)
    fmt.Println(tz2)
}
Europe/Prague
UTC

然而,这只强制连接的时区,这似乎不会影响pgx如何解析从数据库读取的时间戳本身。事实上,它似乎直接或间接地依赖于主机的本地时区。确认您可以将全局time.Local变量更新为UTC并观察差异。

// ...

    var t1, t2 time.Time
    if err := c1.QueryRow(ctx, "select now()::timestamptz").Scan(&t1); err != nil {
        panic(err)
    }
    if err := c2.QueryRow(ctx, "select now()::timestamptz").Scan(&t2); err != nil {
        panic(err)
    }
    fmt.Println(t1)
    fmt.Println(t2)

    // explicitly set Local to UTC
    time.Local = time.UTC
    if err := c1.QueryRow(ctx, "select now()::timestamptz").Scan(&t1); err != nil {
        panic(err)
    }
    if err := c2.QueryRow(ctx, "select now()::timestamptz").Scan(&t2); err != nil {
        panic(err)
    }
    fmt.Println(t1)
    fmt.Println(t2)
}
Europe/Prague
UTC
2022-06-27 17:18:13.189557 +0200 CEST
2022-06-27 17:18:13.190047 +0200 CEST
2022-06-27 15:18:13.190401 +0000 UTC
2022-06-27 15:18:13.190443 +0000 UTC

出于显而易见的原因,我会避免做上述事情。如果pgx不提供配置用来解析时间戳的默认位置的方法,那么我能想到的下一个最好的选择是使用自定义time.Time类型。

// ...

    var t1, t2 time.Time
    if err := c1.QueryRow(ctx, "select now()::timestamptz").Scan(&t1); err != nil {
        panic(err)
    }
    if err := c2.QueryRow(ctx, "select now()::timestamptz").Scan(&t2); err != nil {
        panic(err)
    }
    fmt.Println(t1)
    fmt.Println(t2)

    var tt1, tt2 myTime
    if err := c1.QueryRow(ctx, "select now()::timestamptz").Scan(&tt1); err != nil {
        panic(err)
    }
    if err := c2.QueryRow(ctx, "select now()::timestamptz").Scan(&tt2); err != nil {
        panic(err)
    }
    fmt.Println(tt1)
    fmt.Println(tt2)
}

type myTime struct {
    time.Time
}

func (tt *myTime) Scan(src interface{}) error {
    if t, ok := src.(time.Time); ok {
        tt.Time = t.In(time.UTC)
        return nil
    }
    return fmt.Errorf("myTime: unsupported type %T", src)
}
Europe/Prague
UTC
2022-06-27 17:26:45.94049 +0200 CEST
2022-06-27 17:26:45.940959 +0200 CEST
2022-06-27 15:26:45.941321 +0000 UTC
2022-06-27 15:26:45.941371 +0000 UTC
mspsb9vt

mspsb9vt2#

您可以将应用程序配置为全局使用UTC:

package main

import "time"

func main() {

    location, _ := time.LoadLocation("UTC")
    time.Local = location
    
    // setup db connection
    // ...
}

相关问题