当尝试使用强制转换(TimestampType)将带有时区信息的ISO8601字符串转换为TimestampType时,仅接受时区格式为+01:00的字符串。如果以ISO8601合法方式+0100(不含冒号)定义了时区,则解析将失败并返回null。我需要在保留ms部分的同时将字符串转换为TimestampType。
2019-02-05T14:06:31.556+0100 Returns null
2019-02-05T14:06:31.556+01:00 Returns a correctly parsed TimestampType
我尝试使用to_timestamp()和unix_timestamp()。cast(TimestampType)函数。不幸的是,它们截断了我需要保留的时间戳的ms部分。另外,您需要将它们应用于新列,并且不能就地替换复杂类型中的属性(如果我在from_json函数的模式中将ApiReceived属性设置为TimestampType,则可以这样做)。 / p>
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))
上述DataFrame的输出类型
df:org.apache.spark.sql.DataFrame
Time:string
NewTime:timestamp
NewTime2:timestamp
NewTime3:timestamp
并输出值
Time 2019-02-05T14:06:31.556+0100
NewTime 2019-02-05 13:06:31
NewTime2 2019-02-05 13:06:31
NewTime3 null
是否有一种方法可以使Spark在不依靠UDF:s的情况下处理转换?
更新
经过更彻底的调查,我发现Sparks日期时间解析有些不一致。 :)
val df = Seq(
//Extended format
("2019-02-05T14:06:31.556+01:00"),
("2019-02-05T14:06:31.556+01"),
("2019-02-05T14:06:31.556"),
//Basic Format
("20190205T140631556+0100"),
("20190205T140631556+01"),
("20190205T140631556"),
//Mixed extended with basic
("2019-02-05T14:06:31.556+0100"),
("20190205T140631556+01:00")
).toDF
val formatStrings = Seq(
("yyyy-MM-dd'T'HH:mm:ss.SSSZ"),
("yyyy-MM-dd'T'HH:mm:ss.SSSX"),
("yyyyMMdd'T'HHmmssSSSZ"),
("yyyyMMdd'T'HHmmssSSSX")
)
val format = formatStrings(0)
val df2 = df
.select($"value".as("Time"))
.withColumn("NewTime3", $"Time".cast(TimestampType))
.withColumn("NewTime", to_timestamp($"Time", format))
.withColumn("NewTime2", unix_timestamp($"Time", format).cast(TimestampType))
.withColumn("NewTime4", date_format($"Time", format))
display(df2)
我运行这些数据帧并比较输出,这有点令人沮丧。最宽松的formatString是第二个SSSX
处理此问题的唯一合理方法是确保所有ISO8601字符串均符合您计划使用的功能所理解的标准。
仍然,还没有找到在两种格式中都保留毫秒部分的方法。
2019-02-05T14:06:31.556+01:00 and
2019-02-05T14:06:31.556+0100
更新2
显然,不符合ISO8601标准的混合基本形式和扩展形式。字符串“ 2019-02-05T14:06:31.556 + 0100”不是标准格式。不过,根据RFC822,这似乎是正确的。
如果我正确理解JIRA票证,则标准解析(即字符串列上的cast())只会处理格式正确的ISO8601字符串,而不会处理RFC822或其他边缘情况(即混合扩展格式和基本格式)。如果您使用的是小写字母,则必须提供格式字符串并使用其他解析方法。
我没有访问ISO8601:2004标准的权限,所以我无法检查,但是JIRA中的注释是否正确,互联网需要更新。许多网页将RFC822和ISO8601合并,并将“ 2019-02-05T14:06:31.556 + 0100”列为合法的ISO8601字符串。