如何在PySpark中使用to_date转换含荷兰语月份缩写的多格式日期字符串
荷兰语格式日期字符串转DateType最优方案
现有实现可优化点
现有自定义UDF的实现可以满足需求,但存在两个可优化点:
- UDF会带来额外的序列化/反序列化开销,性能弱于Spark原生函数
- 原有代码存在语法错误:
to_date的格式参数错误传入了UDF内,实际应该作为to_date的第二个参数
原生函数实现方案(推荐)
Spark 3.0及以上版本的to_date/to_timestamp原生支持指定locale,无需自定义映射字典,同时自带灵活格式匹配能力:
d格式符自动兼容1位或2位天数MMM格式符可匹配本地化月份缩写,搭配locale参数即可解析荷兰语月份yy格式符自动兼容2位/4位年份,无需手动补前缀
实现代码
from pyspark.sql import functions as F # 测试数据 df = spark.createDataFrame([ ["2-feb-1966"], ["05-mei-1974"], ["3-mrt-83"], ["05-mrt-1983"], ["12-jun-75"] ]).toDF("DateOfBirth") # 原生解析逻辑 df = df.withColumn( "DateOfBirth_new", F.to_date( F.col("DateOfBirth"), format="d-MMM-yy", options={"locale": "nl-NL"} ) )
2位年份世纪补全规则调整
如果需要固定将2位年份补前缀19,可额外加一层判断逻辑:
df = df.withColumn( "DateOfBirth_new", F.when( F.year(F.col("DateOfBirth_new")) < 1900, F.to_date(F.concat(F.lit("19"), F.date_format(F.col("DateOfBirth_new"), "yy-MM-dd")), "yyyy-MM-dd") ).otherwise(F.col("DateOfBirth_new")) )
如果业务中存在2000年后出生的用户,可以根据业务范围调整补全规则,比如将小于30的2位年份补20,大于等于30的补19即可。
低版本Spark兼容方案
如果使用的Spark版本低于3.0,不支持locale参数,可以继续使用原有UDF,修正语法错误后即可正常运行:
import pyspark.sql.types as T @F.udf(T.StringType()) def convert_date(s): month_dict = {"jan":"01", "feb":"02", "mrt":"03", "apr":"04", "mei":"05", "jun":"06", "jul":"07", "aug":"08", "sep":"09", "okt":"10", "nov":"11", "dec":"12" } day, month, year = s.split("-") if len(day) == 1: day = '0' + day if len(year) < 4: year = '19' + year return day + "-" + month_dict[month] + "-" + year df = df.withColumn('DateOfBirth_new', F.to_date(convert_date(F.col("DateOfBirth")), "dd-MM-yyyy"))
内容的提问来源于stack exchange,提问作者John Doe
相关产品推荐
相关产品推荐

