Scala中时间处理org.joda.time.DateTime工具

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/whgyxy/article/details/86554624

org.joda.time.DateTime常用工具 scala实现

org.joda.time

java原生的时间处理函数实在是无力吐槽,太难用了。后来找到一个非常好用的时间处理模块——joda时间处理,真是个好东西,处理时间非常便捷,在这个基础上进行简单的封装可以完成很多事情,这里列出scala的一些实现。这里使用的日期输入都支持整型(YYYYMMDD)和字符串(YYYY-MM-DD)两种输入格式

POM文件依赖

    <dependency>
      <groupId>joda-time</groupId>
      <artifactId>joda-time</artifactId>
      <version>2.9.2</version>
    </dependency>

方法索引

函数名 功能 描述
toISODate 转为日期标准ISO8601格式 将YYYYMMDD,YYYY/MM/DD,YYYY%MM%DD,DD%MM%YYYY,DD/MM/YYYY等格式转为标准ISO格式YYYY-MM-DD
dayOfWeek 根据日期返回周几
getDeltaNaturalWeek 返回上N个自然周的周一与周日 delta支持负数
getDeltaNaturalMonth 返回上N个自然月的1号和最后一天 delta支持负数
getDeltaWeekRange 返回上delta个周的自然周的第一天和上一周的最后一天,注意与 getDeltaNaturalWeek 的区别 delta支持负数
getDeltaMonthRange 返回上delta个月的自然月的第一天和上月的最后一天注意与getDeltaNaturalMonth的区别 delta支持负数
getDeltaMonthCut 返回上delta个月的月份形式 delta支持负数
getDeltaDay 返回具体日期 delta支持负数
getRangeDays 从开始日期和结合日期获取日期列表 包含开始与结束日期
getDeltaRangeDays 以开始日期与相邻天数确定日期列表 delta支持负数
getDaysOfMonth 获取制定月份的所有日期 month 支持 YYYYMM 或 YYYYMMDD
getRangeMonths 从开始日期和结束日期获取月份列表
getWeekGroup 从开始日期和结束日期获取周中和周末的元组
getDelta 查看两个日期相差多少天 如果startTime和endTime参数写反了话结果就是负数
import org.joda.time.{DateTime, Days}

import scala.collection.mutable.ArrayBuffer


object JodaUtils {

  val MONTH_NUM_MAP = Map(1 -> 0, 2 -> 3, 3 -> 3, 4 -> 6, 5 -> 1, 6 -> 4, 7 -> 6, 8 -> 2, 9 -> 5, 10 -> 0, 11 -> 3, 12 -> 5)
  val CENTRURY_NUM = 6

  /**
    * 转为日期标准ISO8601格式
    *
    * @param date YYYYMMDD
    * @return yyyy-MM-dd
    */
  def toISODate(date: Int): String = {
    val day = date % 100
    val month = date / 100 % 100
    val year = date / 10000
    year + "-" + month + "-" + day
  }

  /**
    * 转为日期标准ISO8601格式
    *
    * @param date    支持YYYYMMDD,YYYY/MM/DD,YYYY%MM%DD,DD%MM%YYYY,DD/MM/YYYY
    * @param reverse 日期是否是反转格式,如: 08/03/2018, 08-03-2018,默认是正常格式,如20180308 2018/03/08
    * @return yyyy-MM-dd
    */
  def toISODate(date: String, reverse: Boolean = false): String = {
    if (reverse) {
      if (date.length == 8)
        date.substring(6, 8) + "-" + date.substring(4, 6) + "-" + date.substring(0, 4)
      else if (date.length == 10)
        date.substring(8, 10) + "-" + date.substring(5, 7) + "-" + date.substring(0, 4)
      else
        throw new Exception("date length must be 8 or 10:" + date)
    } else {
      if (date.length == 8)
        date.substring(0, 4) + "-" + date.substring(4, 6) + "-" + date.substring(6, 8)
      else if (date.length == 10)
        date.substring(0, 4) + "-" + date.substring(5, 7) + "-" + date.substring(8, 10)
      else
        throw new Exception("date length must be 8 or 10:" + date)
    }
  }

  /**
    * 输入日期是星期几 如:20180308 -> 4  即周四
    *
    * @param date YYYYMMDD
    * @return 周几,值一定落在集合{1, 2, 3, 4, 5, 6, 7}, eg. 1 -> Monday
    */
  def dayOfWeek(date: Int): Int = {
    val year = date / 10000 % 100
    val month = MONTH_NUM_MAP(date / 100 % 100)
    val day = date % 100
    val yearNum = year / 4
    val N = (CENTRURY_NUM + year + yearNum + month + day) % 7
    if (0 == N) 7
    else N
  }

  /**
    * 输入日期是星期几 如:2018-03-08 -> 4  即周四
    *
    * @param day ISO日期格式,yyyy-MM-dd
    * @return 周几,值一定落在集合{1, 2, 3, 4, 5, 6, 7}, eg. 1 -> Monday
    */
  def dayOfWeek(date: String): Int = {
    val year = date.slice(2, 4).toInt
    val month = date.slice(5, 7).toInt
    val day = date.slice(8, 10).toInt
    val yearNum = year / 4
    val monthNum = MONTH_NUM_MAP(month)
    val N = (CENTRURY_NUM + year + yearNum + monthNum + day) % 7
    if (0 == N) 7
    else N
  }

  /**
    * 返回上delta个周的自然周的第一天和最后一天 如:
    * (20180308,-2)-> (20180219,20180225)
    * (20180308,-1)-> (20180226,20180304)
    * (20180308,0) -> (20180305,20180311)
    * (20180308,1) -> (20180312,20180318)
    * (20180308,2) -> (20180319,20180325)
    *
    * @param date  YYYYMMDD
    * @param delta 上n周
    * @return 上个自然周周一、周日的日期(YYYYMMDD)
    */
  def getDeltaNaturalWeek(date: Int, delta: Int): (Int, Int) = {
    val day = new DateTime(toISODate(date))
    val Monday = day.plusWeeks(delta).minusDays(day.getDayOfWeek - 1).toString("yyyyMMdd").toInt
    val Sunday = day.plusWeeks(delta + 1).minusDays(day.getDayOfWeek).toString("yyyyMMdd").toInt
    (Monday, Sunday)
  }

  /**
    * 返回上delta个周的自然周的第一天和最后一天 如:
    * (2018-03-08,-2)-> (2018-02-19,2018-02-25)
    * (2018-03-08,-1)-> (2018-02-26,2018-03-04)
    * (2018-03-08,0) -> (2018-03-05,2018-03-11)
    * (2018-03-08,1) -> (2018-03-12,2018-03-18)
    * (2018-03-08,2) -> (2018-03-19,2018-03-25)
    *
    * @param date  ISO日期格式,yyyy-MM-dd
    * @param delta 上n周
    * @return 上个自然周周一、周日的日期(yyyy-MM-dd)
    */
  def getDeltaNaturalWeek(date: String, delta: Int): (String, String) = {
    val day = new DateTime(date)
    val Monday = day.plusWeeks(delta).minusDays(day.getDayOfWeek - 1).toString("yyyy-MM-dd")
    val Sunday = day.plusWeeks(delta + 1).minusDays(day.getDayOfWeek).toString("yyyy-MM-dd")
    (Monday, Sunday)
  }

  /**
    * 返回上delta个月的自然月的第一天和最后一天 如:
    * (20180308,-2)) -> (20180101,20180131)
    * (20180308,-1) -> (20180201,20180228)
    * (20180308,0)  -> (20180301,20180331)
    * (20180308,1)  -> (20180401,20180430)
    * (20180308,2)  -> (20180501,20180531)
    *
    * @param date  YYYYMMDD
    * @param delta 上delta个月
    * @return 上delta个自然月第一天、最后一天的日期(YYYYMMDD)
    */
  def getDeltaNaturalMonth(date: Int, delta: Int): (Int, Int) = {
    val day = new DateTime(toISODate(date))
    val firstDay = day.plusMonths(delta).toString("yyyyMM01").toInt
    val lastDay = day.plusMonths(delta + 1).minusDays(day.getDayOfMonth).toString("yyyyMMdd").toInt
    (firstDay, lastDay)
  }


  /**
    * 返回上delta个月的自然月的第一天和最后一天 如:
    * (2018-03-08,-2) -> (2018-01-01,2018-01-31)
    * (2018-03-08,-1) -> (2018-02-01,2018-02-28)
    * (2018-03-08,0)  -> (2018-03-01,2018-03-31)
    * (2018-03-08,1)  -> (2018-04-01,2018-04-30)
    * (2018-03-08,2)  -> (2018-05-01,2018-05-31)
    *
    * @param date  ISO日期格式,yyyy-MM-dd
    * @param delta 上delta个月
    * @return 上delta个自然月第一天、最后一天的日期(yyyy-MM-dd)
    */
  def getDeltaNaturalMonth(date: String, delta: Int): (String, String) = {
    val day = new DateTime(date)
    val firstDay = day.plusMonths(delta).toString("yyyy-MM-01")
    val lastDay = day.plusMonths(delta + 1).minusDays(day.getDayOfMonth).toString("yyyy-MM-dd")
    (firstDay, lastDay)
  }

  /**
    * 返回上delta个周的自然周的第一天和最后一天 如:
    * (20180308,-2)-> (20180219,20180304)
    * (20180308,-1)-> (20180226,20180304)
    * (20180308,0) -> (20180305,20180311)
    * (20180308,1) -> (20180312,20180318)
    * (20180308,2) -> (20180312,20180325)
    *
    * @param date  YYYYMMDD
    * @param delta 上n周
    * @return 上个自然周周一、周日的日期(YYYYMMDD)
    */
  def getDeltaWeekRange(date: Int, delta: Int ): (Int, Int) = {
    val day = new DateTime(toISODate(date))
    if (delta >= 0) {
      val incremental = if (delta == 0) 0 else 1
      val Monday = day.plusWeeks(incremental).minusDays(day.getDayOfWeek - 1).toString("yyyyMMdd").toInt
      val Sunday = day.plusWeeks(delta + 1).minusDays(day.getDayOfWeek).toString("yyyyMMdd").toInt
      (Monday, Sunday)
    } else {
      val Monday = day.plusWeeks(delta).minusDays(day.getDayOfWeek - 1).toString("yyyyMMdd").toInt
      val Sunday = day.minusDays(day.getDayOfWeek).toString("yyyyMMdd").toInt
      (Monday, Sunday)
    }
  }


  /**
    * 返回上delta个周的自然周的第一天和最后一天 如:
    * (2018-03-08,-2)-> (2018-02-19,2018-03-04)
    * (2018-03-08,-1)-> (2018-02-26,2018-03-04)
    * (2018-03-08,0) -> (2018-03-05,2018-03-11)
    * (2018-03-08,1) -> (2018-03-12,2018-03-18)
    * (2018-03-08,2) -> (2018-03-12,2018-03-25)
    *
    * @param date  ISO日期格式,yyyy-MM-dd
    * @param delta 上n周
    * @return 上个自然周周一、周日的日期(yyyy-MM-dd)
    */
  def getDeltaWeekRange(date: String, delta: Int): (String, String) = {
    val day = new DateTime(date)
    if (delta >= 0) {
      val incremental = if (delta == 0) 0 else 1
      val Monday = day.plusWeeks(incremental).minusDays(day.getDayOfWeek - 1).toString("yyyy-MM-dd")
      val Sunday = day.plusWeeks(delta + 1).minusDays(day.getDayOfWeek).toString("yyyy-MM-dd")
      (Monday, Sunday)
    } else {
      val Monday = day.plusWeeks(delta).minusDays(day.getDayOfWeek - 1).toString("yyyy-MM-dd")
      val Sunday = day.minusDays(day.getDayOfWeek).toString("yyyy-MM-dd")
      (Monday, Sunday)
    }
  }

  /**
    * 返回上delta个月的自然月的第一天和最后一天 如:
    * (20180308,-2) -> (20180101,20180228)
    * (20180308,-1) -> (20180201,20180228)
    * (20180308,0)  -> (20180301,20180331)
    * (20180308,1)  -> (20180401,20180430)
    * (20180308,2)  -> (20180401,20180531)
    *
    * @param date  YYYYMMDD
    * @param delta 上delta个月
    * @return 上delta个自然月第一天、最后一天的日期(YYYYMMDD)
    */
  def getDeltaMonthRange(date: Int, delta: Int): (Int, Int) = {
    val day = new DateTime(toISODate(date))
    if (delta >= 0) {
      val incremental = if (delta == 0) 0 else 1
      val firstDay = day.plusMonths(incremental).toString("yyyyMM01").toInt
      val lastDay = day.plusMonths(delta + 1).minusDays(day.getDayOfMonth).toString("yyyyMMdd").toInt
      (firstDay, lastDay)
    } else {
      val firstDay = day.plusMonths(delta).toString("yyyyMM01").toInt
      val lastDay = day.minusDays(day.getDayOfMonth).toString("yyyyMMdd").toInt
      (firstDay, lastDay)
    }
  }

  /**
    * 返回上delta个月的自然月的第一天和最后一天 如:
    * (2018-03-08,-2) -> (2018-01-01,2018-02-28)
    * (2018-03-08,-1) -> (2018-02-01,2018-02-28)
    * (2018-03-08,0)  -> (2018-03-01,2018-03-31)
    * (2018-03-08,1)  -> (2018-04-01,2018-04-30)
    * (2018-03-08,2)  -> (2018-04-01,2018-05-31)
    *
    * @param date  ISO日期格式,yyyy-MM-dd
    * @param delta 上delta个月
    * @return 上delta个自然月第一天、最后一天的日期(yyyy-MM-dd)
    */
  def getDeltaMonthRange(date: String, delta: Int): (String, String) = {
    val day = new DateTime(date)
    if (delta >= 0) {
      val incremental = if (delta == 0) 0 else 1
      val firstDay = day.plusMonths(incremental).toString("yyyy-MM-01")
      val lastDay = day.plusMonths(delta + 1).minusDays(day.getDayOfMonth).toString("yyyy-MM-dd")
      (firstDay, lastDay)
    } else {
      val firstDay = day.plusMonths(delta).toString("yyyy-MM-01")
      val lastDay = day.minusDays(day.getDayOfMonth).toString("yyyy-MM-dd")
      (firstDay, lastDay)
    }
  }


  /**
    * 返回上delta个月的月份形式 如:20180308,delta=1 ->  201802
    *
    * @param date  YYYYMMDD
    * @param delta 上几个月,默认n=1,即上一个月
    * @return YYYYMM
    */
  def getDeltaMonthCut(date: Int, delta: Int = -1): Int = {
    val day = new DateTime(toISODate(date))
    day.plusMonths(delta).toString("yyyyMM").toInt
  }

  /**
    * 返回具体日期,如(20180308,-1)-> 20180307,(20180308,0)-> 20180308,(20180308,1)-> 20180309,
    *
    * @param date  YYYYMMDD
    * @param delta 间隔的天数
    * @return YYYYMMDD
    */
  def getDeltaDay(date: Int, delta: Int): Int = {
    val day = new DateTime(toISODate(date))
    day.plusDays(delta).toString("yyyyMMdd").toInt
  }


  /**
    * 返回具体日期,如(2018-03-08,-1)-> 2018-03-07,(2018-03-08,0)-> 2018-03-08,(2018-03-08,1)-> 2018-03-09,
    *
    * @param date  ISO日期格式,yyyy-MM-dd
    * @param delta 间隔的天数
    * @return YYYYMMDD
    */
  def getDeltaDay(date: String, delta: Int): String = {
    val day = new DateTime(date)
    day.plusDays(delta).toString("yyyy-MM-dd")
  }

  /**
    * 返回具体日期,如(20180308,-1)-> 20180307,(20180308,0)-> 20180308,(20180308,1)-> 20180309,
    *
    * @param delta 返回与今天间隔的天数
    * @return YYYYMMDD
    */
  def getDeltaDay(delta: Int): Int = {
    val day = new DateTime()
    day.plusDays(delta).toString("yyyyMMdd").toInt
  }


  /**
    * 从开始日期和结合日期获取日期列表,如(2018-04-10, 2018-04-13) -> (2018-04-10,2018-04-11,2018-04-12,2018-04-13)
    *
    * @param startDay 开始日期,ISO日期格式,yyyy-MM-dd
    * @param endDay   结束日期,ISO日期格式,yyyy-MM-dd
    * @return 日期列表(字符串类型)
    */
  def getRangeDays(startDay: String, endDay: String): Array[String] = {
    val startTime = new DateTime(startDay)
    val endTime = new DateTime(endDay)
    val numberOfDays = Days.daysBetween(startTime, endTime).getDays
    val step = if(numberOfDays + 1 > 0) 1 else -1
    (0 to numberOfDays by step).map(startTime.plusDays(_).toString("yyyy-MM-dd")).toArray
  }

  /**
    * 从开始日期和结束日期获取日期列表,如(20180410, 20180413) -> (20180410,20180411,20180412,20180413)
    *
    * @param startDay 开始日期,YYYYMMDD
    * @param endDay   结束日期,YYYYMMDD
    * @return 日期列表(整数类型)
    */
  def getRangeDays(startDay: Int, endDay: Int): Array[Int] = {
    val startTime = new DateTime(toISODate(startDay))
    val numberOfDays = getDelta(startDay, endDay)
    val step = if(numberOfDays + 1 > 0) 1 else -1
    (0 to numberOfDays by step).map(startTime.plusDays(_).toString("yyyyMMdd").toInt).toArray
  }


  /**
    * 以开始日期与相邻天数确定日期列表,如(2018-04-11, 3) -> (2018-04-11,2018-04-12,2018-04-13,2018-04-14)
    *                              (2018-04-11, -3)-> (2018-04-11,2018-04-10,2018-04-09,2018-04-08)
    * @param startDay 开始日期,ISO日期格式,yyyy-MM-dd
    * @param delta 相邻天数,支持负数
    * @return 日期列表
    */
  def getDeltaRangeDays(startDay:String, delta:Int):Array[String] = {
    val endDay = new DateTime(startDay).plusDays(delta).toString("yyyy-MM-dd")
    getRangeDays(startDay, endDay)
  }


  /**
    * 以开始日期与相邻天数确定日期列表,如(20180411, 3) -> (20180411,20180412,20180413,20180414
    *                              (20180411, -3)-> (20180411,20180410,20180409,20180408)
    * @param startDay 开始日期,YYYYMMDD
    * @param delta 相邻天数,支持负数
    * @return 日期列表
    */
  def getDeltaRangeDays(startDay:Int, delta:Int):Array[Int] = {
    val endDay = new DateTime(toISODate(startDay)).plusDays(delta).toString("yyyyMMdd").toInt
    getRangeDays(startDay, endDay)
  }

  /**
    * 获取制定月份的所有日期
    *
    * @param month 支持 YYYYMM 或 YYYYMMDD
    * @return [20180201,20180202,...,201802028] 从小到大排序
    */
  def getDaysOfMonth(month: Int): Array[Int] = {
    val start = if (month < 1000000) month * 100 + 1 else month / 100 * 100 + 1
    val startDay = new DateTime(toISODate(start))
    val endDay = startDay.plusMonths(1).minusDays(1)
    getRangeDays(startDay.toString("yyyyMMdd").toInt, endDay.toString("yyyyMMdd").toInt)
  }

  /**
    * 从开始日期和结束日期获取月份列表,eg. (20180410, 20180613) -> (201804,201805,201806)
    *
    * @param start YYYYMMDD
    * @param end   YYYYMMDD
    * @return [201712,201801,201802]
    */
  def getRangeMonths(start: Int, end: Int): Array[Int] = {
    val startDay = new DateTime(toISODate(start))
    val endDay = new DateTime(toISODate(end))
    val monthList = new ArrayBuffer[String]
    var index = 0
    var monthStr = startDay.plusMonths(index).toString("yyyyMM")
    val endMonth = endDay.toString("yyyyMM")
    while (monthStr <= endMonth) {
      index += 1
      monthList.append(monthStr)
      monthStr = startDay.plusMonths(index).toString("yyyyMM")
    }
    monthList.map(_.toInt).toArray
  }


  /**
    * 从开始日期和结束日期获取月份列表,eg. (2018-04-10, 2018-06-13) -> (201804,201805,201806)
    *
    * @param start ISO日期格式,yyyy-MM-dd
    * @param end   ISO日期格式,yyyy-MM-dd
    * @return [201712,201801,201802]
    */
  def getRangeMonths(start: String, end: String): Array[String] = {
    val startDay = new DateTime(start)
    val endDay = new DateTime(end)
    val monthList = new ArrayBuffer[String]
    var index = 0
    var monthStr = startDay.plusMonths(index).toString("yyyyMM")
    val endMonth = endDay.toString("yyyyMM")
    while (monthStr <= endMonth) {
      index += 1
      monthList.append(monthStr)
      monthStr = startDay.plusMonths(index).toString("yyyyMM")
    }
    monthList.toArray
  }


  /**
    * 从开始日期和结束日期获取周中和周末的分组
    *
    * @param start YYYYMMDD
    * @param end   YYYYMMDD
    * @return
    */
  def getWeekGroup(start: Int, end: Int): (Array[Int], Array[Int]) = {
    val weekDays = new ArrayBuffer[Int]()
    val weekEnds = new ArrayBuffer[Int]()
    getRangeDays(start, end).foreach(x => {
      val day = new DateTime(toISODate(x))
      if (day.dayOfWeek.get() < 6) weekDays.append(x)
      else weekEnds.append(x)
    })
    (weekDays.toSet.toArray, weekEnds.toSet.toArray)
  }


  /**
    * 查看两个日期相差多少天 - 支持负数,
    * eg(20170101,20170131,"day") -> 30,(20170101,20170131,"month") -> 0,(20170101,20170131,"year")->0
    *
    * @param startDay 开始日期 YYYYMMDD
    * @param endDay   结束日期 YYYYMMDD
    * @return 间隔天数
    */
  def getDelta(startDay: Int, endDay: Int): Int = {
    val startTime = new DateTime(toISODate(startDay))
    val endTime = new DateTime(toISODate(endDay))
    Days.daysBetween(startTime, endTime).getDays
  }


  /**
    * 查看两个日期相差多少天 - 支持负数,
    * eg(2017-01-01,2017-01-31) -> 30
    *
    * @param startDay 开始日期 ISO日期格式,yyyy-MM-dd
    * @param endDay   结束日期 ISO日期格式,yyyy-MM-dd
    * @return 间隔天数
    */
  def getDelta(startDay: String, endDay: String): Int = {
    val startTime = new DateTime(toISODate(startDay))
    val endTime = new DateTime(toISODate(endDay))
    Days.daysBetween(startTime, endTime).getDays
  }


}

参考网站
1 Joda-Time
2 根据日期计算星期几
3 C语言根据日期判断星期几(使用基姆拉尔森计算公式)

猜你喜欢

转载自blog.csdn.net/whgyxy/article/details/86554624