小编Mol*_*tch的帖子

Spark 2.4.0-无法将ISO8601字符串解析为保留ms的TimestampType

当尝试使用cast(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
Run Code Online (Sandbox Code Playgroud)

我试图使用to_timestamp()和unix_timestamp()。cast(TimestampType)函数。不幸的是,它们截断了我需要保留的时间戳的ms部分。另外,您需要将它们应用于新列,并且不能就地替换复杂类型中的属性(如果我在from_json函数的模式中将ApiReceived属性设为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))
Run Code Online (Sandbox Code Playgroud)

上面的DataFrame的输出类型

df:org.apache.spark.sql.DataFrame
  Time:string
  NewTime:timestamp
  NewTime2:timestamp
  NewTime3:timestamp
Run Code Online (Sandbox Code Playgroud)

并输出值

Time        2019-02-05T14:06:31.556+0100
NewTime     2019-02-05 13:06:31
NewTime2    2019-02-05 13:06:31
NewTime3    null
Run Code Online (Sandbox Code Playgroud)

有没有一种方法可以使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 …
Run Code Online (Sandbox Code Playgroud)

apache-spark databricks azure-databricks

6
推荐指数
0
解决办法
526
查看次数