如何将纪元转换为日期时间红移?

Posted

技术标签:

【中文标题】如何将纪元转换为日期时间红移?【英文标题】:How to convert epoch to datetime redshift? 【发布时间】:2016-10-02 08:59:23 【问题描述】:

我在 dbeaver 工作。我有一张桌子 x。

TABLE x 有一列“时间戳

1464800406459 
1464800400452 
1464800414056 
1464800422854 
1464800411797

我想要的结果:

Wed, 01 Jun 2016 17:00:06.459 GMT
Wed, 01 Jun 2016 17:00:00.452 GMT
Wed, 01 Jun 2016 17:00:14.056 GMT
Wed, 01 Jun 2016 17:00:22.854 GMT 
Wed, 01 Jun 2016 17:00:11.797 GMT 

我试过红移查询

SELECT FROM_UNIXTIME(x.timestamp) as x_date_time 
FROM x

但没用。

发生错误:

无效操作:函数from_unixtime(字符变化)不存在

我也试过了

SELECT DATE_FORMAT(x.timestamp, '%d/%m/%Y') as x_date 
FROM x

发生错误:

无效操作:函数 date_format(character varying, "unknown") 不存在

语法有什么问题吗?还是有其他方法可以转换为人类可读的日期和时间?

提前致谢

【问题讨论】:

【参考方案1】:

Redshift 没有from_unixtime() 功能。您需要使用以下 SQL 查询来获取时间戳。它只是将秒数添加到纪元并作为时间戳返回。

select timestamp 'epoch' + your_timestamp_column * interval '1 second' AS your_column_alias
from your_table

【讨论】:

我才意识到 your_timestamp_column 是字符串,它有 13 位数字。所以我将您的语法添加为:select timestamp 'epoch' + CAST(your_timestamp_column AS BIGINT)/1000 * interval '1 second' AS your_column_alias from your_table。谢谢。 如何添加时区?因为时间后面没有格林威治标准时间。 我不确定我们是否可以在时间之后获得 GMT,因为这只是时间戳字段。您可以尝试使用时区而不是时间戳来选择时间戳。 @KhusnaNadia 的答案是有效的,因为 OP 字符串的格式是 13 位数字。理想情况下,您希望您的字符串为 10 位数字,因此相应地将其答案中的 /1000 更改为字符串格式中 >10 的位数。 (例如:如果您的字符串是 10 位,则不需要 /1000,如果您的字符串是 15 位,则需要 /100000 等) @ZephDavies 将您的 Unix 时间戳列视为浮点数:select timestamp 'epoch' + your_timestamp_column::float * interval '1 second' …【参考方案2】:

UDF 会很慢。检查了 3 个解决方案和 1k 行的执行时间。

最慢的 -

-- using UDF from one of the answers
SELECT from_unixtime(column_with_time_in_ms/ 1000)
FROM table_name LIMIT 1000;

执行时间00:00:02.348062s

第二好 -

SELECT date_add('ms',column_with_time_in_ms,'1970-01-01')
FROM table_name LIMIT 1000;

执行时间00:00:01.112831s

而且最快 -

SELECT TIMESTAMP 'epoch' + column_with_time_in_ms/1000 *INTERVAL '1 second'
FROM table_name LIMIT 1000;

执行时间00:00:00.095102s


stl_query计算的执行时间-

SELECT *
       ,endtime - starttime
FROM stl_query
WHERE querytxt ilike('%table_name%limit%')
ORDER BY starttime DESC;

【讨论】:

Redshift 没有 from_unixtime 或 date_add。此处唯一真正适用于 Redshift 的建议是上述答案之一的副本(最快的答案)。此外,如果时间以毫秒为单位,则无需除以 1000。不过,感谢您分享执行时间的方法。 @szeitlin - 您必须从@aloschilov 的答案中定义from_unixtime() UDF,如我的代码sn-p 中的SQL 注释中所述。由于我使用的专栏以毫秒为单位存储纪元,因此我确实需要除以 1000 才能以秒为单位获得纪元。如果您的列以秒为单位存储它,那么您无需划分。 拯救我的一天!谢谢!【参考方案3】:

最简单的解决方案是创建from_unixtime()函数:

CREATE OR REPLACE FUNCTION from_unixtime(epoch BIGINT)
  RETURNS TIMESTAMP  AS
'import datetime

return datetime.datetime.fromtimestamp(epoch)
'
LANGUAGE plpythonu IMMUTABLE;

详情请见Redshift documentation on UDF

【讨论】:

这太棒了。 不错,但用户定义的函数不能在物化视图中使用 @Che 具体化视图为introduced on Nov 29, 2019。在回答的那一刻,那些并不存在。我敢打赌,将来可能会添加这些内容。【参考方案4】:

为了快速参考,这里是上面在 Python 中显示的 from_unixtime 函数的 SQL UDF 实现。我没有测试过性能,但我想它会类似于普通的 SQL 版本。不过写起来要容易得多。

注意:这会计算从纪元开始的秒数

CREATE FUNCTION from_unixtime (BIGINT)
  RETURNS TIMESTAMP WITHOUT TIME ZONE
IMMUTABLE
as $$
  SELECT TIMESTAMP 'epoch' + $1 / 1000 * interval '1 second'
$$ LANGUAGE sql;

【讨论】:

【参考方案5】:

我是这样用的

CAST(DATEADD(S, CONVERT(int,LEFT(column_name, 10)), '1970-01-01')as timestamp) as column_name

SELECT 
    ,task_id 
    ,CAST(DATEADD(S, CONVERT(int,LEFT(SLA, 10)), '1970-01-01')as timestamp) as SLA
FROM my_schema.my_task_table ;

【讨论】:

以上是关于如何将纪元转换为日期时间红移?的主要内容,如果未能解决你的问题,请参考以下文章

如何将日期时间(在特定时区)转换为纪元秒

如何将自纪元以来的 Unix 时间/时间转换为标准日期和时间?

如何使用 Perl 将纪元时间转换为 UTC 时间?

如何在python中将日期转换为纪元时间[重复]

PostgreSQL:如何从 Unix 纪元转换为日期?

如何将(round)纪元时间转换为最接近的小时和日期wrt IST(在Java中)