如何比较不同时区的时间戳?

7ca*_*ect 5 postgresql timestamp timezone

例如,我有一个带有时间戳的表:

    2018-04-05 06:00:00 +01
    2018-04-05 06:00:00 +00
    2018-04-05 06:00:00 -01
    2018-04-05 04:00:00 -01
Run Code Online (Sandbox Code Playgroud)

我想要获得的条目是......

BETWEEN 2018-04-05 06:00:00+01 AND 2018-04-05 07:00:00+01
Run Code Online (Sandbox Code Playgroud)

所以我的输出是:

    2018-04-05 06:00:00 +01
    2018-04-05 04:00:00 -01
Run Code Online (Sandbox Code Playgroud)

操作员会BETWEEN自动处理时区差异并为我提供所需的输出吗?

Erw*_*ter 4

这才有效:

\n\n
SELECT *, ts AT TIME ZONE \'-01\'  -- see below about \'-1\' vs \'+1\'\nFROM  (\n   VALUES \n   (1, timestamptz \'2018-04-05 06:00:00 +01\')\n , (2,             \'2018-04-05 06:00:00 +00\')\n , (3,             \'2018-04-05 06:00:00 -01\')\n , (4,             \'2018-04-05 04:00:00 -01\')\n   ) t(id, ts)\nWHERE  ts BETWEEN \'2018-04-05 06:00:00+01\'  -- coerced to timestamptz\n              AND \'2018-04-05 07:00:00+01\'; -- derived from context!\n
Run Code Online (Sandbox Code Playgroud)\n\n

但请注意这里的几个陷阱和潜在的误解

\n\n
    \n
  • SQL构造BETWEEN ... AND(严格来说不是一个函数;实际上更像是一个运算符)与时区无关。这将是对事物运作方式的误解。

  • \n
  • 请注意两种不同的数据类型timestamp( timestamp without time zone) 和timestamptz( timestamp with time zone)。看:

    \n\n
  • \n
  • 特别是,文字中的时区偏移量timestamptz仅用作值的输入/输出修饰符,并且根本不存储。仅内部存储相应的 UTC 时间。看:

    \n\n
  • \n
  • 请注意由于 POSIX 和 SQL 标准之间的分歧,时间戳文字和时区说明符(翻转符号)之间存在奇怪的语法差异:

    \n\n
  • \n
  • 您显示的输出(具有不同的时区偏移量)不能通过简单地返回timestamptz值来实现:

    \n\n
    \n
    2018-04-05 06:00:00 +01\n2018-04-05 04:00:00 -01\n
    Run Code Online (Sandbox Code Playgroud)\n
    \n\n

    timestamptz值始终根据会话的设置显示。timezone要获取显示的字符串(针对不同的时区),您必须保留输入的时区偏移量并使用它来格式化输出。(或将完整的输入文字存储为text

  • \n
  • 最后,请注意“2018-04-05 04:00:00 -01”也通过了测试,因为它与“2018-04-05 06:00:00+01”的完全相同',只是格式不同(同一时间点,针对不同时区显示)。\n因此,在您的示例中,三行通过了测试,而不仅仅是两行。timestamptz

  • \n
\n\n

如果您现在头晕目眩,请考虑这个演示:\n

\n\n
\n
WITH tbl AS (\n   SELECT *\n        , split_part(tstz_string, \' \', 3) AS tz_string\n        , tstz_string::timestamptz AS tstz\n   FROM  (\n      VALUES \n      (1, \'2018-04-05 06:00:00 +01\')\n    , (2, \'2018-04-05 06:00:00 +00\')\n    , (3, \'2018-04-05 06:00:00 -01\')\n    , (4, \'2018-04-05 04:00:00 -01\')\n      ) t(id, tstz_string)\n   )\nSELECT *\n     , to_char(tz_string::numeric * -1, \'SG00\')                                       AS tz_posix\n     ,  tstz AT TIME ZONE (tz_string::numeric * -1)::text AS ts_at_org_tz\n     , (tstz AT TIME ZONE (tz_string::numeric * -1)::text)::text || \' \' ||  tz_string AS tstz_org\n     , (tstz AT TIME ZONE (tz_string::numeric * -1)::text)::text || \' \' ||  tz_string \n      = tstz_string                                                                   AS strings_equal\nFROM   tbl;\n
Run Code Online (Sandbox Code Playgroud)\n\n
\nid | tstz_string | tz_string | tsz | tz_posix | ts_at_org_tz | ts_at_org_tz | tstz_org | strings_equal\n-: | :---------------------- | :-------- | :-------------------- | :----- | :------------------ | :---------------------- | :------------\n 1 | 2018-04-05 06:00:00 +01 | +01 | 2018-04-05 06:00:00+01 | -01 | 2018-04-05 06:00:00 | 2018-04-05 06:00:00 +01 | t \n 2 | 2018-04-05 06:00:00 +00 | +00 | 2018-04-05 07:00:00+01 | +00 | 2018-04-05 06:00:00 | 2018-04-05 06:00:00 +00 | t \n 3 | 2018-04-05 06:00:00 -01 | -01 | 2018-04-05 08:00:00+01 | +01 | 2018-04-05 06:00:00 | 2018-04-05 06:00:00 -01 | t \n 4 | 2018-04-05 04:00:00 -01 | -01 | 2018-04-05 06:00:00+01 | +01 | 2018-04-05 04:00:00 | 2018-04-05 04:00:00 -01 | t\n
\n
\n\n

db<>在这里摆弄

\n