Spark 2.4.0解析ISO8601字符串至TimestampType的兼容问题
Spark 2.4.0 带时区时间字符串解析的坑及测试总结
我最近在Spark 2.4.0里处理带时区的时间字符串转TimestampType时踩了不少坑,特意做了一系列测试,整理下实际情况:
核心问题
转换带时区的时间字符串时,不同格式的表现差异很大:
- 仅
+01:00这种带冒号的时区格式,能被cast(TimestampType)正确解析,且完整保留毫秒; +0100这种无冒号的时区格式,用cast(TimestampType)会直接返回null;- 尝试
to_timestamp()或unix_timestamp().cast(TimestampType),虽然能解析两种时区格式,但会截断毫秒部分,而且这两种方法没法在嵌套的复杂数据类型里就地替换属性,处理起来很繁琐。
测试代码及结果
我写了这段代码验证不同方法的表现:
df .select($"body".cast(StringType)) .select(from_json($"body", schema).as("Payload")) .select($"Payload.Metadata.ApiReceived".as("Time")) .withColumn("NewTime", to_timestamp($"Time", "yyyy-MM-dd'T'HH:mm:ss.SSSZ")) .withColumn("NewTime2", unix_timestamp($"Time", "yyyy-MM-dd'T'HH:mm:ss.SSSZ").cast(TimestampType)) .withColumn("NewTime3", $"Time".cast(TimestampType))
当输入时间字符串为2019-02-05T14:06:31.556+0100时,输出结果如下:
NewTime和NewTime2:能解析出时间,但毫秒部分被截断;NewTime3:直接返回null。
深入分析
我测试了多种日期格式模板后发现,SSSX格式的兼容性相对较好,但依然没找到不需要自定义UDF就能同时支持+01:00和+0100两种时区格式,且完整保留毫秒的方法。
后来查Spark内部工单才明白:2019-02-05T14:06:31.556+0100这种格式是混合了ISO8601的时间部分和RFC822的时区部分,并不符合严格的ISO8601标准,而Spark的默认解析逻辑只支持合规的ISO8601字符串,所以才会出现这种解析不一致的情况。
内容的提问来源于stack exchange,提问作者Molotch
相关产品推荐
相关产品推荐

