web-dev-qa-db-ja.com

日付範囲を反復処理します(scala way)

開始日と終了日を考慮して、foreach、map、または同様の関数を使用して、日ごとに繰り返したいと思います。何かのようなもの

(DateTime.now to DateTime.now + 5.day by 1.day).foreach(println)

https://github.com/nscala-time/nscala-time を使用していますが、上記の構文を使用するとjoda Intervalオブジェクトが返されます。日付ですが、一種のミリ秒の範囲です。

編集:質問は時代遅れです。 joda ホームページでアドバイスされているように、Java 8を使用している場合は、 Java.time から始めるか移行する必要があります。

11
Gismo Ranas

plusDaysを使用できます:

val now = DateTime.now
(0 until 5).map(now.plusDays(_)).foreach(println)

指定された開始日と終了日:

import org.joda.time.Days

val start = DateTime.now.minusDays(5)
val end   = DateTime.now.plusDays(5)    

val daysCount = Days.daysBetween(start, end).getDays()
(0 until daysCount).map(start.plusDays(_)).foreach(println)
25

日ごとに繰り返すために、私はします:

Iterator.iterate(start) { _ + 1.day }.takeWhile(_.isBefore(end))

これは、暗黙的な機能を提供し、型変換を可能にする小さなヘルパーオブジェクトを用意するのに十分役立つことが証明されています。

object IntervalIterators {
  implicit class ImplicitIterator(val interval: Interval) extends AnyVal {
    def iterateBy(step: Period): Iterator[DateTime] = Iterator.iterate(interval.start) { _ + step }
        .takeWhile(_.isBefore(interval.end))

    def iterateBy[A](step: Period, transform: DateTime => A): Iterator[A] = iterateBy(step).map(transform)

    def iterateByDay: Iterator[LocalDate] = iterateBy(1.day, { _.toLocalDate })

    def iterateByHour: Iterator[DateTime] = iterateBy(1.hour)
  }
}

使用例:

import IntervalIterators._

(DateTime.now to 5.day.from(DateTime.now)).iterateByDay // Iterator[LocalDate]

(30.minutes.ago to 1.hour.from(DateTime.now)).iterateBy(1.second)  // Iterator[DateTime], broken down by second
21
hayden.sikh

Scalaを使用したJava.time APIのソリューション

必要なインポートと初期化

_import Java.time.temporal.ChronoUnit
import Java.time.temporal.ChronoField.Epoch_DAY
import Java.time.{LocalDate, Period}

val now = LocalDate.now
val daysTill = 5
_

サンプル期間のLocalDateのリストを作成

_(0 to daysTill)
  .map(days => now.plusDays(days))
  .foreach(println)
_

toEpochDayまたはgetLong(ChronoField.Epoch_DAY)を使用して、開始と終了の間の特定の日付を反復します

_//Extract the duration
val endDay = now.plusDays(daysTill)
val startDay = now

val duration = endDay.getLong(Epoch_DAY) - startDay.getLong(Epoch_DAY)

/* This code does not give desired results as trudolf pointed
val duration = Period
  .between(now, now.plusDays(daysTill))
  .get(ChronoUnit.DAYS)
*/

//Create list for the duration
(0 to duration)
  .map(days => now.plusDays(days))
  .foreach(println)
_
2
mrsrinivas

この回答は、mrsrinivas回答の問題を修正します。.get(ChronoUnits.DAYS)は、期間の日部分のみを返し、合計日数は返しません。

必要なインポートと初期化

import Java.time.temporal.ChronoUnit
import Java.time.{LocalDate, Period}

上記の答えが間違った結果につながる方法に注意してください(合計日数は117です)

scala> Period.between(start, end)
res6: Java.time.Period = P3M26D

scala> Period.between(start, end).get(ChronoUnit.DAYS)
res7: Long = 26

開始と終了の間の特定の日付を反復します

val start = LocalDate.of(2018, 1, 5)
val end   = LocalDate.of(2018, 5, 1)

// Create List of `LocalDate` for the period between start and end date

val dates: IndexedSeq[LocalDate] = (0L to (end.toEpochDay - start.toEpochDay))
  .map(days => start.plusDays(days))

dates.foreach(println)
2
trudolf

あなたはそのようなものを使うことができます:

 object Test extends App {
   private val startDate: DateTime = DateTime.now()
   private val endDate: DateTime = DateTime.now().plusDays(5)
   private val interval: Interval = new Interval(startDate, endDate)
   Stream.from(0,1)
         .takeWhile(index => interval.contains(startDate.plusDays(index)))
         .foreach(index => println(startDate.plusDays(index)))
 }
1
igreenfield

この場合、Scala wayJava wayです。

Java 9+Scalaを実行する場合、 Java.time.LocalDate::datesUntil を使用できます。

import Java.time.LocalDate
import collection.JavaConverters._

// val start = LocalDate.of(2019, 1, 29)
// val end   = LocalDate.of(2018, 2,  2)
start.datesUntil(end).iterator.asScala
// Iterator[Java.time.LocalDate] = <iterator> (2019-01-29, 2019-01-30, 2019-01-31, 2019-02-01)

最後の日付を含める場合:

start.datesUntil(end.plusDays(1)).iterator.asScala
// 2019-01-29, 2019-01-30, 2019-01-31, 2019-02-01, 2019-02-02
0
Xavier Guihot
import Java.util.{Calendar, Date}
import scala.annotation.tailrec

/** Gets date list between two dates
  *
  * @param startDate  Start date
  * @param endDate    End date
  * @return           List of dates from startDate to endDate
  */
def getDateRange(startDate: Date, endDate: Date): List[Date] = {
  @tailrec
  def addDate(acc: List[Date], startDate: Date, endDate: Date): List[Date] = {
    if (startDate.after(endDate)) acc
    else addDate(endDate :: acc, startDate, addDays(endDate, -1))
  }

  addDate(List(), startDate, endDate)
}

/** Adds a date offset to the given date
  *
  * @param date       ==> Date
  * @param amount     ==> Offset (can be negative)
  * @return           ==> New date
  */
def addDays(date: Date, amount: Int): Date = {
  val cal = Calendar.getInstance()
  cal.setTime(date)
  cal.add(Calendar.DATE, amount)
  cal.getTime
}
0
Luc Vaillant