关于BigQuery TIMESTAMP_TRUNC函数时区参数行为的技术咨询
先看你给出的SQL示例及结果:
SELECT TIMESTAMP_TRUNC(TIMESTAMP(FORMAT_TIMESTAMP("%F %T", '2022-12-17 23:50:50.000000 UTC')), DAY, "UTC-1") --2022-12-17 01:00:00 UTC SELECT TIMESTAMP_TRUNC(TIMESTAMP(FORMAT_TIMESTAMP("%F %T", '2022-12-17 23:50:50.000000 UTC')), DAY, "UTC") --2022-12-17 00:00:00 UTC SELECT TIMESTAMP_TRUNC(TIMESTAMP(FORMAT_TIMESTAMP("%F %T", '2022-12-17 23:50:50.000000 UTC')), DAY, "UTC+1") --2022-12-17 23:00:00 UTC SELECT TIMESTAMP_TRUNC(TIMESTAMP(FORMAT_TIMESTAMP("%F %T", '2022-12-17 23:50:50.000000 UTC')), DAY, "UTC+2") --2022-12-17 22:00:00 UTC SELECT TIMESTAMP_TRUNC(TIMESTAMP(FORMAT_TIMESTAMP("%F %T", '2022-12-17 23:50:50.000000 UTC+2')), DAY, "UTC+2") --2022-12-16 22:00:00 UTC
疑问1:既然时间戳表达式本身可指定时区,TIMESTAMP_TRUNC的时区参数作用是什么?
BigQuery里的TIMESTAMP类型本质是UTC时间戳,不带时区属性。你输入的带时区的字符串(比如'2022-12-17 23:50:50.000000 UTC')只是用来转换为对应的UTC时间戳的——BigQuery会把这个带时区的时间转成UTC标准时间存储。
而TIMESTAMP_TRUNC的时区参数,是用来定义“截断边界”的时区规则。比如当你截断到DAY时,这个参数决定了“一天的起始点”是哪个时区的0点,而不是默认的UTC0点。简单说:它是让你按照指定时区的时间周期(日/小时等)来截断,而不是UTC的周期。
疑问2:详细解释三个时区的含义
时间戳表达式中的时区:
这个时区是用来将输入的字符串转换为UTC时间戳的“转换依据”。比如'2022-12-17 23:50:50.000000 UTC+2'表示这个时间是UTC+2时区的12月17日23:50:50,BigQuery会把它转换成对应的UTC时间(即2022-12-17 21:50:50 UTC),最终生成的TIMESTAMP值就是这个UTC时间,不再携带时区信息。TIMESTAMP_TRUNC第三个参数的时区:
这个时区是用来确定截断的“时间周期起点”。以截断到DAY为例:- 当指定
UTC-1时,“一天的起点”是UTC-1时区的00:00:00,对应的UTC时间是01:00:00; - 当指定
UTC+1时,“一天的起点”是UTC+1时区的00:00:00,对应的UTC时间是前一天的23:00:00。
函数会先把原UTC时间戳转换到这个指定时区,找到该时区下对应周期的起始点,再把这个起始点转换回UTC时间作为结果。
- 当指定
结果中的UTC:
BigQuery的TIMESTAMP类型输出时,统一以UTC时区展示——因为它本质就是UTC时间戳,所有TIMESTAMP的输出都会带上UTC标识,这是类型本身的特性,和你指定的截断时区无关。
结合示例拆解最后一条SQL
最后一条:SELECT TIMESTAMP_TRUNC(TIMESTAMP(FORMAT_TIMESTAMP("%F %T", '2022-12-17 23:50:50.000000 UTC+2')), DAY, "UTC+2")
- 第一步:把
'2022-12-17 23:50:50.000000 UTC+2'转成UTC时间戳,结果是2022-12-17 21:50:50 UTC; - 第二步:按
UTC+2时区截断到DAY——这个UTC时间在UTC+2时区是2022-12-17 23:50:50,属于UTC+2时区的12月17日,该时区的当天起点是2022-12-17 00:00:00 UTC+2; - 第三步:把这个起点转成UTC时间,就是
2022-12-16 22:00:00 UTC,也就是最终的输出结果。
内容的提问来源于stack exchange,提问作者fancyeffective

