Redshift - добавление смещения часового пояса (Varchar) к столбцу меток времени - PullRequest
0 голосов
/ 12 марта 2019

как часть ETL для Redshift, в одной из исходных таблиц есть 2 столбца: 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 и т. Д.

Кто-нибудь видел эту проблему раньше?Ценю любую помощь / вклад.Спасибо.

Ответы [ 2 ]

1 голос
/ 13 марта 2019

Просто возьмите часть смещения в часах:

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 голосов
/ 16 марта 2019

Во-первых, узнайте, что если ваши временные метки уже соответствуют местному времени данного смещения, то вам нужно вычесть это смещение, чтобы преобразовать обратно в 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.)

Однако у вас есть то, что смещения часового пояса не в формате, понятном для этих функций. См. примечания по использованию часового пояса . Итак, прежде чем мы попытаемся преобразовать, давайте переведем ваши строки смещения в понятный формат.

Мы хотим, чтобы -0700 стал +07:00. Двоеточие обязательно, и знак должен быть перевернут, потому что он будет интерпретирован в формате часового пояса в стиле POSIX. В этом формате положительные значения лежат запад Гринвичского времени вместо обычных соглашений, указанных в 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 здесь.

...