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