迭代日期范围(scala 方式)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30166507/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Iterate over dates range (the scala way)
提问by Gismo Ranas
Given a start and an end date I would like to iterate on it by day using a foreach, map or similar function. Something like
给定开始日期和结束日期,我想使用 foreach、map 或类似函数按天对其进行迭代。就像是
(DateTime.now to DateTime.now + 5.day by 1.day).foreach(println)
I am using https://github.com/nscala-time/nscala-time, but I get returned a joda Interval object if I use the syntax above, which I suspect is also not a range of dates, but a sort of range of milliseconds.
我正在使用https://github.com/nscala-time/nscala-time,但是如果我使用上面的语法,我会返回一个 joda Interval 对象,我怀疑它也不是日期范围,而是一种范围毫秒。
EDIT: The question is obsolete. As advised on the jodahomepage, if you are using java 8 you should start with or migrate to java.time.
编辑:这个问题已经过时了。正如joda主页上所建议的,如果您使用的是 java 8,您应该从java.time开始或迁移到java.time。
回答by Shyamendra Solanki
You may use plusDays:
您可以使用plusDays:
val now = DateTime.now
(0 until 5).map(now.plusDays(_)).foreach(println)
Given start and end dates:
给定开始和结束日期:
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)
回答by hayden.sikh
For just iterating by day, I do:
为了每天迭代,我这样做:
Iterator.iterate(start) { _ + 1.day }.takeWhile(_.isBefore(end))
This has proven to be useful enough that I have a small helper object to provide an implicit and allow for a type transformation:
这已被证明足够有用,我有一个小的辅助对象来提供隐式并允许类型转换:
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
回答by trudolf
This answer fixes the issue of mrsrinivas answer, that .get(ChronoUnits.DAYS)returns only the days part of the duration, and not the total number of days.
此答案解决了 mrsrinivas 答案的问题,即.get(ChronoUnits.DAYS)仅返回持续时间的天数部分,而不是总天数。
Necessary import and initialization
必要的导入和初始化
import java.time.temporal.ChronoUnit
import java.time.{LocalDate, Period}
Note how above answer would lead to wrong result (total number of days is 117)
请注意以上答案如何导致错误结果(总天数为 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)
回答by mrsrinivas
Solution with java.time API using Scala
使用 Scala 的 java.time API 解决方案
Necessary import and initialization
必要的导入和初始化
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 List of LocalDatefor sample duration
创建LocalDate样本持续时间的列表
(0 to daysTill)
.map(days => now.plusDays(days))
.foreach(println)
Iterate over specific dates between start and end using toEpochDayor getLong(ChronoField.EPOCH_DAY)
使用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)
回答by igreenfield
you can use something like that:
你可以使用类似的东西:
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)))
}
回答by Luc Vaillant
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
}
回答by Xavier Guihot
In this case, the Scala wayis the Java way:
在这种情况下,Scala way是Java way:
When running Scalaon Java 9+, we can use java.time.LocalDate::datesUntil:
在运行Scala时Java 9+,我们可以使用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 to be included:
如果要包括最后日期:
start.datesUntil(end.plusDays(1)).iterator.asScala
// 2019-01-29, 2019-01-30, 2019-01-31, 2019-02-01, 2019-02-02

