将包含多个字符串日期格式的列转换为Spark中的DateTime

Ste*_*han 4 python apache-spark apache-spark-sql pyspark

我的Spark DataDrame中有一个包含多种字符串格式的日期列.我想将这些转换为DateTime.

我的专栏中的两种格式是:

  • mm/dd/yyyy; 和
  • yyyy-mm-dd

到目前为止,我的解决方案是使用UDF更改第一个日期格式以匹配第二个日期格式,如下所示:

import re

def parseDate(dateString):
    if re.match('\d{1,2}\/\d{1,2}\/\d{4}', dateString) is not None:
        return datetime.strptime(dateString, '%M/%d/%Y').strftime('%Y-%M-%d')
    else:
        return dateString

# Create Spark UDF based on above function
dateUdf = udf(parseDate)

df = (df.select(to_date(dateUdf(raw_transactions_df['trans_dt']))))
Run Code Online (Sandbox Code Playgroud)

这可行,但不是所有容错的.我特别关注:

  • 我还没有遇到的日期格式.
  • 区分mm/dd/yyyydd/mm/yyyy(我正在使用的正则表达式目前没有这样做).

有一个更好的方法吗?

use*_*411 7

就个人而言,我建议直接使用SQL函数,而不需要昂贵且低效的重新格式化:

from pyspark.sql.functions import coalesce, to_date

def to_date_(col, formats=("MM/dd/yyyy", "yyyy-MM-dd")):
    # Spark 2.2 or later syntax, for < 2.2 use unix_timestamp and cast
    return coalesce(*[to_date(col, f) for f in formats])
Run Code Online (Sandbox Code Playgroud)

这将选择第一种格式,它可以成功解析输入字符串.

用法:

df = spark.createDataFrame([(1, "01/22/2010"), (2, "2018-12-01")], ("id", "dt"))
df.withColumn("pdt", to_date_("dt")).show()
Run Code Online (Sandbox Code Playgroud)
+---+----------+----------+
| id|        dt|       pdt|
+---+----------+----------+
|  1|01/22/2010|2010-01-22|
|  2|2018-12-01|2018-12-01|
+---+----------+----------+
Run Code Online (Sandbox Code Playgroud)

它会更快udf,添加新格式只需调整formats参数.

但是它不会帮助您解决格式歧义问题.一般情况下,如果没有人工干预和与外部数据交叉引用,可能无法做到这一点.

在Scala中当然可以做同样的事情:

import org.apache.spark.sql.Column
import org.apache.spark.sql.functions.{coalesce, to_date}

def to_date_(col: Column, 
             formats: Seq[String] = Seq("MM/dd/yyyy", "yyyy-MM-dd")) = {
  coalesce(formats.map(f => to_date(col, f)): _*)
}
Run Code Online (Sandbox Code Playgroud)