Date range iteration (scala path)

Given the start and end date, I would like to repeat it daily, using foreach, map, or a similar function. Sort of

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

I use https://github.com/nscala-time/nscala-time , but I get the joda Interval object returned if I use the syntax above, which I suspect is also not a date range, but a kind of millisecond range.

EDIT: The question is out of date. As indicated on the joda homepage , if you are using java 8, you should start with java.time or go to it .

+7
source share
7 answers

You can use plusDays :

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

Start and end date data:

 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) 
+21
source

For a simple repetition during the day, I do:

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

This turned out to be useful enough that I have a small helper object to provide implicit and allow type conversion:

 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) } } 

Sample Usage:

 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 
+15
source

Solution using java.time API using Scala

Import and initialization required

 import java.time.temporal.ChronoUnit import java.time.temporal.ChronoField.EPOCH_DAY import java.time.{LocalDate, Period} val now = LocalDate.now val daysTill = 5 

Create a LocalDate list for sample duration

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

toEpochDay getLong(ChronoField.EPOCH_DAY) on specific dates between start and end using toEpochDay or 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
source

This answer fixes the problem of the .get(ChronoUnits.DAYS) response .get(ChronoUnits.DAYS) returns only a fraction of the days in duration, not the total number of days.

Import and initialization required

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

Please note that the above answer may lead to an incorrect result (total number of days is 117)

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

Iterate over specific dates between start and end

 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
source

you can use something like this:

  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
source
 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
source

In this case, the Scala way is the Java way :

When running Scala on Java 9+ we can use 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) 

And if the last date is included:

 start.datesUntil(end.plusDays(1)).iterator.asScala // 2019-01-29, 2019-01-30, 2019-01-31, 2019-02-01, 2019-02-02 
0
source

All Articles