Redshift - 将时区偏移量(Varchar)添加到时间戳列

问题描述 投票:0回答:2

作为ETL到Redshift的一部分,在其中一个源表中,有两列:original_timestamp - TIMESTAMP:这是在任何区域中插入记录的本地时间original_timezone_offset - Varchar:这是UTC的偏移量

数据看起来像这样:

original_timestamp      original_timezone_offset
2011-06-22 11:00:00.000000    -0700
2014-11-29 17:00:00.000000    -0800
2014-12-02 22:00:00.000000    +0900
2011-06-03 09:23:00.000000    -0700
2011-07-28 03:00:00.000000    -0700
2011-05-01 01:30:00.000000    -0700

在我的目标表中,我需要将其转换为UTC(使用偏移量)。我该怎么做?到目前为止,我尝试过多种方法,但dateadd()似乎是最接近的解决方案。但是当我说:dateadd()的问题是:

SELECT original_timestamp, original_timezone_offset
 ,dateadd(H, original_timezone_offset, original_timestamp) as original_utc_time

它是在原始时间戳上加/减'700'/'800'小时而不是7/8小时,因为偏移量是一个VARCHAR,值类似于:-0700等。

之前有人看过这个问题吗?感谢任何帮助/输入。谢谢。

amazon-web-services amazon-redshift timezone-offset
2个回答
1
投票

只需占用偏移量的“小时”部分:

WITH t as (
SELECT  '2011-06-22 11:00:00.000000'::timestamp as original_timestamp, '-0700' as original_timezone_offset
UNION ALL
SELECT '2014-11-29 17:00:00.000000'::timestamp,'-0800'
UNION ALL
SELECT '2014-12-02 22:00:00.000000'::timestamp,'+0900'
)
SELECT
  original_timestamp,
  original_timezone_offset,
  DATEADD(hour, SUBSTRING(original_timezone_offset, 1, 3)::INT, original_timestamp)
FROM t

2011-06-22 11:00:00 -0700   2011-06-22 04:00:00
2014-11-29 17:00:00 -0800   2014-11-29 09:00:00
2014-12-02 22:00:00 +0900   2014-12-03 07:00:00

如果您有非全时小时偏移(例如+0730),则需要一些额外的花哨代码。


0
投票

首先,要认识到如果您的时间戳已经在给定偏移量的本地时间内,那么您需要减去该偏移量以转换回UTC。在你给出的第一个例子中,2011-06-22 11:00:00 -0700相当于2011-06-22 18:00:00 UTC

但是,您应该让AT TIME ZONE函数为您完成工作,而不是尝试自己添加或减去这些值。它将创建一个在您提供的偏移量中的timestamptz,然后您可以再次使用它转换为UTC。

(请注意,您可以使用CONVERT_TIMEZONE函数,但只有Redshift才能理解它,其中AT TIME ZONE也适用于常规的PostgreSQL。)

但是,您所拥有的时区偏移量不是这些函数所理解的格式。见time zone usage notes。因此,在我们尝试转换之前,让我们将偏移字符串转换为理解格式。

我们希望-0700成为+07:00。冒号是必需的,并且必须翻转符号,因为它将使用POSIX样式的时区格式进行解释。在该格式中,正值位于GMT以西,而不是ISO 8601中规定的通常惯例。

concat(translate(substring(original_timezone_offset, 1, 3), '-+', '+-'),':',substring(original_timezone_offset, 4, 2))

然后我们将使用AT TIME ZONE进行转换:

(original_timezone AT TIME ZONE <the above mess>) AT TIME ZONE 'UTC' AS utc_timestamp

把它们放在一起......

WITH t as (
SELECT  '2011-06-22 11:00:00.000000'::timestamp as original_timestamp, '-0700' as original_timezone_offset
UNION ALL
SELECT '2014-11-29 17:00:00.000000'::timestamp,'-0800'
UNION ALL
SELECT '2014-12-02 22:00:00.000000'::timestamp,'+0900'
)
SELECT
  original_timestamp,
  original_timezone_offset,
  concat(translate(substring(original_timezone_offset, 1, 3), '-+', '+-'),':',substring(original_timezone_offset, 4, 2)) as modified_timezone_offset,
  (original_timestamp AT TIME ZONE concat(translate(substring(original_timezone_offset, 1, 3), '-+', '+-'),':',substring(original_timezone_offset, 4, 2))) AT TIME ZONE 'UTC' AS utc_timestamptz
FROM t

输出:

2011-06-22 11:00:00  -0700  +07:00  2011-06-22 18:00:00
2014-11-29 17:00:00  -0800  +08:00  2014-11-30 01:00:00
2014-12-02 22:00:00  +0900  -09:00  2014-12-02 13:00:00

SQL Fiddle here.

© www.soinside.com 2019 - 2024. All rights reserved.