使用udf在PySpark数据框中将epoch转换为datetime

时间:2018-04-23 00:14:31

标签: python apache-spark pyspark apache-spark-sql

我有一个带有此架构的PySpark数据框:

root
 |-- epoch: double (nullable = true)
 |-- var1: double (nullable = true)
 |-- var2: double (nullable = true)

epoch以秒为单位,应转换为日期时间。为此,我按如下方式定义用户定义的函数(udf):

from pyspark.sql.functions import udf    
import time
def epoch_to_datetime(x):
    return time.localtime(x)
    # return time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(x))
    # return x * 0 + 1

epoch_to_datetime_udf = udf(epoch_to_datetime, DoubleType())
df.withColumn("datetime", epoch_to_datetime(df2.epoch)).show()

我收到此错误:

---> 21     return time.localtime(x)
    22     # return x * 0 + 1
    23 
    TypeError: a float is required

如果我只是在函数中返回x + 1,它就可以了。在float(x)中尝试float(str(x))numpy.float(x)time.localtime(x)无效,我仍然会收到错误消息。在udf之外,time.localtime(1.514687216E9)或其他数字可以正常工作。使用datetime包将epoch转换为datetim会导致类似的错误。

timedatetime软件包似乎不喜欢从PySpark中使用DoubleType。我有什么想法可以解决这个问题?感谢。

2 个答案:

答案 0 :(得分:6)

您不需要udf功能

您只需将双历元列投射到timestampType() ,然后使用data_format功能,如下所示

from pyspark.sql import functions as f
from pyspark.sql import types as t
df.withColumn('epoch', f.date_format(df.epoch.cast(dataType=t.TimestampType()), "yyyy-MM-dd"))

这会给你一个字符串日期

root
 |-- epoch: string (nullable = true)
 |-- var1: double (nullable = true)
 |-- var2: double (nullable = true)

您可以使用to_date功能,如下所示

from pyspark.sql import functions as f
from pyspark.sql import types as t
df.withColumn('epoch', f.to_date(df.epoch.cast(dataType=t.TimestampType())))

会将date作为datatypeepoch

root
 |-- epoch: date (nullable = true)
 |-- var1: double (nullable = true)
 |-- var2: double (nullable = true)

我希望答案很有帮助

答案 1 :(得分:2)

Ramesh Maharjan's Answer不支持在时间戳中获取毫秒或微秒。添加了毫秒支持的更新答案如下:

实施Dao Thi's answer

中建议的方法
import pyspark.sql.functions as F
df = spark.createDataFrame([('22-Jul-2018 04:21:18.792 UTC', ),('23-Jul-2018 04:21:25.888 UTC',)], ['TIME'])
df.show(2,False)
df.printSchema()

输出:

+----------------------------+
|TIME                        |
+----------------------------+
|22-Jul-2018 04:21:18.792 UTC|
|23-Jul-2018 04:21:25.888 UTC|
+----------------------------+
root
|-- TIME: string (nullable = true)

字符串时间格式(包括毫秒)转换为 unix_timestamp(double)。使用子字符串方法(start_position = -7,length_of_substring = 3)从字符串中提取毫秒,并分别向unix_timestamp添加毫秒。 (投射到子字符串以使其浮动以进行添加)

df1 = df.withColumn("unix_timestamp",F.unix_timestamp(df.TIME,'dd-MMM-yyyy HH:mm:ss.SSS z') + F.substring(df.TIME,-7,3).cast('float')/1000)

在Spark中将 unix_timestamp(double)转换为 timestamp数据类型

df2 = df1.withColumn("TimestampType",F.to_timestamp(df1["unix_timestamp"]))
df2.show(n=2,truncate=False)

这将为您提供以下输出

+----------------------------+----------------+-----------------------+
|TIME                        |unix_timestamp  |TimestampType          |
+----------------------------+----------------+-----------------------+
|22-Jul-2018 04:21:18.792 UTC|1.532233278792E9|2018-07-22 04:21:18.792|
|23-Jul-2018 04:21:25.888 UTC|1.532319685888E9|2018-07-23 04:21:25.888|
+----------------------------+----------------+-----------------------+

检查架构:

df2.printSchema()


root
 |-- TIME: string (nullable = true)
 |-- unix_timestamp: double (nullable = true)
 |-- TimestampType: timestamp (nullable = true)