Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 前几个月的最后日期Id_Scala_Date_Apache Spark Sql_Days - Fatal编程技术网

Scala 前几个月的最后日期Id

Scala 前几个月的最后日期Id,scala,date,apache-spark-sql,days,Scala,Date,Apache Spark Sql,Days,我的数据框有一个DateId(即一个整数列,将日期定义为自1993-06-25以来的天数)。目标是计算列中每个日期前一个月最后一天的日期id: DateId -> _intermittent calc Date_ -> _result LastDayOfPriorMonthId_ 9063 -> 2018-04-18 -> 9045 (i.e. 2018-03-31) 8771 -> 2017-06-

我的数据框有一个DateId(即一个整数列,将日期定义为自1993-06-25以来的天数)。目标是计算列中每个日期前一个月最后一天的日期id:

DateId ->  _intermittent calc Date_       -> _result LastDayOfPriorMonthId_
9063   ->  2018-04-18                     -> 9045 (i.e. 2018-03-31)
8771   ->  2017-06-30                     -> 8741 (i.e. 2017-05-31)
9175   ->  2018-08-08                     -> 9167 (i.e. 2018-07-31)
解决方案将非常简单,但我遇到了类型转换问题:

val a = Seq(9063, 8771, 9175).toDF("DateId")
val timeStart = to_date(lit("1993-06-25"))


val dateIdAdd : (Column) => Column = x => {x - date_add(timeStart, x).DATE_OF_MONTH}
函数编译失败,出现以下错误:

notebook:2: error: type mismatch;
found   : org.apache.spark.sql.Column
required: Int
   x - date_add(timeStart, x).DATE_OF_MONTH
.cast(IntegerType)
这样的表达式不会更改结果(
x
仍然是火花列类型,
.cast(Int)
不适用


请注意:问题中也解决了类似的问题,但当这里应用
timeStart
常量时,相同的方法失败了。同样,使用函数优于表达式,因为相同的计算用于实际数据的多列。

使用Scala转换函数测试许多选项后,hack基于带有Java字符串的UDF和
SimpleDataFormat
我唯一能弄明白的事情:

val dateIdAdd = udf((dateId : Long) => {
   val d = new SimpleDateFormat("yyyy-MM-dd")
   val ts = d.parse("1993-06-25")
   val tc = d.format(new Date(ts.getTime() + (24 * 3600 * 1000 * dateId)))
   dateId - Integer.parseInt(tc.substring(tc.length()-2))
})
在添加另一个验证支持功能和简单选择后:

val dateIdToDate = udf((dateId : Long) => {
  val d = new SimpleDateFormat("yyyy-MM-dd")
  val ts = d.parse("1993-06-25")
  d.format(new Date(ts.getTime() + (24 * 3600 * 1000 * dateId)))
})

val aa = a.select($"*"
             , dateIdToDate($"DateId") as "CalcDateFromId"
             , dateIdAdd($"DateId") as "CalcLastDayOfMonthId")

display(aa)
产生了预期结果(但我怀疑这是最有效的方法):


你能从Java翻译吗?对不起,我还没有编写Scala代码

编辑:根据您(提问者丹)的说法,Scala版本是:

val baseDate = LocalDate.of(1993, Month.JUNE, 25)
val lastDayIdOfPriorMonth = udf((dateId : Long) => {
    val date = baseDate.plusDays(dateId)
    val lastOfPrevMonth = YearMonth.from(date).minusMonths(1).atEndOfMonth()
    ChronoUnit.DAYS.between(baseDate, lastOfPrevMonth)
})
让我们使用您的示例日期(再次使用Java)进行尝试:

这张照片是:

9063 -> 9045
8771 -> 8741
9175 -> 9167
在你的问题中,你在最后一个案例中给出了9176作为预期结果,但我认为这是一个打字错误


请欣赏代码的清晰性和自解释性。

关于原始描述中的打字错误,您是对的。9167是正确的答案-基于我的文本字符串的黑客生成相同的结果(编辑原始问题以避免混淆)。您的解决方案需要3个附加库(
import java.time import java.time.\uimport java.time.temporal.ChronoUnit
)Scala的版本是:
val baseDate=LocalDate.of(1993年6月25日)val lastdaydofpriormonth=udf((dateId:Long)=>{val date baseDate baseDate.plusDays(dateId)val lastofpevmonth=YearMonth.from(date).minusMonths(1).atEndOfMonth()ChronoUnit.DAYS.between(baseDate,LastOfPreMonth)})
请在您的答案中声明此解决方案!感谢Scala翻译。我已经将其添加到了答案中。这就是您在Scala中计算库的方式吗?在Java中,我只会说它需要JDK,即不需要额外的库。它确实需要导入
Java.time.\u
Java.time.temporal.ChronoUnit
。是的,根据我有限的知识,库必须导入。可能有其他选择,但教程和示例经常使用导入(例如)。我认为这更像是单词用法的问题。必须导入类(在我工作的地方,50条导入语句并不少见,我们不认为这本身就是一个问题).图书馆里通常有很多课。
val baseDate = LocalDate.of(1993, Month.JUNE, 25)
val lastDayIdOfPriorMonth = udf((dateId : Long) => {
    val date = baseDate.plusDays(dateId)
    val lastOfPrevMonth = YearMonth.from(date).minusMonths(1).atEndOfMonth()
    ChronoUnit.DAYS.between(baseDate, lastOfPrevMonth)
})
    System.out.println("9063 -> " + dateIdAdd(9063));
    System.out.println("8771 -> " + dateIdAdd(8771));
    System.out.println("9175 -> " + dateIdAdd(9175));
9063 -> 9045
8771 -> 8741
9175 -> 9167