Spark中dd-MMM-YY格式日期字符串转Timestamp失败求助
日期转换错误的原因分析与修复方案
嘿,我帮你拆解了下你遇到的日期转Timestamp出错的问题,主要有几个核心坑点,还有对应的解决办法:
最可能的问题:格式匹配与年份解析偏差
你的日期格式是1-Jan-14(单数字日+英文月份缩写+两位年份),你用的d-MMM-yy格式看起来没问题,但其实藏着两个容易踩的坑:
- 月份缩写的语言依赖:
MMM这个格式符要求Spark运行环境的默认语言是英文,如果你的本地/集群环境是其他语言(比如中文),就识别不了Jan这种英文月份缩写,直接返回null。 - 两位年份的解析逻辑:
yy格式默认会把14解析成1914而不是2014,而unix时间戳是从1970年开始计算的,1914年早于这个时间点,转成Timestamp自然会得到错误值甚至null。
次要问题:unix_timestamp的局限性
unix_timestamp返回的是从1970-01-01到目标日期的秒数,本身是个长整型。如果解析出的年份在1970之前,这个值会是负数,而Timestamp类型基于unix时间戳,没法表示1970年之前的时间,这就直接导致转换失败。
修复方案:用更可靠的to_timestamp函数
Spark 2.0之后推出的to_timestamp函数比unix_timestamp更友好,直接支持日期转Timestamp,还能指定语言环境和时区,完美解决上面的问题:
import org.apache.spark.sql.functions.to_timestamp val finalDf: DataFrame = priceDF .withColumn("Price", priceDF("ClosePrice").cast(DoubleType)) // 核心修复:用to_timestamp,指定格式,同时加上英文locale避免语言识别问题 .withColumn("TimeStamp", to_timestamp($"Date", "d-MMM-yy", "en_US")) .drop("Date").drop("ClosePrice") .sort("TimeStamp")
如果你的Spark版本比较旧,必须用unix_timestamp,那得手动调整年份:
import org.apache.spark.sql.functions.{unix_timestamp, lit, when} val finalDf: DataFrame = priceDF .withColumn("Price", priceDF("ClosePrice").cast(DoubleType)) .withColumn("unixTime", unix_timestamp($"Date", "d-MMM-yy")) // 把19xx的日期调整为20xx:如果unixTime是负数(早于1970),加上100年的秒数 .withColumn("adjustedUnixTime", when($"unixTime" < 0, $"unixTime" + lit(3153600000L)).otherwise($"unixTime")) .withColumn("TimeStamp", $"adjustedUnixTime".cast(TimestampType)) .drop("Date", "ClosePrice", "unixTime", "adjustedUnixTime") .sort("TimeStamp")
额外提醒
- 先确认你的CSV里所有日期格式都是统一的
d-MMM-yy,要是有混合格式(比如有的是01-Jan-14),得先做数据清洗。 - 最好在Spark配置里指定时区,避免时区差异导致的时间偏差:
sparkConf.set("spark.sql.session.timeZone", "Asia/Kolkata") // 换成你实际用的时区,比如UTC
内容的提问来源于stack exchange,提问作者Shashi Shankar
相关产品推荐
相关产品推荐

