在Spark(配置单元)中将字符串转换为时间戳,并且日期时间无效



我正试图将字符串更改为时间戳,但在我的区域中,3月的最后一个星期日(凌晨2:00至3:00(不存在并返回null。示例:

scala> spark.sql("select to_timestamp('20220327 021500', 'yyyyMMdd HHmmss') from *").show(1)
+--------------------------------------------------+
|to_timestamp('20220327 021500', 'yyyyMMdd HHmmss')|
+--------------------------------------------------+
|                                              null|
+--------------------------------------------------+
only showing top 1 row

scala> spark.sql("select to_timestamp('20220327 031500', 'yyyyMMdd HHmmss') from *").show(1)
+--------------------------------------------------+
|to_timestamp('20220327 031500', 'yyyyMMdd HHmmss')|
+--------------------------------------------------+
|                               2022-03-27 03:15:00|
+--------------------------------------------------+
only showing top 1 row

一个解决方案可能是在这些天的凌晨2:00到3:00之间增加一个小时,但我不知道如何实现这个解决方案

我无法更改数据源

我能做什么?

感谢

编辑

官方文件显示:

在Spark 3.1中,从_unix_time,unix_timestamp,到_unix_timestamp,如果指定的日期时间模式,to_timestamp和to_date将失败无效。在Spark 3.0或更早版本中,结果为NULL。(1(

让我们考虑下面的数据帧,其中包含一个名为ts的列。

val df = Seq("20220327 021500", "20220327 031500", "20220327 011500").toDF("ts")

在spark 3.1+中,我们可以使用to_timestamp,它会在您的情况下自动增加一个小时。

df.withColumn("time", to_timestamp($"ts", "yyyyMMdd HHmmss")).show
+---------------+-------------------+
|             ts|               time|
+---------------+-------------------+
|20220327 021500|2022-03-27 03:15:00|
|20220327 031500|2022-03-27 03:15:00|
|20220327 011500|2022-03-27 01:15:00|
+---------------+-------------------+

在spark 3.0和2.4.7中,我们得到了:

df.withColumn("time", to_timestamp($"ts", "yyyyMMdd HHmmss")).show
+---------------+-------------------+
|             ts|               time|
+---------------+-------------------+
|20220327 021500|               null|
|20220327 031500|2022-03-27 03:15:00|
|20220327 011500|2022-03-27 01:15:00|
+---------------+-------------------+

但奇怪的是,在spark 2.4.7中,to_utc_timestamp的工作方式与未来版本中的to_timestamp相同。唯一的问题是我们不能使用自定义日期格式。然而,如果我们自己转换日期,我们可以获得:

df.withColumn("ts", concat(
substring('ts, 0, 4), lit("-"),
substring('ts, 5, 2), lit("-"),
substring('ts, 7, 5), lit(":"),
substring('ts,12,2), lit(":"),
substring('ts,14,2))
)
.withColumn("time", to_utc_timestamp('ts, "UTC"))
.show
+-------------------+-------------------+
|                 ts|               time|
+-------------------+-------------------+
|2022-03-27 02:15:00|2022-03-27 03:15:00|
|2022-03-27 03:15:00|2022-03-27 03:15:00|
|2022-03-27 01:15:00|2022-03-27 01:15:00|
+-------------------+-------------------+

我发现了两种不同的解决方案,在这两种解决方案中,您都必须将字符串格式更改为yyyy-MM-dd HH:MM:ss:

select cast(CONCAT(SUBSTR('20220327021000',0,4),'-',
SUBSTR('20220327021000',5,2),'-',
SUBSTR('20220327021000',7,2),' ', 
SUBSTR('20220327021020',9,2),':',
SUBSTR('20220327021020',11,2),':',
SUBSTR('20220327021020',13,2)) as timestamp);
select 
cast(
regexp_replace("20220327031005", 
'^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$','$1-$2-$3 $4:$5:$6'
) as timestamp);

最新更新