在BigQuery

时间:2017-01-10 17:03:43

标签: sql google-bigquery

我已经多次梳理了Google的documentation,但我似乎无法找到一个简单的函数(在SELECT查询中)将UTC时间戳转换为不同的时区,我的案子是太平洋。对于大多数国际时区,我只需使用TIMESTAMP_SUBTIMESTAMP_ADD来减去/添加偏移小时数,但美国使用夏令时会使事情变得复杂(不必要!)。

我是否遗漏了文档中的内容?或者还有其他方法可以轻松转换为另一个时区吗?

4 个答案:

答案 0 :(得分:2)

TIMESTAMP类型与UTC绑定。当您将TIMESTAMP转换为与特定时区无关的其他类型时,例如STRINGDATEDATETIME,您可以指定转换的时区,例如:

SELECT EXTRACT(DATE FROM CURRENT_TIMESTAMP()
               AT TIME ZONE 'America/Los_Angeles') AS current_pst_day;

如果你想要不同时区之间的(当前)小时数,你可以使用不同时区的CURRENT_DATETIME()并采取不同的方法:

SELECT
  time_zone,
  DATETIME_DIFF(CURRENT_DATETIME(time_zone),
                CURRENT_DATETIME(), HOUR) AS hours_from_utc
FROM UNNEST(['America/Los_Angeles', 'America/New_York']) AS time_zone;
+---------------------+----------------+
| time_zone           | hours_from_utc |
+---------------------+----------------+
| America/Los_Angeles | -8             |
| America/New_York    | -5             |
+---------------------+----------------+

为了使偏移更方便,您可以将其包装到SQL函数中,然后调用它以将偏移量添加到特定时间戳:

CREATE TEMP FUNCTION OffsetForTimeZone(t TIMESTAMP, time_zone STRING) AS (
  TIMESTAMP_ADD(t, INTERVAL DATETIME_DIFF(CURRENT_DATETIME(time_zone),
                                          CURRENT_DATETIME(), HOUR) HOUR)
);

SELECT OffsetForTimeZone(CURRENT_TIMESTAMP(), 'America/Los_Angeles');

请注意,此结果仍然是TIMESTAMP与UTC相关联,尽管会被当前与太平洋时间之间的差异所抵消。

答案 1 :(得分:1)

作为Elliott答案的附录,我想测试时区数学是否适用于夏令时变化:

#standardSQL
WITH dates AS (
  SELECT TIMESTAMP('2015-07-01') x, 'summer' season
  UNION ALL SELECT TIMESTAMP('2015-01-01') x, 'winter' season
)

SELECT
  season,
  time_zone,
  DATETIME_DIFF(DATETIME(x, time_zone),
                DATETIME(x), HOUR) AS hours_from_utc
FROM UNNEST(['America/Los_Angeles', 'America/New_York']) AS time_zone
CROSS JOIN dates 
ORDER BY 1,2

它确实:

+--------+---------------------+----------------+
| season |      time_zone      | hours_from_utc |
+--------+---------------------+----------------+
| summer | America/Los_Angeles |             -7 |
| summer | America/New_York    |             -4 |
| winter | America/Los_Angeles |             -8 |
| winter | America/New_York    |             -5 |
+--------+---------------------+----------------+

它甚至意识到智利在2015年没有通过DST:

#standardSQL
WITH dates AS (
  SELECT TIMESTAMP('2014-07-01') x
  UNION ALL SELECT TIMESTAMP('2015-07-01') x
  UNION ALL SELECT TIMESTAMP('2016-07-01') x
)

SELECT
  EXTRACT(YEAR FROM x),
  time_zone,
  DATETIME_DIFF(DATETIME(x, time_zone),
                DATETIME(x), HOUR) AS hours_from_utc
FROM UNNEST(['Chile/Continental', 'America/New_York']) AS time_zone
CROSS JOIN dates 
ORDER BY 2,2


+------+-------------------+----------------+
| f0_  |     time_zone     | hours_from_utc |
+------+-------------------+----------------+
| 2014 | America/New_York  |             -4 |
| 2015 | America/New_York  |             -4 |
| 2016 | America/New_York  |             -4 |
| 2014 | Chile/Continental |             -4 |
| 2015 | Chile/Continental |             -3 |
| 2016 | Chile/Continental |             -4 |
+------+-------------------+----------------+

答案 2 :(得分:0)

由于最初发布我的问题,我只是使用带有偏移的TIMESTAMP_SUB函数将默认的UTC时间戳转换为我想要的时区;我之前没有使用Elliot优雅的解决方案,因为它要求我创建一个Tableau的自定义SQL功能不允许的功能。

对于任何有兴趣的人,我现在已经找到了另一种解决方案,尽管它很丑陋。当从一种格式转换为另一种格式时,BigQuery允许内置时区偏移(例如,“America / Los_Angeles”)。例如,从timestamp到datetime:

SELECT DATETIME(CURRENT_TIMESTAMP(),"America/Los_Angeles")

示例从当前UTC时间到太平洋时间。但是,它现在采用日期时间格式,Tableau无法将其识别为日期/时间对象。为了使其恢复为时间戳格式,我将上面的函数包含在TIMESTAMP函数中:

SELECT TIMESTAMP(DATETIME(CURRENT_TIMESTAMP(),"America/Los_Angeles"))

愚蠢,不优雅,减慢约20%,但似乎有效。

答案 3 :(得分:0)

这应该有效:

SELECT CURRENT_DATE("America/Los_Angeles")