I would recommend using Iterator.iterate
to produce a lazy sequence of dates:
import java.time.LocalDate
def days(start: LocalDate, step: Int): Iterator[LocalDate] =
Iterator.iterate(start)(_.plusDays(step))
You can have this iterator go forward with step > 0
or backwards with step < 0
(or stand still with step == 0
, but you're unlikely to want that).
In your case you can have step = -1
to move backward one day at a time for each item in the iterator and then .take(30)
items and mkString
out of them:
val startingDate = LocalDate.parse("2020-08-20")
val output = days(start = startingDate, step = -1).take(30).mkString(",")
// output is 2020-08-20,2020-08-19,2020-08-18,2020-08-17,...
You can play around with this code here on Scastie.
Note that Iterator
s are mutable, which means that they can't be safely shared across your code. For a purely functional alternative you can use a LazyList
, as shown in this Scastie snippet.
Now, the problem with this approach is that you may inadvertently cause an infinite loop: if you don't .take(30)
the call to mkString
will never terminate. If you prefer to have a strict collection, you can use the range
method, which is defined, among others, on List
s, by first producing a range of integers and then adding each item in the range to your starting date, as in the following alternative example:
import java.time.LocalDate
def days(start: LocalDate, end: Long): List[LocalDate] =
List.range(0, end, step = if (end < 0) -1 else 1).map(start.plusDays)
val startingDate = LocalDate.parse("2020-08-20")
val output = days(start = startingDate, end = -30).mkString(",")
// output is the same as in the previous example
Here you can find the documentation for List.range
(you'll easily understand why I passed step
as I did reading the documentation and maybe playing a bit around with this snippet on Scastie).
Note that you can use the same approach (the range
method) with Iterator
s and other lazy sequences as well.
A few resources on lazy vs. strict and mutable vs. immutable collections: