11

我花了几个小时试图使下一段代码工作。

import org.joda.time.{DateTime, Period}


def dateRange(from: DateTime, to: DateTime, step: Period): Iterator[DateTime]      =Iterator.iterate(from)(_.plus(step)).takeWhile(!_.isAfter(to))

val range = {
dateRange(new DateTime(2012, 06, 30).minusYears(5), new DateTime(2000, 06, 30),new Period.months(6))
}

我正在尝试设置一个从 2000 年到 2012 年以 6 个月为增量的日期范围数组。我面临的问题是以下错误。

Exception in thread "main" java.lang.IllegalArgumentException: No instant converter found for type: scala.Tuple3
at    org.joda.time.convert.ConverterManager.getInstantConverter(ConverterManager.java:165)
at org.joda.time.base.BaseDateTime.<init>(BaseDateTime.java:169)
at org.joda.time.DateTime.<init>(DateTime.java:241)
at tester.MomentumAlgo$class.$init$(MomentumAlgo.scala:154)
at tester.RunMomentumAlgo$$anon$1.<init>(RunMomentumAlgo.scala:86)
at tester.RunMomentumAlgo$.main(RunMomentumAlgo.scala:86)
at tester.RunMomentumAlgo.main(RunMomentumAlgo.scala)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

我似乎与最后一个 Period.months() 部分有关,但是我不知道如何解决它。我不知道的 Tuple3 错误。

如果有人可以给我一个不同的解决方案,那也很棒。我想要一个从 2000 年到 2012 年的日期列表,每 6 个月一次。

欢迎任何问题。我认为这将是一段常见的代码,但网上并没有太多关于它的内容。

提前致谢。

4

6 回答 6

13

一种解决方法是定义这样的日期:

val date = new DateTime().withYear(2013).withMonthOfYear(7).withDayOfMonth(16)

REPL 中的整个序列就变成了这样:

scala> import org.joda.time.{DateTime, Period}
import org.joda.time.{DateTime, Period}

scala> def dateRange(from: DateTime, to: DateTime, step: Period): Iterator[DateTime]      =Iterator.iterate(from)(_.plus(step)).takeWhile(!_.isAfter(to))
dateRange: (from: org.joda.time.DateTime, to: org.joda.time.DateTime, step: org.joda.time.Period)Iterator[org.joda.time.DateTime]

scala> val from = new DateTime().withYear(2012).withMonthOfYear(6).withDayOfMonth(30).minusYears(5)
from: org.joda.time.DateTime = 2007-06-30T21:46:05.536-07:00

scala> val to = new DateTime().withYear(2000).withMonthOfYear(6).withDayOfMonth(30)
to: org.joda.time.DateTime = 2000-06-30T21:46:26.186-07:00

scala> val range = dateRange(from, to, new Period().withMonths(6))
range: Iterator[org.joda.time.DateTime] = non-empty iterator

scala> range.toList
res4: List[org.joda.time.DateTime] = List(
2000-06-30T21:46:26.186-07:00,
2000-12-30T21:46:26.186-08:00,
2001-06-30T21:46:26.186-07:00,
2001-12-30T21:46:26.186-08:00,
2002-06-30T21:46:26.186-07:00,
2002-12-30T21:46:26.186-08:00,
2003-06-30T21:46:26.186-07:00,
2003-12-30T21:46:26.186-08:00,
2004-06-30T21:46:26.186-07:00,
2004-12-30T21:46:26.186-08:00,
2005-06-30T21:46:26.186-07:00,
2005-12-30T21:46:26.186-08:00,
2006-06-30T21:46:26.186-07:00,
2006-12-30T21:46:26.186-08:00)

此外,正如我的评论中所述,我无法重现这一点。似乎 REPL 和编译器中的行为不同。

于 2013-07-17T04:50:29.537 回答
6

我需要类似的东西。这是我想出的:

import org.joda.time.{Period, DateTime}

class DateRange(val start: DateTime, val end: DateTime, val step: Period, inclusive: Boolean) extends Iterable[DateTime] {
    override def iterator: Iterator[DateTime] = new DateRangeIterator

    class DateRangeIterator extends Iterator[DateTime] {
        var current = start

        override def hasNext: Boolean = current.isBefore(end) || (inclusive && current == end)

        override def next(): DateTime = {
            val returnVal = current
            current = current.withPeriodAdded(step, 1)
            returnVal
        }
    }
}

示例用法:

val startOfDay: DateTime = new DateTime().withTimeAtStartOfDay()
val endOfDay: DateTime = startOfDay.plusDays(1)
val dateRange = new DateRange(startOfDay, endOfDay, Period.hours(1), false)
for (d <- dateRange) println(d)

输出:

2015-03-16T00:00:00.000-05:00
2015-03-16T01:00:00.000-05:00
2015-03-16T02:00:00.000-05:00
2015-03-16T03:00:00.000-05:00
2015-03-16T04:00:00.000-05:00
2015-03-16T05:00:00.000-05:00
2015-03-16T06:00:00.000-05:00
2015-03-16T07:00:00.000-05:00
2015-03-16T08:00:00.000-05:00
2015-03-16T09:00:00.000-05:00
2015-03-16T10:00:00.000-05:00
2015-03-16T11:00:00.000-05:00
2015-03-16T12:00:00.000-05:00
2015-03-16T13:00:00.000-05:00
2015-03-16T14:00:00.000-05:00
2015-03-16T15:00:00.000-05:00
2015-03-16T16:00:00.000-05:00
2015-03-16T17:00:00.000-05:00
2015-03-16T18:00:00.000-05:00
2015-03-16T19:00:00.000-05:00
2015-03-16T20:00:00.000-05:00
2015-03-16T21:00:00.000-05:00
2015-03-16T22:00:00.000-05:00
2015-03-16T23:00:00.000-05:00
于 2015-03-16T15:47:54.393 回答
5

DateTime 没有带三个int参数的构造函数,因此以元组作为参数new DateTime(2012, 06, 30)调用DateTime(Object)构造函数。(2012, 06, 30)文档说:

Object从一个表示日期时间的实例构造一个实例。

如果该对象暗示了一个年表(例如GregorianCalendar确实),那么将使用该年表。否则,使用 ISO 默认值。因此,如果GregorianCalendar传入 a,则使用的年表将是 GJ,但如果传入日期,则年表将是 ISO。

识别的对象类型在 中定义,ConverterManager包括ReadableInstant、和。格式由描述。StringCalendarDateStringISODateTimeFormat.dateTimeParser()

不出所料,ConverterManager不知道如何处理 Scala 元组,这会导致异常。

如果有人可以给我一个不同的解决方案,那也很棒。我想要一个从 2000 年到 2012 年的日期列表,每 6 个月一次。

如果你真的想要日期,最好使用的类型是LocalDate(顺便说一下,它确实有你想要的构造函数)。如果你想DateTime在这些日期的开始,那么你需要考虑使用哪个时区。

于 2013-07-17T06:13:48.080 回答
5

好的,这是完整的工作代码。

import org.joda.time.{Period, DateTime}

object runme {

  def main(args:Array[String]) {

  def dateRange(from: DateTime, to: DateTime, step: Period): Iterator[DateTime]
  =Iterator.iterate(from)(_.plus(step)).takeWhile(!_.isAfter(to))

  val range = { dateRange(new DateTime(2000, 06, 30,0,0,0,0).minusYears(5) ,new DateTime(2013, 06, 30,0,0,0,0),new Period(0,6,0,0,0,0,0,0))}

  range.foreach(u => { 
    print(u.getYear)
    print(u.getMonthOfYear)
    println(u.getDayOfMonth)
  })

 }
}

我认为我的主要问题是函数后没有足够的数字DateTime()(即毫秒等),这意味着编译器没有收到它想要的所有参数。正如阿列克谢·罗曼诺夫所说

然后打印所需范围的日期,并可用作迭代器。

希望对其他人有所帮助。

感谢@Brian 和其他人的帮助

于 2013-07-17T23:07:48.790 回答
1

我只是偶然发现了这个问题并想出了这个简单的解决方案。

def generateDateRange(from: LocalDate, to: LocalDate): List[Date] = {
    if(from.compareTo(to) > 0) Nil
    from :: generateDateRange(from.plusDays(1), to)
}

我们通过将范围的开始附加到一天后开始的新范围来递归地构建日期列表。

于 2020-05-28T20:40:02.267 回答
1

我对 hucko 的代码做了一些小改动

private def generateDateRange(from: LocalDate, to: LocalDate): List[LocalDate] = {
    if (from.compareTo(to) > 0) Nil
    else from :: generateDateRange(from.plusDays(1), to)
}
于 2021-02-19T15:15:29.980 回答