如何生成两周相同/不同年份的所有周数?

时间:2017-12-25 12:29:20

标签: scala

在我的应用程序中,一周表示为格式为String的字符串:

{year}-{week-no} // week-no ranges from 1 to 52

例如: 2017年第7周表示为:2017-07

我想写一个方法,它需要两个星期的日期,并在这两个星期之间产生所有周。所以,如果我通过:

  • 2017-052017-08 (相同年份):该方法应返回List(2017-05,2017-06,2017-07,2017-08)
  • 2017-052019-02 (不同年份):该方法应返回List(2017-05,2017-06,.........2017-51,2017-52,2018-01,2018-02,.......2018-51,2018-52,2019-01,2019-02)

到目前为止,我已经开发了以下解决方案:

def weeksGenerator(fromWeek: String,toWeek: String): List[String] = {
    val upperWeekNummber = fromWeek.split("-").toList.last.toInt
    val upperYearNummber = fromWeek.split("-").toList.head.toInt
    val lowerWeekNummber = toWeek.split("-").toList.last.toInt
    val lowerYearNummber = toWeek.split("-").toList.head.toInt

    (lowerYearNummber - upperYearNummber) match {
      case 0L => Range.inclusive(upperWeekNummber,lowerWeekNummber).map{weekNum =>
        s"${upperYearNummber.toString}-${weekNum}"
      }.toList
      case diff: Int =>
        Range.inclusive(0,diff).foreach(println)
        Range.inclusive(0,diff).flatMap{
        d => if(d==diff){
          // this is the last element
          Range.inclusive(1,lowerWeekNummber).map{weekNum =>
            s"${(upperYearNummber+d).toString}-${weekNum}"
          }
        }
        else if(d ==0) {
          // first element
          Range.inclusive(upperWeekNummber,52).map{weekNum =>
            s"${(upperYearNummber+d).toString}-${weekNum}"
          }
        }
        else {
          Range.inclusive(1,52).map{weekNum =>
            s"${(upperYearNummber+d).toString}-${weekNum}"
          }
        }
      }.toList
    }
  }

我认为我的解决方案存在两个问题:

  • 我认为这不是最concise and functional解决方案。
  • 当周数来自1 to 9时,我想生成2017-012017-02而不是2017-12017-2。我不想手动追加0.我正在寻找更好的方法。

那么,这里最好的方法是什么?

3 个答案:

答案 0 :(得分:2)

我可能会做以下事情:

def weeksGenerator(fromWeek: String,toWeek: String): List[String] = {
  val maxWeeks = 52
  val minWeeks = 1

  val year1 = fromWeek.split("-")(0).toInt
  val year2 = toWeek.split("-")(0).toInt
  val week1 = fromWeek.split("-")(1).toInt
  val week2 = toWeek.split("-")(1).toInt

  val wholeWeeks = minWeeks to maxWeeks
  val years = year1 to year2
  val headWeeks = week1 to maxWeeks
  val lastWeeks = minWeeks to week2

  val enumeratedYears = years.zip(1 to years.length)
  val yearsAndWeeksZip = enumeratedYears.map{case (year, index) => if (index == 1) (year, headWeeks) else if (index == years.length) (year, lastWeeks) else (year, wholeWeeks)}
  val yearsAndWeeks = yearsAndWeeksZip.flatMap{case (year, weeks) => weeks.map(week => year.toString + "-" + "%02d".format(week))}

  yearsAndWeeks.toList
}

您可以使用format同样正确显示数字:

scala> "%02d".format(4)
res15: String = 04

scala> "%02d".format(50)
res16: String = 50

在REPL上:

scala> weeksGenerator("2017-10", "2018-01")
res3: List[String] = List(2017-10, 2017-11, 2017-12, 2017-13, 2017-14, 2017-15, 2017-16, 2017-17, 2017-18, 2017-19, 2017-20, 2017-21, 2017-22, 2017-23, 2017-24, 2017-25, 2017-26, 2017-27, 2017-28, 2017-29, 2017-30, 2017-31, 2017-32, 2017-33, 2017-34, 2017-35, 2017-36, 2017-37, 2017-38, 2017-39, 2017-40, 2017-41, 2017-42, 2017-43, 2017-44, 2017-45, 2017-46, 2017-47, 2017-48, 2017-49, 2017-50, 2017-51, 2017-52, 2018-01)

我认为这个解决方案描述了一种使用高阶函数来解决这个问题的简洁明了的方法。它可以缩短,但我想它会失去清晰度。

答案 1 :(得分:2)

我认为最好的方法是依赖java.time api

代码看起来像这样(我不包括输入的解析):

import java.time.DayOfWeek
import java.time.LocalDate
import java.time.temporal.IsoFields
import java.time.temporal.ChronoUnit
import java.time.format.DateTimeFormatter
import java.time.temporal.TemporalAdjusters

val initialDate = LocalDate.ofYearDay(2017, 50).`with`(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 50).`with`(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
val finalDate = LocalDate.ofYearDay(2017, 50).`with`(IsoFields.WEEK_OF_WEEK_BASED_YEAR, 8).`with`(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))

for {
  i <- 0 to ChronoUnit.WEEKS.between(initialDate, finalDate).toInt
} yield initialDate.plusWeeks(i).format(DateTimeFormatter.ofPattern("YYYY-ww"))

这里有demo

答案 2 :(得分:2)

您可以利用java time API为您完成艰苦的工作(处理闰周等)。只需将您的输入解析为LocalDate,然后使用Chrono API获取介于两者之间的周数。

import java.time.LocalDate
import java.time.temporal.ChronoUnit
import java.time.format.DateTimeFormatter

def listOfWeeks(initialWeekString: String, finalWeekString: String): List[String] = {
  val dateTimeFormatter = DateTimeFormatter.ofPattern("YYYY-ww-EEE")
  val dateTimeFormatter2 = DateTimeFormatter.ofPattern("YYYY-ww")

  val initialDate = LocalDate.parse(initialWeekString + "-Mon", dateTimeFormatter)
  val finalDate = LocalDate.parse(finalWeekString + "-Mon", dateTimeFormatter)

  val weeksCount = ChronoUnit.WEEKS.between(initialDate, finalDate).toInt

  (0 to weeksCount)
    .map(i => initialDate.plusWeeks(i).format(dateTimeFormatter2))
    .toList
}

println(listOfWeeks("2017-05", "2017-06"))

// List(2017-05, 2017-06)