如何设置PGX从DB获取UTC值?

发布于 2025-02-10 19:19:13 字数 1120 浏览 1 评论 0原文

我正在使用 ent 带有 pgx

Postgres中创建的列是:

used_at timestamp with time zone NOT NULL,

Postgres中的值是在没有时区(在UTC中)的:

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

使用此查询:

show timezone

我获取:

Etc/UTC

但是从ENT(使用pgx stdlib)i获取值:

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

问题仍在这里。

我需要一种从db的UTC值(存储在DB中的Laready)的方法。

I'm using Ent with Pgx.

The column created in Postgres is:

used_at timestamp with time zone NOT NULL,

The value in Postgres is saved without timezone (in UTC):

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

Using this query:

show timezone

I get:

Etc/UTC

But from Ent (using pgx stdlib) I get the value:

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

Using pgdriver/pq I get the UTC value from DB.

How can I setup pgx to get UTC value?

I tried using this connection string with this code too:

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

The problem is still here.

I need a way to get back from DB the UTC values (that are laready stored in the DB).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怎会甘心 2025-02-17 19:19:14

timezone不是有效参数键字

但是,您可以使用 关键字指定命令行选项,以在连接启动时发送到服务器。请记住,您需要%encode 其中。

如何设置代码>

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一旦从数据库中读取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没有提供一种配置用于解析时间戳的默认位置的方法类型。

    // ...

    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

timezone is not a valid parameter key word.

You can however use the options key word to specify command-line options to send to the server at connection start. Just keep in mind that you need to percent encode the values therein.

Example of how to set the 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

However this only enforces the connection's timezone which does not seem to have an effect on how pgx parses the timestamps themselves once read from the database. In fact it seems it relies, directly or indirectly, on the host machine's local timezone. To confirm that you can update the global time.Local variable to UTC and observe the difference.

    // ...

    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

For obvious reasons I'd avoid doing the above. If pgx doesn't provide a way to configure the default location it uses to parse the timestamps then the next best option, that I can think of, would be to use a custom time.Time type.

    // ...

    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
半世晨晓 2025-02-17 19:19:14

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

package main

import "time"

func main() {

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

You can configure your application to use UTC globally:

package main

import "time"

func main() {

    location, _ := time.LoadLocation("UTC")
    time.Local = location
    
    // setup db connection
    // ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文