Scala Spark中year函数返回年份错误问题求助
为啥Spark提取1000年早期日期的年份会少1?
嘿,这个问题其实是个隐藏的历法历史坑!你遇到的情况完全是因为Spark依赖的Java日期API在处理公元1582年之前的日期时,会自动做儒略历和格里高利历的转换校准,导致年份计算出现偏移。
到底是啥原因?
简单说,现在我们用的公历(格里高利历)是1582年才由教皇格里高利十三世推行的,用来修正儒略历的闰年误差;在那之前欧洲普遍使用的是儒略历。Java的日期库在处理公元1年到1582年的日期时,会把你输入的公历日期转换成对应的儒略历日期来计算年份:
- 你输入的
1000-01-03这个公历日期,对应的儒略历日期其实是999年12月24日,所以year函数自然就提取到了999。 - 等日期到了
1000-01-05,对应的儒略历日期已经跨入1000年了,所以年份就正常显示1000了。
怎么验证和解决?
先验证下这个转换逻辑
你可以用Java代码直接测试这个历法转换:
import java.time.LocalDate; import java.time.chrono.JulianChronology; public class CalendarTest { public static void main(String[] args) { LocalDate gregDate = LocalDate.of(1000, 1, 3); LocalDate julianDate = JulianChronology.INSTANCE.date(gregDate); System.out.println("公历日期: " + gregDate); System.out.println("对应儒略历日期: " + julianDate); System.out.println("儒略历年份: " + julianDate.getYear()); // 输出999 } }
在Spark里拿到正确的公历年份
如果你需要强制按格里高利历(也就是我们现在用的公历)来计算早期日期的年份,可以写个自定义UDF绕开这个自动转换:
import org.apache.spark.sql.functions._ import java.time.chrono.IsoChronology val df = Seq( ("1000-01-03 00:00:00") ).toDF("date_val") .withColumn("conv_date", to_date(col("date_val"))) // 自定义UDF,强制用ISO格里高利历提取年份 .withColumn("year_val_greg", udf((date: java.sql.Date) => { val localDate = date.toLocalDate() IsoChronology.INSTANCE.year().get(localDate) }).apply(col("conv_date"))) .withColumn("year_val_trunc", trunc( to_date(col("date_val")),"year")) df.show()
这样处理后,1000-01-03的年份就会正确返回1000了。
另外你看到的year_val_trunc显示0999-01-06,也是因为trunc函数同样受到了这个历法转换的影响,截断的是儒略历的年份起始日期。
内容的提问来源于stack exchange,提问作者rg687
相关产品推荐
相关产品推荐

