我在火花日期格式中观察到了奇怪的行为。实际上,我需要将日期yy
转换为yyyy
。日期转换后,日期应该是20yy
我尝试如下,但2040年后失败了。
import org.apache.spark.sql.functions._
val df= Seq(("06/03/35"),("07/24/40"), ("11/15/43"), ("12/15/12"), ("11/15/20"), ("12/12/22")).toDF("Date")
df.withColumn("newdate", from_unixtime(unix_timestamp($"Date", "mm/dd/yy"), "mm/dd/yyyy")).show
+--------+----------+
| Date| newdate|
+--------+----------+
| 06/3/35|06/03/2035|
|07/24/40|07/24/2040|
|11/15/43|11/15/1943| // Here year appended with 19
|12/15/12|12/15/2012|
|11/15/20|11/15/2020|
|12/12/22|12/12/2022|
+--------+----------+
为什么会有这种行为,是否有任何我可以直接使用的日期实用程序函数,而无需在字符串日期后附加20
答案 0 :(得分:3)
解析两位数的年份字符串受SimpleDateFormat
docs中记录的某些相对解释的约束:
要使用缩写的年份模式(“ y”或“ yy”)进行分析,SimpleDateFormat必须解释相对于某个世纪的缩写的年份。它通过将日期调整为在创建SimpleDateFormat实例之前的80年内和之后的20年内来实现此目的。例如,使用模式“ MM / dd / yy”和1997年1月1日创建的SimpleDateFormat实例,字符串“ 01/11/12”将解释为2012年1月11日,而字符串“ 05/04 /” 64”将被解释为1964年5月4日。
因此,2043
距今已有20年之久,解析器使用记录中的1943。
这是一种使用UDF的方法,该UDF在解析日期之前显式调用set2DigitYearStart
对象上的SimpleDateFormat
(我以1980年为例):
def parseDate(date: String, pattern: String): Date = {
val format = new SimpleDateFormat(pattern);
val cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1980)
val beginning = cal.getTime();
format.set2DigitYearStart(beginning)
return new Date(format.parse(date).getTime);
}
然后:
val custom_to_date = udf(parseDate _);
df.withColumn("newdate", custom_to_date($"Date", lit("mm/dd/yy"))).show(false)
+--------+----------+
|Date |newdate |
+--------+----------+
|06/03/35|2035-01-03|
|07/24/40|2040-01-24|
|11/15/43|2043-01-15|
|12/15/12|2012-01-15|
|11/15/20|2020-01-15|
|12/12/22|2022-01-12|
+--------+----------+
了解数据后,您将知道为set2DigitYearStart()
的参数选择哪个值