如何在配置单元中将时间戳转换为 gmt 格式
How can i convert a timestamp to gmt format in hive
我的 table 中有一个时间戳列,我正在从时间戳列中导出一个名为 dt_skey
的列。为了清楚说明,我们假设时间戳列名称为 time_column
。这就是 time_column 看起来像 2017-02-05 03:33:50
的方式,dt_skey
列看起来像这样 20170205033350
只是删除了它们之间的符号。
我的问题是:time_column
在美国东部时间,我想在从中导出 dt_skey
时将其转换为 gmt 格式。我想这样做的原因是当我们通过 impala 查询时,时间戳将被转换为 gmt 格式,而 dt_skey
不会被转换,因为它是一个 int 数据类型。我正在通过配置单元进行摄取,当我们通过配置单元查询时,时间戳和 dt_skey
列将同步。出于报告目的和我们使用 impala 的用户,所以我想对 dt_skey
列进行更改,以便如果用户查看 impala 两列应该同步。
下面是我用来从时间戳列导出 dt_skey
列的 sql:
cast(substr(regexp_replace(cast(time_column as string), '-',''),1,8) as int)as dt_skey
以上查询会将此 2017-02-02 07:32:51
转换为此 20170202
。
请帮助我将 dt_skey
偏移为 GMT 格式。我也欢迎通过spark解决方案。
您只需在字段中添加 0,例如:
SELECT datetimefield+0;
SELECT CONVERT_TZ('2017-02-02 07:32:51','EST','GMT');
if CONVERT_TZ return NULL 你可以像这样安装时区表:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
样本
mysql> SELECT CONVERT_TZ('2017-02-02 07:32:51','EST','GMT');
+-----------------------------------------------+
| CONVERT_TZ('2017-02-02 07:32:51','EST','GMT') |
+-----------------------------------------------+
| 2017-02-02 12:32:51 |
+-----------------------------------------------+
1 row in set (0,00 sec)
mysql>
mysql> SELECT DATE(TIMESTAMP('2017-02-02 07:32:51'))+0;
+------------------------------------------+
| DATE(TIMESTAMP('2017-02-02 07:32:51'))+0 |
+------------------------------------------+
| 20170202 |
+------------------------------------------+
1 row in set (0,00 sec)
mysql> select id, mydate, date(mydate), date(mydate)+0 from df;
+----+---------------------+--------------+----------------+
| id | mydate | date(mydate) | date(mydate)+0 |
+----+---------------------+--------------+----------------+
| 1 | 2017-02-05 03:33:50 | 2017-02-05 | 20170205 |
+----+---------------------+--------------+----------------+
1 row in set (0,00 sec)
mysql>
mysql> SELECT TIMESTAMP('2017-02-05 03:33:50')+0;
+------------------------------------+
| TIMESTAMP('2017-02-05 03:33:50')+0 |
+------------------------------------+
| 20170205033350 |
+------------------------------------+
1 row in set (0,00 sec)
mysql>
mysql> select id, mydate, mydate+0 from df;
+----+---------------------+----------------+
| id | mydate | mydate+0 |
+----+---------------------+----------------+
| 1 | 2017-02-05 03:33:50 | 20170205033350 |
+----+---------------------+----------------+
1 row in set (0,00 sec)
mysql>
在 Spark 中:
rdd = spark.sparkContext.parallelize([('2017-02-05 03:33:50',)])
df = spark.createDataFrame(rdd, ['EST'])
df = df.withColumn('GMT', f.to_utc_timestamp(df['EST'], 'EST'))
res = df.withColumn('YouWanna', f.date_format(df['GMT'], 'yyyyMMddHHmmss'))
res.show(truncate=False)
+-------------------+---------------------+--------------+
|EST |GMT |YouWanna |
+-------------------+---------------------+--------------+
|2017-02-05 03:33:50|2017-02-05 08:33:50.0|20170205083350|
+-------------------+---------------------+--------------+
或在配置单元中:
select date_format(to_utc_timestamp('2017-02-05 03:33:50','EST'), 'yyyyMMddHHmmss') from dual
你是这个意思吗?
假设您想要一个 Hive 查询,这就是我将 Hive TimeStamp 列(使用当前系统时区)转换为 Impala TimeStamp(使用 UTC,这是与 GMT 相同,但不推荐使用 GMT。
CREATE TEMPORARY MACRO to_impala_timestamp(ts TIMESTAMP)
CAST(FROM_UNIXTIME(UNIX_TIMESTAMP(ts) +CAST(CAST(PRINTF('%tz', ts) AS FLOAT)*36.0 AS INT)) AS TIMESTAMP)
;
--## WARNING - do not use MACROs if your Hive version is below V1.3 (Apache, Horton)
--## or below V1.1-CDH5.7.3, V1.1-CDH5.8.3, V1.1-CDH5.9.0 (Cloudera)
--## cf. "HIVE-11432 Hive macro give same result for different arguments"
PRINTF('%tz', ts)
将提取时区,动态处理夏令时 -- 假设正在处理与您的 Hadoop 集群使用的 系统时区 相关的问题。如果它是不同的 TZ,那么您必须相应地调整宏。
您可以使用以下查询对其进行测试:
CREATE TABLE test_tz
STORED AS Parquet
AS
SELECT CAST(ts AS STRING) AS initial_ts_as_string
, printf('%1$tz %1$tZ', ts) AS tzone_offset_and_code
, ts AS ts_for_hive
, to_impala_timestamp(ts) AS ts_for_impala
FROM ...
我们的集群使用中欧时间,这就是结果在 Hive 中的显示方式...
+--------------------------+--------------------+-----------------------------+-------------------------+
| initial_ts_as_string | tz_offset_and_code | ts_for_hive | ts_for_impala |
+--------------------------+--------------------+-----------------------------+-------------------------+
| 2015-09-13 11:32:30.627 | +0200 CEST | 2015-09-13 11:32:30.627 | 2015-09-13 13:32:30.0 |
| 2015-12-10 12:27:01.282 | +0100 CET | 2015-12-10 12:27:01.282 | 2015-12-10 13:27:01.0 |
| 2016-05-17 15:49:06.386 | +0200 CEST | 2016-05-17 15:49:06.386 | 2016-05-17 17:49:06.0 |
...然后在 Impala...
+-------------------------+--------------------+-------------------------------+---------------------+
| initial_ts_as_string | tz_offset_and_code | ts_for_hive | ts_for_impala |
+-------------------------+--------------------+-------------------------------+---------------------+
| 2015-09-13 11:32:30.627 | +0200 CEST | 2015-09-13 09:32:30.627000000 | 2015-09-13 11:32:30 |
| 2015-12-10 12:27:01.282 | +0100 CET | 2015-12-10 11:27:01.282000000 | 2015-12-10 12:27:01 |
| 2016-05-17 15:49:06.386 | +0200 CEST | 2016-05-17 13:49:06.386000000 | 2016-05-17 15:49:06 |
请注意,运行 转换时会丢失毫秒数;它们可以通过额外的技巧来恢复,但通常这超出了重点。
旁注:要将 TimeStamp(或 Date 或 Float 或其他)格式化为字符串,旧的 Java PRINTF()
函数比使用默认格式加上 REGEXP_***()
函数更实用。 ..
感谢您提供的所有解决方案
这里的所有答案都有部分解决方案,使用答案资源我尝试了以下语法并且有效。
cast(substr(regexp_replace(to_utc_timestamp(timestamp_column, 'EST') ,'-',''),1,8) as int) as dt_skey
为了解释上面的语法,我的时间戳列是这样的 (yyyy-MM-dd HH:mm:ss) "2017-02-16 12:20:21"
在 运行 之后,上面的语法我的输出将类似于“20170216”,即 'yyyyMMdd' regexp_replace 将执行正则表达式以仅显示 yyyyMMdd。 to_utc_timestamp(timestamp_column, 'EST')
会将时间戳列转换为 UTC 时区。
我的 table 中有一个时间戳列,我正在从时间戳列中导出一个名为 dt_skey
的列。为了清楚说明,我们假设时间戳列名称为 time_column
。这就是 time_column 看起来像 2017-02-05 03:33:50
的方式,dt_skey
列看起来像这样 20170205033350
只是删除了它们之间的符号。
我的问题是:time_column
在美国东部时间,我想在从中导出 dt_skey
时将其转换为 gmt 格式。我想这样做的原因是当我们通过 impala 查询时,时间戳将被转换为 gmt 格式,而 dt_skey
不会被转换,因为它是一个 int 数据类型。我正在通过配置单元进行摄取,当我们通过配置单元查询时,时间戳和 dt_skey
列将同步。出于报告目的和我们使用 impala 的用户,所以我想对 dt_skey
列进行更改,以便如果用户查看 impala 两列应该同步。
下面是我用来从时间戳列导出 dt_skey
列的 sql:
cast(substr(regexp_replace(cast(time_column as string), '-',''),1,8) as int)as dt_skey
以上查询会将此 2017-02-02 07:32:51
转换为此 20170202
。
请帮助我将 dt_skey
偏移为 GMT 格式。我也欢迎通过spark解决方案。
您只需在字段中添加 0,例如:
SELECT datetimefield+0;
SELECT CONVERT_TZ('2017-02-02 07:32:51','EST','GMT');
if CONVERT_TZ return NULL 你可以像这样安装时区表:
mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root -p mysql
样本
mysql> SELECT CONVERT_TZ('2017-02-02 07:32:51','EST','GMT');
+-----------------------------------------------+
| CONVERT_TZ('2017-02-02 07:32:51','EST','GMT') |
+-----------------------------------------------+
| 2017-02-02 12:32:51 |
+-----------------------------------------------+
1 row in set (0,00 sec)
mysql>
mysql> SELECT DATE(TIMESTAMP('2017-02-02 07:32:51'))+0;
+------------------------------------------+
| DATE(TIMESTAMP('2017-02-02 07:32:51'))+0 |
+------------------------------------------+
| 20170202 |
+------------------------------------------+
1 row in set (0,00 sec)
mysql> select id, mydate, date(mydate), date(mydate)+0 from df;
+----+---------------------+--------------+----------------+
| id | mydate | date(mydate) | date(mydate)+0 |
+----+---------------------+--------------+----------------+
| 1 | 2017-02-05 03:33:50 | 2017-02-05 | 20170205 |
+----+---------------------+--------------+----------------+
1 row in set (0,00 sec)
mysql>
mysql> SELECT TIMESTAMP('2017-02-05 03:33:50')+0;
+------------------------------------+
| TIMESTAMP('2017-02-05 03:33:50')+0 |
+------------------------------------+
| 20170205033350 |
+------------------------------------+
1 row in set (0,00 sec)
mysql>
mysql> select id, mydate, mydate+0 from df;
+----+---------------------+----------------+
| id | mydate | mydate+0 |
+----+---------------------+----------------+
| 1 | 2017-02-05 03:33:50 | 20170205033350 |
+----+---------------------+----------------+
1 row in set (0,00 sec)
mysql>
在 Spark 中:
rdd = spark.sparkContext.parallelize([('2017-02-05 03:33:50',)])
df = spark.createDataFrame(rdd, ['EST'])
df = df.withColumn('GMT', f.to_utc_timestamp(df['EST'], 'EST'))
res = df.withColumn('YouWanna', f.date_format(df['GMT'], 'yyyyMMddHHmmss'))
res.show(truncate=False)
+-------------------+---------------------+--------------+
|EST |GMT |YouWanna |
+-------------------+---------------------+--------------+
|2017-02-05 03:33:50|2017-02-05 08:33:50.0|20170205083350|
+-------------------+---------------------+--------------+
或在配置单元中:
select date_format(to_utc_timestamp('2017-02-05 03:33:50','EST'), 'yyyyMMddHHmmss') from dual
你是这个意思吗?
假设您想要一个 Hive 查询,这就是我将 Hive TimeStamp 列(使用当前系统时区)转换为 Impala TimeStamp(使用 UTC,这是与 GMT 相同,但不推荐使用 GMT。
CREATE TEMPORARY MACRO to_impala_timestamp(ts TIMESTAMP)
CAST(FROM_UNIXTIME(UNIX_TIMESTAMP(ts) +CAST(CAST(PRINTF('%tz', ts) AS FLOAT)*36.0 AS INT)) AS TIMESTAMP)
;
--## WARNING - do not use MACROs if your Hive version is below V1.3 (Apache, Horton)
--## or below V1.1-CDH5.7.3, V1.1-CDH5.8.3, V1.1-CDH5.9.0 (Cloudera)
--## cf. "HIVE-11432 Hive macro give same result for different arguments"
PRINTF('%tz', ts)
将提取时区,动态处理夏令时 -- 假设正在处理与您的 Hadoop 集群使用的 系统时区 相关的问题。如果它是不同的 TZ,那么您必须相应地调整宏。
您可以使用以下查询对其进行测试:
CREATE TABLE test_tz
STORED AS Parquet
AS
SELECT CAST(ts AS STRING) AS initial_ts_as_string
, printf('%1$tz %1$tZ', ts) AS tzone_offset_and_code
, ts AS ts_for_hive
, to_impala_timestamp(ts) AS ts_for_impala
FROM ...
我们的集群使用中欧时间,这就是结果在 Hive 中的显示方式...
+--------------------------+--------------------+-----------------------------+-------------------------+
| initial_ts_as_string | tz_offset_and_code | ts_for_hive | ts_for_impala |
+--------------------------+--------------------+-----------------------------+-------------------------+
| 2015-09-13 11:32:30.627 | +0200 CEST | 2015-09-13 11:32:30.627 | 2015-09-13 13:32:30.0 |
| 2015-12-10 12:27:01.282 | +0100 CET | 2015-12-10 12:27:01.282 | 2015-12-10 13:27:01.0 |
| 2016-05-17 15:49:06.386 | +0200 CEST | 2016-05-17 15:49:06.386 | 2016-05-17 17:49:06.0 |
...然后在 Impala...
+-------------------------+--------------------+-------------------------------+---------------------+
| initial_ts_as_string | tz_offset_and_code | ts_for_hive | ts_for_impala |
+-------------------------+--------------------+-------------------------------+---------------------+
| 2015-09-13 11:32:30.627 | +0200 CEST | 2015-09-13 09:32:30.627000000 | 2015-09-13 11:32:30 |
| 2015-12-10 12:27:01.282 | +0100 CET | 2015-12-10 11:27:01.282000000 | 2015-12-10 12:27:01 |
| 2016-05-17 15:49:06.386 | +0200 CEST | 2016-05-17 13:49:06.386000000 | 2016-05-17 15:49:06 |
请注意,运行 转换时会丢失毫秒数;它们可以通过额外的技巧来恢复,但通常这超出了重点。
旁注:要将 TimeStamp(或 Date 或 Float 或其他)格式化为字符串,旧的 Java
PRINTF()
函数比使用默认格式加上 REGEXP_***()
函数更实用。 ..
感谢您提供的所有解决方案
这里的所有答案都有部分解决方案,使用答案资源我尝试了以下语法并且有效。
cast(substr(regexp_replace(to_utc_timestamp(timestamp_column, 'EST') ,'-',''),1,8) as int) as dt_skey
为了解释上面的语法,我的时间戳列是这样的 (yyyy-MM-dd HH:mm:ss) "2017-02-16 12:20:21"
在 运行 之后,上面的语法我的输出将类似于“20170216”,即 'yyyyMMdd' regexp_replace 将执行正则表达式以仅显示 yyyyMMdd。 to_utc_timestamp(timestamp_column, 'EST')
会将时间戳列转换为 UTC 时区。