Scala Spark中ISO 8601 timestemp字符串的日期差异

Scala Spark中ISO 8601 timestemp字符串的日期差异,scala,datetime,apache-spark,timestamp,Scala,Datetime,Apache Spark,Timestamp,我有两个ISO 8601格式的日期时间字符串: 2017-05-30T09:15:06.050298Z 2017-05-30T09:15:06.054939Z 我想要在Spark环境中使用Scala计算上述两个字符串之间的时间差 您可以使用xml日期解析器,因为它必须遵守ISO-8601: val t1 = javax.xml.bind.DatatypeConverter.parseDateTime("2017-05-30T09:15:06.050298Z") val t2 = javax.x

我有两个ISO 8601格式的日期时间字符串:

2017-05-30T09:15:06.050298Z
2017-05-30T09:15:06.054939Z


我想要在Spark环境中使用Scala计算上述两个字符串之间的时间差

您可以使用xml日期解析器,因为它必须遵守ISO-8601:

val t1 = javax.xml.bind.DatatypeConverter.parseDateTime("2017-05-30T09:15:06.050298Z")

val t2 = javax.xml.bind.DatatypeConverter.parseDateTime("2017-05-30T09:15:06.054939Z")

val diff = t1.getTimeInMillis - t2.getTimeInMillis
Java 8的
LocalDateTime
为纳秒 由于Spark不支持大于秒的日期差,我们需要为毫秒或纳米创建一个UDF

与日期时间相关的导入 以纳秒为单位创建UDF到日期的差异 检查:

通过将当天的
ChronoField.NANO\u修改为当天的
ChronoField.MICRO\u
在UDF的最后一行中,我们还可以获得微秒级的日期差

现在,在任何DataFrame/DataSet对象上使用UDF

import spark.implicits._ //to use $-notation on columns

// create the dataframe df
val df = ...

val resultDf = df.withColumn("date_diff", date_diff_nano($"dt1", $"dt2"))
这里
dt1
dt2
df


秒差与Spark SQL的unix\u时间戳 使用Spark SQL预定义函数将日期转换为一天中的秒数(但是Java
SimpleDataFormat
可以支持长达毫秒的解析),然后您就可以这样做了


使用
datediff
它接受以下格式的日期时间值

  • java.sql.Timestamp
  • java.sql.Date
  • 'YYYY-MM-dd'
  • 'YYYY-MM-dd HH:MM:ss'的字符串格式

正如你在评论中所说,你使用的是Joda Time,这里有一个使用它的答案

你说你在两天之间打电话给
。但是两个日期都在同一天,所以结果总是零。要获得毫秒精度的日期差,只需从两个
DateTime
对象中减去毫秒值:

import org.joda.time.DateTime

val s1 = "2017-05-30T09:15:06.050298Z"
val s2 = "2017-05-30T09:15:06.054939Z"

val diffInMillis = DateTime.parse(s2).getMillis() - DateTime.parse(s1).getMillis()
diffInMillis
将是
4
——第一个日期的秒分数是
050298
,第二个是
054939
,但joda的
DateTime
具有毫秒精度,因此最后3位数字被丢弃。您可以通过执行以下操作进行检查:

println(DateTime.parse(s1))
println(DateTime.parse(s2))
这将输出:

2017-05-30T09:15:06.050Z
2017-05-30T09:15:06.054Z

如您所见,日期之间的差异为4毫秒


新的Java日期/时间API Joda Time处于维护模式,正在被新的API所取代,因此我不建议使用它启动新项目。甚至在文章中也提到:“请注意,Joda Time被认为是一个基本上“完成”的项目。没有计划进行重大的增强。如果使用Java SE 8,请迁移到Java.Time(JSR-310)。”


如果您有新的
java.time
API(JDK>=1.8),您也可以使用它。如果
java.time
类不可用(JDK你试过什么吗?你说的spark env是什么意思,你有spark dataframe和rdd吗?是的,我试过几个选项。spark env只是一个可选的。我有一个spark dataframe,我也在检查非dataframe操作。我试过org.joda.time.DateTime,在那里我只能找到天之间的差异。那又怎样那么,你想得到差异吗?例如,我得到的代码输出是:d1:org.joda.time.DateTime=2017-05-30T09:15:06.050Z d2:org.joda.time.DateTime=2017-05-30T09:15:06.054Z days:Int=0如果我在两天之间尝试,那么差异是0。但是我不想要日差,我要的是秒/毫秒差到分d差异(如果有)。您使用的是哪种spark版本?spark SQL unix_时间戳将忽略毫秒部分。它在您链接到的文档中明确说明了这一点。@sradomski:很高兴看到建设性的反馈。我更正了它并添加了其他信息。我们现在放弃了spark毫秒处理,并将时间戳编码为UTC后的毫秒大纪元。
import org.apache.spark.sql.functions.unix_timestamp

val resultDf = df.withColumn("date_diff_sec", 
  (unix_timestamp($"dt1"), unix_timestamp($"dt2")))
import org.apache.spark.sql.functions.datediff

val resultDf = df.withColumn("date_diff_days", datediff($"dt1", $"dt2"))
import org.joda.time.DateTime

val s1 = "2017-05-30T09:15:06.050298Z"
val s2 = "2017-05-30T09:15:06.054939Z"

val diffInMillis = DateTime.parse(s2).getMillis() - DateTime.parse(s1).getMillis()
println(DateTime.parse(s1))
println(DateTime.parse(s2))
import java.time.Instant
import java.time.temporal.ChronoUnit

val s1 = "2017-05-30T09:15:06.050298Z"
val s2 = "2017-05-30T09:15:06.054939Z"

// difference in nanoseconds
val diffInNanos = ChronoUnit.NANOS.between(Instant.parse(s1), Instant.parse(s2))