我有一个来自源的日期字符串,格式为"2019 年 5 月 24 日星期五 00:00:00",我会将其转换为日期并存储在我的数据帧中为"2019-05-24",使用类似于我的示例的代码在 Spark 2.0 下对我有用
from pyspark.sql.functions import to_date, unix_timestamp, from_unixtime
df = spark.createDataFrame([("Fri May 24 00:00:00 BST 2019",)], ['date_str'])
df2 = df.select('date_str', to_date(from_unixtime(unix_timestamp('date_str', 'EEE MMM dd HH:mm:ss zzz yyyy'))).alias('date'))
df2.show(1, False)
在我的沙盒环境中,我已经更新到 spark 3.0,现在上面的代码出现以下错误,是否有一种新的方法 在 3.0 中执行此操作以将我的字符串转换为日期
:org.apache.spark.SparkUpgradeException: 你可能会得到不同的 由于 Spark 3.0 升级而导致的结果:无法识别"EEE MMM dd HH:mm:ss zzz yyyy' pattern in the DateTimeFormatter.
- 您可以将 spark.sql.legacy.timeParserPolicy 设置为 LEGACY 以恢复 Spark 3.0 之前的行为。
- 您可以使用以下指南形成有效的日期时间模式 https://spark.apache.org/docs/latest/sql-ref-datetime-pattern.html
如果要在较新版本的 spark(>3( 中使用旧格式,则需要设置spark.conf.set("spark.sql.legacy.timeParserPolicy","LEGACY")
或spark.sql("set spark.sql.legacy.timeParserPolicy=LEGACY")
,这将解决问题。
感谢您的回复,很好的建议,目前我将使用 LEGACY 设置。 我对 Spark 3.0 有一个解决方法,方法是将 EEE 元素串起来,但我注意到 BST 时区如何错误地转换偏移 10 小时的错误,而在 LEGACY 下,它正确保持与我目前在 BST 区域相同。 我可以对此做点什么,但会等到秋天的时钟改变后再确认。
spark.sql("set spark.sql.legacy.timeParserPolicy=LEGACY")
df = spark.createDataFrame([('Fri May 24 00:00:00 BST 2019',)], ['mydate'])
df = df.select('mydate',
to_timestamp(df.mydate.substr(5, 28), 'MMM dd HH:mm:ss zzz yyyy').alias('datetime'),
to_timestamp(df.mydate, 'EEE MMM dd HH:mm:ss zzz yyyy').alias('LEGACYdatetime')
).show(1, False)
df = spark.createDataFrame([('Fri May 24 00:00:00 GMT 2019',)], ['mydate'])
df = df.select('mydate',
to_timestamp(df.mydate.substr(5, 28), 'MMM dd HH:mm:ss zzz yyyy').alias('datetime'),
to_timestamp(df.mydate, 'EEE MMM dd HH:mm:ss zzz yyyy').alias('LEGACYdatetime')
).show(1, False)
spark.sql("set spark.sql.legacy.timeParserPolicy=CORRECTED")
df = spark.createDataFrame([('Fri May 24 00:00:00 BST 2019',)], ['mydate'])
df = df.select('mydate',
to_timestamp(df.mydate.substr(5, 28), 'MMM dd HH:mm:ss zzz yyyy').alias('datetime')
).show(1, False)
df = spark.createDataFrame([('Fri May 24 00:00:00 GMT 2019',)], ['mydate'])
df = df.select('mydate',
to_timestamp(df.mydate.substr(5, 28), 'MMM dd HH:mm:ss zzz yyyy').alias('datetime')
).show(1, False)
+----------------------------+-------------------+-------------------+
|mydate |datetime |LEGACYdatetime |
+----------------------------+-------------------+-------------------+
|Fri May 24 00:00:00 BST 2019|2019-05-24 00:00:00|2019-05-24 00:00:00|
+----------------------------+-------------------+-------------------+
+----------------------------+-------------------+-------------------+
|mydate |datetime |LEGACYdatetime |
+----------------------------+-------------------+-------------------+
|Fri May 24 00:00:00 GMT 2019|2019-05-24 01:00:00|2019-05-24 01:00:00|
+----------------------------+-------------------+-------------------+
+----------------------------+-------------------+
|mydate |datetime |
+----------------------------+-------------------+
|Fri May 24 00:00:00 BST 2019|2019-05-23 14:00:00|
+----------------------------+-------------------+
+----------------------------+-------------------+
|mydate |datetime |
+----------------------------+-------------------+
|Fri May 24 00:00:00 GMT 2019|2019-05-24 01:00:00|
+----------------------------+-------------------+
Legacy和当前版本的Spark之间的差异很微妙
例如:
spark.sql("set spark.sql.legacy.timeParserPolicy=EXCEPTION")
df = spark.createDataFrame([('12/25/2019 01:30:00 PM',),], ['Christmas'])
df.select(to_timestamp(col('Christmas'),'MM/dd/yyyy hh:mm:ss a')).show()
输出以下内容:
+----------------------------------------------+
|to_timestamp(Christmas, MM/dd/yyyy hh:mm:ss a)|
+----------------------------------------------+
| 2019-12-25 13:30:00|
+----------------------------------------------+
然而
spark.sql("set spark.sql.legacy.timeParserPolicy=EXCEPTION")
df = spark.createDataFrame([('12/25/2019 01:30:00 PM',),], ['Christmas'])
df.select(to_timestamp(col('Christmas'),'MM/dd/yyyy hh:mm:ss aa')).show()
会提高SparkUpgradeException
请注意,我们在时间格式中有"aa",而不仅仅是一个。
根据Java Docs,这是to_timestamp函数使用的,"aa"总是错误的,我想Spark的早期版本更宽松。
因此,要么修复日期格式,要么按照Shivam的建议将timeParserPolicy设置为"旧版"。
解析/格式化时间戳/日期字符串。当用户指定的模式用于解析和格式化时,这会对 CSV/JSON 数据源以及unix_timestamp、date_format、to_unix_timestamp、from_unixtime、to_date to_timestamp函数产生影响。在 Spark 3.0 中,我们在用于格式化和解析的日期时间模式中定义了自己的模式字符串,该模式通过 DateTimeFormatter 在后台实现。新实现对其输入执行严格检查。例如,如果模式为 yyyy-MM-dd,则无法解析 2015-07-22 10:00:00 时间戳,因为解析器不消耗整个输入。另一个示例是 31/01/2015 00:00 输入无法通过 dd/MM/yyyy hh:mm 模式解析,因为 hh 假定小时数在 1-12 范围内。在 Spark 2.4 及更低版本中,java.text.SimpleDateFormat 用于时间戳/日期字符串转换,支持的模式在 SimpleDateFormat 中描述。可以通过将 spark.sql.legacy.timeParserPolicy 设置为 LEGACY 来恢复旧行为
因此,将此 Spark 配置添加到您的代码中将解决此问题:
spark.conf.set("spark.sql.legacy.timeParserPolicy","LEGACY"(