如何在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()
有没有更好的方法来实现这一点。
【问题讨论】:
你能发布确切的日期格式吗? 是的,当然有更好的方法(至少一个)。我建议你不要使用SimpleDateFormat
和Calendar
。这些类设计不佳且早已过时,尤其是前者,尤其是出了名的麻烦。而是使用来自java.time, the modern Java date and time API 的LocalDate
和DateTimeFormatter
。
【参考方案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-dariabeginningOfWeek
和endOfWeek
函数是解决此问题的最简单方法。它们也是最灵活的,因为它们可以轻松配置为不同的周末结束日期。
假设你有这个数据集:
+----------+
| 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中获取周开始日期的主要内容,如果未能解决你的问题,请参考以下文章