【问题标题】:How to get week start date in scala如何在scala中获取周开始日期
【发布时间】:2019-08-06 10:18:28
【问题描述】:

我写了下面的代码来获取通过日期的星期一日期,基本上创建了一个 udf 来传递一个日期并获取它的星期一日期

def calculate_weekstartUDF = udf((pro_rtc:String)=>{
  val df = new SimpleDateFormat("yyyy-MM-dd").parse(pro_rtc)
  val cal = Calendar.getInstance()
  cal.setTime(df)
  cal.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY)
  //Get this Monday date
  val Period=cal.getTime()
})

在下面的代码中使用上面的 UDF flattendedJSON.withColumn("weekstartdate",calculate_weekstartUDF($"pro_rtc")).show()

有没有更好的方法来实现这一点。

【问题讨论】:

  • 你能发布确切的日期格式吗?
  • 是的,当然有更好的方法(至少一个)。我建议你不要使用SimpleDateFormatCalendar。这些类设计不佳且早已过时,尤其是前者,尤其是出了名的麻烦。而是使用来自java.time, the modern Java date and time APILocalDateDateTimeFormatter

标签: scala date apache-spark user-defined-functions


【解决方案1】:

使用 spark 中的 date_sub,next_day 函数尝试这种方法。

解释:

date_sub(
        next_day('dt,"monday"), //get next monday date
   7)) //substract week from the date

Example:

val df =Seq(("2019-08-06")).toDF("dt")
import org.apache.spark.sql.functions._
df.withColumn("week_strt_day",date_sub(next_day('dt,"monday"),7)).show()

Result:

+----------+-------------+
|        dt|week_strt_day|
+----------+-------------+
|2019-08-06|   2019-08-05|
+----------+-------------+

【讨论】:

  • 智能简单
【解决方案2】:

您可以使用 Java 8 日期 API:

import java.time.LocalDate
import java.time.format.DateTimeFormatter
import java.time.temporal.{TemporalField, WeekFields}
import java.util.Locale

def calculate_weekstartUDF =
 (pro_rtc:String)=>{
   val localDate = LocalDate.parse(pro_rtc);  // By default parses a string in YYYY-MM-DD format.
   val dayOfWeekField = WeekFields.of(Locale.getDefault).dayOfWeek()
   localDate.`with`(dayOfWeekField, 1)  
  }

当然,如果您想使用另一个Locale,请指定除Locale.getDefault 之外的其他内容。

【讨论】:

【解决方案3】:

tl;博士

LocalDate
.parse( "2019-01-23" )
.with(
    TemporalAdjusters.previous( DayOfWeek.MONDAY )
)
.toString()

2019-01-21

避免使用旧的日期时间类

您正在使用糟糕的日期时间类,这些类在几年前被 JSR 310 中定义的现代 java.time 类所取代。

java.time

您的输入字符串是标准的ISO 8601 格式。 java.time 类在解析/生成字符串时默认使用这些标准格式。所以不需要指定格式模式。

这里是 Java 语法示例代码。 (我不知道 Scala)

LocalDate ld = LocalDate.parse( "2019-01-23" ) ;

要从那个日期移到另一个日期,请使用TemporalAdjuster。您可以在 TemporalAdjusters 类中找到几个。

使用DayOfWeek 枚举指定一周中的某一天,预定义七个对象,一周中的每一天一个。

TemporalAdjuster ta = TemporalAdjusters.previous( DayOfWeek.MONDAY ) ;
LocalDate previousMonday = ld.with( ta ) ;

看到这个code run live at IdeOne.com

2019 年 1 月 21 日,星期一

如果开始日期恰好是星期一,而您想继续使用该日期,请使用备用调节器 previousOrSame

【讨论】:

  • @OleV.V.我在最后提到过。问题写得不清晰,我看不出作者的意图。
【解决方案4】:

试试这个:

在我的示例中,“pro_rtc”以秒为单位。根据需要进行调整。

import org.apache.spark.sql.functions._
dataFrame
   .withColumn("Date", to_date(from_unixtime(col("pro_rtc"))))
   .withColumn("Monday", expr("date_sub(Date, dayofweek(Date) - 2)"))

这样,您还可以利用 Spark 的查询引擎并避免 UDF 的延迟

【讨论】:

  • date_sub(Date, dayofweek(Date) - 1) 会在星期日而不是星期一,无论如何感谢您的回答:)
  • 对。我会解决的
  • 即使现在也有问题dayofweek只适用于周日
  • 你确定吗?我检查了整整 7 天
【解决方案5】:

spark-dariabeginningOfWeekendOfWeek 函数是解决此问题的最简单方法。它们也是最灵活的,因为它们可以轻松配置为不同的周末结束日期。

假设你有这个数据集:

+----------+
| some_date|
+----------+
|2020-12-27|
|2020-12-28|
|2021-01-03|
|2020-12-12|
|      null|
+----------+

假设一周在星期三结束,以下是计算一周开始和一周结束的方法:

import com.github.mrpowers.spark.daria.sql.functions._
df
  .withColumn("end_of_week", endOfWeek(col("some_date"), "Wed"))
  .withColumn("beginning_of_week", beginningOfWeek(col("some_date"), "Wed"))
  .show()

结果如下:

+----------+-----------+-----------------+
| some_date|end_of_week|beginning_of_week|
+----------+-----------+-----------------+
|2020-12-27| 2020-12-30|       2020-12-24|
|2020-12-28| 2020-12-30|       2020-12-24|
|2021-01-03| 2021-01-06|       2020-12-31|
|2020-12-12| 2020-12-16|       2020-12-10|
|      null|       null|             null|
+----------+-----------+-----------------+

有关底层实现,请参阅this fileThis post 更详细地解释了这些功能。

【讨论】:

  • 非常感谢您能就此分享任何想法
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-19
  • 2017-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多