Создание dateRange Scala, Joda, Java

Я потратил часы, пытаясь сделать этот следующий фрагмент кода.

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 месяцев.

Любые вопросы приветствуются. Я думал, что это будет общий кусок кода, но об этом не так много.

Спасибо заранее.

Ответ 1

Работа вокруг заключается в определении таких дат:

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 и компиляторе различно.

Ответ 2

DateTime не имеет конструктор, содержащий три аргумента int, поэтому new DateTime(2012, 06, 30) вызывает конструктор DateTime(Object) с кортежем (2012, 06, 30) в качестве аргумента. В документации указано:

Создает экземпляр из Object, который представляет дату и время.

Если объект подразумевает хронологию (например, GregorianCalendar), то эта хронология будет использоваться. В противном случае используется ISO по умолчанию. Таким образом, если a GregorianCalendar передается, используемая хронология будет GJ, но если дата передана в хронологии, будет ISO.

Определенные типы объектов определены в ConverterManager и включают ReadableInstant, String, Calendar и Date. Форматы String описываются ISODateTimeFormat.dateTimeParser().

Неудивительно, что ConverterManager не знает, что делать с кортежем Scala, что приводит к исключению.

Если кто-то может дать мне другое решение, это тоже будет здорово. Я хочу список дат с 2000 по 2012 год, каждые 6 месяцев.

Если вам действительно нужны даты, лучший тип для использования - LocalDate (у которого есть, кстати, конструктор, который вы хотите), Если вы хотите DateTime в начале этих дат, вам нужно подумать о том, какой часовой пояс использовать.

Ответ 3

Хорошо, вот полный рабочий код.

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 и другие за помощь

Ответ 4

Мне нужно было что-то подобное. Вот что я придумал:

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