我有两个ISO 8601格式的日期时间字符串:
2017-05-30T09:15:06.050298Z
2017-05-30T09:15:06.054939Z
我想在Spark环境中使用Scala来区分上述两个字符串之间的时差。
答案 0 :(得分:1)
由于Spark不支持高于Seconds的日期差异,我们需要为Millis或Nanos创建UDF 。
LocalDateTime
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoField;
检查:help in building DateTimeFormatter pattern
将
spark.udf.register("date_diff_nano", (d1: String, d2: String) => val dtFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.n'Z'") val dt1 = LocalDateTime.parse(d1, dtFormatter) val dt2 = LocalDateTime.parse(d2, dtFormatter) (dt1.getLong(ChronoField.NANO_OF_DAY) - dt2.getLong(ChronoField.NANO_OF_DAY)) )
修改为ChronoField.NANO_OF_DAY
在UDF的最后一行,我们也可以在微秒内获得日期差异。
现在,在任何DataFrame / DataSet对象上使用UDF。
ChronoField.MICRO_OF_DAY
此处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_timestamp(date, format)
函数将日期转换为当天的秒数(但Java unix_timestamp
可以支持解析最多毫秒),然后您可以执行Date diff with Spark SQL using unix_timestamp。
SimpleDateFormat
import org.apache.spark.sql.functions.unix_timestamp
val resultDf = df.withColumn("date_diff_sec",
(unix_timestamp($"dt1"), unix_timestamp($"dt2")))
它接受以下格式的日期时间值
datediff
java.sql.Timestamp
- 的字符串格式
java.sql.Date
- 的字符串格式
'YYYY-MM-dd'
'YYYY-MM-dd HH:mm:ss'
答案 1 :(得分:1)
正如你在评论中所说,你正在使用Joda-Time,这是一个使用它的答案。
你说你正在呼叫daysBetween
。但是两个日期都在同一天,所以结果总是为零。要获得具有毫秒精度的日期之间的差异,只需从两个DateTime
对象中减去millis值:
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毫秒。
Joda-Time处于维护模式,正在被新的API取代,因此我不建议使用它来启动新项目。即使在joda's website中它也说:“请注意,Joda-Time被认为是一个很大程度上”完成“的项目。没有计划大的增强。如果使用Java SE 8,请迁移到java.time(JSR) -310)。“强>
如果您有新的java.time
API(JDK> = 1.8),您也可以使用它。如果java.time
类不可用(JDK <= 1.7),您可以尝试基于scala time的ThreeTen Backport,这是Java 8的新日期/时间类的一个很好的后端
以下代码适用于两者。
唯一的区别是包名称(在Java 8中为java.time
,在ThreeTen Backport(或Android的ThreeTenABP)中为org.threeten.bp
),但类和方法名称是相同的
不同之处在于此API具有纳秒精度,因此您可以获得以纳秒为单位的日期之间的差异。
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))
diffInNanos
的值为4641000
。如果您仍然希望以毫秒为单位的此值,则可以将其除以1000000,或使用ChronoUnit.MILLIS
代替ChronoUnit.NANOS
。
答案 2 :(得分:0)
您可以使用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