postgresql Postgres时区转换需要转换到不同的时区

lvjbypge  于 2023-06-22  发布在  PostgreSQL
关注(0)|答案(1)|浏览(219)

我试图在一个特定时区的特定时间获取当前日期,然后在Postgres中将其转换为UTC
我能够做到这一点,但它看起来超级怪异(看看最后)
让我们深入了解一下:
首先,我们要选择时区:Atlantic/Cape_Verde,因为它是UTC - 1,没有夏令时(因此更容易调试)
现在我们把它分成几部分
1.获取时区中的当前日期
1.设置该时区的时间
1.转换为UTC
我们假设现在是06/06/23 20:00(UTC)

1.获取时区当前日期:

-- 06/06/23
SELECT date(now() at time zone 'Atlantic/Cape_Verde');

2.设置该时区的时间:

-- 2023-06-06 03:00:00
SELECT date(now() at time zone 'Atlantic/Cape_Verde') + time '03:00';

3.转换为UTC:

出于某种原因,将其转换为UTC,我需要这样做:

-- 2023-06-06 04:00:00+00
SELECT (date(timezone('Atlantic/Cape_Verde', now())) + time '03:00') at time zone 'Atlantic/Cape_Verde'

为什么为了转换为UTC,我需要转换为我使用的时区??

blmhpbnm

blmhpbnm1#

Postgres有两种时间戳类型:

  • 带时区的时间戳,它代表历史上的特定时刻,Postgres会在会话中配置的时区返回给您。例如,2023-06-06 00:00:01+01是带有时区的时间戳。如果你想始终知道那是哪一天,或者是哪一个月,等等,那么你必须告诉Postgres你想要计算的时区,因为这个历史时刻可能是一个时区/地点的周二,而另一个时区/地点的周一。
  • 没有时区的时间戳,这是一个特定的时间戳文字,但不代表任何历史时刻,因为它不告诉你*时间在哪里2023-06-06 00:00:01是没有时区的时间戳。没有上下文,我们不知道它代表了什么历史时刻,因为不同的地方在不同的历史时刻有一个时间2023-06-06 00:00:01,但我们可以可靠地说这一天是2023-06-06,这是一个星期二。

令人困惑的是,这两种类型都没有与时区一起存储。

  1. now()返回一个带有时区的时间戳,这意味着在你将其转换为日期之前,你必须告诉Postgres你想要哪个时区的日期,因此:now() at time zone'Atlantic/Cape_Verde'给出了佛得角的当前时间,没有时区
    1.要将时间戳截断为日期,可以使用date_trunc('day', timestamp_without_time_zone),因此是date_trunc('day', now() at time zone'Atlantic/Cape_Verde')
    1.现在你得到了一个无时区的时间戳,它显示了佛得角的日期;你告诉Postgres该时间戳的相关时区应该是Cape Verde。因此,date_trunc('day', now() at time zone'Atlantic/Cape_Verde') at time zone'Atlantic/Cape_Verde'。现在你有一个时间戳,它表示佛得角一天开始的时刻,但由于它是一个带有时区的时间戳,Postgres将在会话的配置时区中将其作为带有时区的时间戳返回给你
    1.如果你把它保存为带有时区的时间戳,你就完成了!如果你需要一个没有时区的时间戳,它对应于UTC时区中的那个时刻,你必须告诉Postgres给予你相应的UTC时间:date_trunc('day', now() at time zone'Atlantic/Cape_Verde') at time zone'Atlantic/Cape_Verde' at time zone'Z'
    有关at time stamp构造的更多信息,请阅读原始文档
    您可以通过以下方式简化此操作:
    1.将时区传递到date_trunc,即date_trunc('day', now(),'Atlantic/Cape_Verde');(参见文档),它将返回带有时区的时间戳,所以
    1.之后,你只需要告诉Postgres你想要UTC时间。您可以通过以下方式执行此操作:date_trunc('day', now(),'Atlantic/Cape_Verde') at time zone'Z'

相关问题