如何在scala中获取周开始日期

Posted

技术标签:

【中文标题】如何在scala中获取周开始日期【英文标题】:How to get week start date in 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 API 的LocalDateDateTimeFormatter 【参考方案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 之外的其他内容。

【讨论】:

得到这个错误Schema for type java.time.LocalDate is not supported BTW 输入是 unix 时间格式 Schema for type Any is not supported,也许?【参考方案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 file。 This post 更详细地解释了这些功能。

【讨论】:

非常感谢您能就此分享任何想法

以上是关于如何在scala中获取周开始日期的主要内容,如果未能解决你的问题,请参考以下文章

获取给定周年、给定月份和给定周的开始和结束日期

如何计算当前日期是当年的第几周

如何从当前日期 PHP 获取最近 7 周、7 个月的日期范围?

获取某一天所在周的开始日期和结束日期

如何在 ssis 包中的变量中获取当前周星期一的日期

js如何获取时间