火花日期格式问题

时间:2020-03-11 05:44:18

标签: scala apache-spark date-format

我在火花日期格式中观察到了奇怪的行为。实际上,我需要将日期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

1 个答案:

答案 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()的参数选择哪个值