【问题标题】:BigQuery converting to a different timezoneBigQuery 转换为不同的时区
【发布时间】:2012-09-11 01:10:57
【问题描述】:

我在 google big query 上将数据存储在 unixtimestamp 中。但是,当用户要求报告时,她需要按当地时区过滤和分组数据。

数据以格林威治标准时间存储。用户可能希望查看 EST 中的数据。报告可能会要求按日期对数据进行分组。

我看不到时区转换功能here

有谁知道我如何在 bigquery 中做到这一点?即在将时间戳转换为不同的时区后如何分组?

【问题讨论】:

    标签: datetime timezone google-bigquery


    【解决方案1】:

    2016 年更新请看下面的答案,BigQuery 现在提供时间戳和时区方法


    您是对的 - BigQuery 不提供任何时间戳转换方法。

    在这种情况下,我建议您根据 GMT/UTC 时间戳字段的维度运行 GROUP BY,然后在代码中转换并显示本地时区的结果。

    【讨论】:

    • 嗨迈克尔,感谢您的回复。问题是假设我需要按日期分组的数据。现在,数据需要按本地时区的日期分组。即如果今天格林威治标准时间凌晨 1 点,实际上它是美国东部标准时间昨天。我必须按每个时间戳值对数据进行分组并返回它。但是,这将需要大量的网络 IO 和整体报告的非常慢的性能。有什么技巧可以解决吗?
    • 为什么不在每条记录中都有一个记录用户本地时区的列?然后,您可以快速遍历结果行并提供正确的显示日期。
    • 我们确实考虑过这个选项,但问题是多个用户可能会请求查看相同的数据。因此,将每个可能的转换中的值与记录一起存储是不切实际的。但是,目前我们只有 EST 中的用户,因此我们可以选择这条路线。一旦我们有该地区以外的用户,这将是一个问题。
    • 顺便问一下,有没有什么地方可以建议在大查询中添加这个功能?
    • 更新:我们已经启动了一个新的 Google BigQuery 公共问题跟踪器来帮助发现功能请求和错误报告:code.google.com/p/google-bigquery
    【解决方案2】:

    你的前提是正确的。如果你这样分组,那么想要 EST 或 EDT 的用户将得到错误的日期分组:

    GROUP BY UTC_USEC_TO_DAY(ts_field)
    

    但是只要你算出你的用户想要的偏移量,你仍然可以在服务器上进行完整的计算。例如,如果 EST 比 UTC 晚 5 小时,则查询如下:

    GROUP BY UTC_USEC_TO_DAY(ts_field - (5*60*60*1000*1000000) )
    

    只需将“5”参数化为以小时为单位的偏移量,一切就绪。以下是基于其中一个示例数据集的示例:

    SELECT
      COUNT(*) as the_count,
      UTC_USEC_TO_DAY(timestamp * 1000000 - (5*60*60*1000*1000000) ) as the_day
    FROM
      [publicdata:samples.wikipedia]
    WHERE
      comment CONTAINS 'disaster'
      and timestamp >= 1104537600
    GROUP BY
      the_day
    ORDER BY
      the_day
    

    您可以删除偏移量以查看某些编辑如何移动到不同的日期。

    【讨论】:

    • 您好,感谢您的反馈。这将适用于直接转换。但是,夏令时会引发问题,因为您不能只使用静态值。
    • 同意:您需要您的应用(或您的用户!)找出他们想要的偏移量。这并不是一个真正理想的解决方案。您肯定会错过一些极端情况,例如夏令时开始或结束之日“今天”的确切边界是什么。但它可以满足许多需求。
    • 我们采用同样的方法。
    【解决方案3】:

    截至 2016 年 9 月,BigQuery 已采用标准 SQL,您现在只需使用“DATE(timestamp, timezone)”函数来偏移时区。您可以在此处参考他们的文档:

    BigQuery DATE docs

    【讨论】:

    • 确实这个功能是新的,但是并没有解决问题。如果您有时间戳,通常需要一个新的时间戳。该函数接受时间戳并输出日期。
    • @DennisJaheruddin A timestamp 是一个绝对时间点(BigQuery 的 Unix 纪元微秒)。没有“新”时间戳可获取。如果您希望在特定时区中表示该时间点,则必须将该绝对时间转换为逻辑日历时间,通常由date 表示。这正是这个函数的作用。
    • @ManiGandham 我不明白你的回答,我在说的是这个命令将 1-jan-2001 07:00:00 (不要介意格式)更改为 1 2001 年 1 月,所以它只是没有时间的日期。
    • @DennisJaheruddin 你读过文档吗?如果您需要 DateTime 结果,则可以改用 DATETIME(timestamp, timezone)cloud.google.com/bigquery/docs/reference/standard-sql/…
    • 在那种情况下,我要么错过了它,要么文档自我在 2 月份检查以来已经更新。不管怎样,很高兴你发布了这个答案。
    【解决方案4】:

    BigQuery 中的标准 SQL 具有 built-in functions:

    DATE(timestamp_expression, timezone)
    TIME(timestamp, timezone)
    DATETIME(timestamp_expression, timezone)
    

    例子:

    SELECT 
       original,
       DATETIME(original, "America/Los_Angeles") as adjusted
    FROM sometable;
    
    +---------------------+---------------------+
    | original            | adjusted            |
    +---------------------+---------------------+
    | 2008-12-25 05:30:00 | 2008-12-24 21:30:00 |
    +---------------------+---------------------+
    

    您可以使用标准的IANA timezone names or offsets

    【讨论】:

      【解决方案5】:

      要将任何 TimeZone DateTime 字符串转换为 UTC,可以使用 BigQuery 中支持的 TIMESTAMP 格式使用 PARSE_TIMESTAMP

      例如,要将 IST(印度标准时间)字符串转换为 UTC,请使用以下命令:

      SAFE.PARSE_TIMESTAMP("%a %b %d %T IST %Y", timeStamp_vendor, "Asia/Kolkata")
      

      这里 PARSE_TIMESTAMP 将 IST 字符串解析为 UTC TIMESTAMP(不是字符串)。添加SAFE 作为前缀可以处理错误/空值等问题。

      要将其转换为BigQuery 中的可读字符串格式,请使用FORMAT_TIMESTAMP,如下所示:

      FORMAT_TIMESTAMP("%d-%b-%Y %T %Z", SAFE.PARSE_TIMESTAMP("%a %b %d %T IST %Y", timeStamp_vendor, "Asia/Kolkata"))
      

      此示例将采用 Fri May 12 09:45:12 IST 2019 格式的 IST 字符串并将其转换为 12-May-2019 04:15:12 UTC

      将 IST 替换为所需的时区,将 Asia/Kolkata 替换为相关的时区名称,以实现您的时区的转换

      【讨论】:

        【解决方案6】:

        对我来说,TIMESTAMP_SUBTIMESTAMP_ADD 函数完成了这项工作。当需要将时间戳从 UTC 转换为 PST 时,我使用了:

        TIMESTAMP_SUB(`timestamp`, INTERVAL 8 HOUR)
        

        【讨论】:

        • 仅将此作为最后的手段。 PST 仅存在于一年中的某个时期,因此如果您将其用于 PDT,例如,您将获得不正确的日期。此外,如果您有像“America/Los_Angeles”这样的时区值,那么这种方法根本无济于事。检查其他答案
        【解决方案7】:

        致那些在这里绊倒的人:

        如何将时间戳转换为另一个时区?

        鉴于 TIMESTAMP 值一旦构造为 stored as UTC,并且 TIMESTAMP 没有构造函数 (TIMESTAMP, STRING),您可以先将时间戳转换为另一个时区,方法是先将其转换为 DATETIME,然后再构造新时区中 DATETIME 的新 TIMESTAMP:

        SELECT TIMESTAMP(DATETIME(timestamp_field, '{timezone}'))
        

        例子:

        SELECT
            input_tz,
            input,
            'America/Montreal' AS output_tz,
            TIMESTAMP(DATETIME(input,'America/Montreal')) AS output
        FROM (
            SELECT 'US/Pacific' AS input_tz, TIMESTAMP(DATETIME(DATE(2021, 1, 1), TIME(16, 0, 0)), 'US/Pacific') AS input
            UNION ALL
            SELECT 'UTC' AS input_tz, TIMESTAMP(DATETIME(DATE(2021, 1, 1), TIME(16, 0, 0)), 'UTC') AS input
            UNION ALL
            SELECT 'Europe/Berlin' AS input_tz, TIMESTAMP(DATETIME(DATE(2021, 1, 1), TIME(16, 0, 0)), 'Europe/Berlin') AS input
        ) t
        

        结果:

        Row input_tz input output_tz output
        1 US/Pacific 2021-01-02 00:00:00 UTC America/Montreal 2021-01-01 19:00:00 UTC
        2 UTC 2021-01-01 16:00:00 UTC America/Montreal 2021-01-01 11:00:00 UTC
        3 Europe/Berlin 2021-01-01 15:00:00 UTC America/Montreal 2021-01-0110:00:00 UTC

        如何从 DATETIME 值中去除时区信息?

        BigQuery 中的 DATETIME 是简单的时区,因此它们不包含时区信息。话虽这么说,如果您拥有可以知道 DATETIME 的时区的业务知识,则可以通过将其转换为具有已知时区的 TIMESTAMP 来去除该时区偏移:

        SELECT TIMESTAMP(datetime_value, '{timezone}')
        

        鉴于 TIMESTAMP 以 UTC 存储值,如果这是您首选的存储方法,您可以重新转换为 DATETIME,但现在您会知道您的 DATETIME 是 UTC :)

        希望这会有所帮助! :)

        【讨论】:

        • 这是不正确的。您需要将时间戳上的括号移到末尾,否则它会增加 4 小时,而不是减去。 TIMESTAMP(DATETIME(CURRENT_TIMESTAMP(), '美国/蒙特利尔'))
        • @MikeDeluca 你说得对,马上改正!
        猜你喜欢
        • 1970-01-01
        • 2018-10-05
        • 1970-01-01
        • 1970-01-01
        • 2014-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多