如何在java.time.LocalDate上进行隐式Ordered

时间:2016-06-27 16:46:32

标签: scala implicit java-time localdate

我想使用隐含java.time.LocalDate的{​​{1}}和java.time.LocalDateTime

Ordered

val date1 = java.time.LocalDate.of(2000, 1, 1) val date2 = java.time.LocalDate.of(2010, 10, 10) if (date1 < date2) ... 不起作用,因为import scala.math.Ordering.Implicits._继承自LocalDate而不是Comparable<ChronoLocalDate>。 我怎样才能编写自己的非显式Orderd来使用&lt;,&lt; =,&gt;,&gt; =运算符/方法来比较Comparable<LocalDate>的?

编辑:

我找到了一种使用隐式类的方法:

LocalDate

但我更喜欢像Scala那样为所有实现import java.time.{LocalDate} object MyDateTimeUtils { implicit class MyLocalDateImprovements(val ld: LocalDate) extends Ordered[LocalDate] { def compare(that: LocalDate): Int = ld.compareTo(that) } } // Test import MyDateTimeUtils._ val d1 = LocalDate.of(2016, 1, 1) val d2 = LocalDate.of(2017, 2, 3) if (d1 < d2) println("d1 is less than d2") 的Java类做的事情。你只需要 代码中的Comparable<T>。 Scala实现它:

import scala.math.Ordering.Implicits._

但遗憾的是implicit def ordered[A <% Comparable[A]]: Ordering[A] = new Ordering[A] { def compare(x: A, y: A): Int = x compareTo y } 实施了LocalDate而不是Comparable<ChronoLocalDate>。我找不到修改上述隐式有序方法以适合Comparable<LocalDate> / LocalDate的方法。有什么想法吗?

5 个答案:

答案 0 :(得分:16)

您可以使用Ordering.by为任何类型创建排序,从该类型的函数到已经有订单的函数 - 在本例中为Long

implicit val localDateOrdering: Ordering[LocalDate] = Ordering.by(_.toEpochDay)

答案 1 :(得分:10)

比较LocalDate.toEpochDay很明显,但可能相对较慢......

answer by @tzach-zohar很棒,因为它最明显的是什么;你是在大纪元日订购的:

implicit val localDateOrdering: Ordering[LocalDate] = Ordering.by(_.toEpochDay)

但是,如果您查看implementation of toEpochDay,您会看到它相对复杂 - 18行代码,4个分区,3个条件和isLeapYear()调用 - 并且结果值不是没有缓存,因此每次比较都会重新计算,如果要对大量LocalDate进行排序,这可能会很昂贵。

...使用LocalDate.compareTo可能更具性能......

implementation of LocalDate.compareTo更简单 - 只有2个条件,没有除法 - 这就是scala.math.Ordering.Implicits._所提供的java.lang.Comparable to scala.math.Ordering的隐式转换所带来的,只要它有效!但正如你所说,它没有,因为LocalDate继承自Comparable<ChronoLocalDate>而不是Comparable<LocalDate>。利用它的一种方法可能是......

import scala.math.Ordering.Implicits._

implicit val localDateOrdering: Ordering[LocalDate] =
  Ordering.by(identity[ChronoLocalDate])

...这可让您通过将LocalDate投放到ChronoLocalDate来订购Ordering[ChronoLocalDate],并使用scala.math.Ordering.Implicits._为您提供的new Ordering

...最后,SAM类型

的lambda语法看起来最好

Scala 2.12引入的lambda syntax for SAM types可以简化构建implicit val localDateOrdering: Ordering[LocalDate] = _ compareTo _ 的工作:

parquet-tools merge

......我认为这最终成为我个人的最爱!简洁,仍然相当清楚,并使用(我认为)表现最佳的比较方法。

答案 2 :(得分:3)

以下是我使用的解决方案:

定义两个含义。第一个使Ordering[LocalDate]可用。第二个是给LocalDate compare方法,它非常方便。我通常把它们放在一个库中的包对象中,我可以把它包含在我需要的地方。

package object net.fosdal.oslo.odatetime {

  implicit val orderingLocalDate: Ordering[LocalDate] = Ordering.by(d => (d.getYear, d.getDayOfYear))

  implicit class LocalDateOps(private val localDate: LocalDate) extends AnyVal with Ordered[LocalDate] {
    override def compare(that: LocalDate): Int = Ordering[LocalDate].compare(localDate, that)
  }
}

如果定义了这两个,您现在可以执行以下操作:

import net.fosdal.oslo.odatetime._

val bool: Boolean = localDate1 < localDate1

val localDates: Seq[LocalDate] = ...
val sortedSeq = localDates.sorted

或者......你可以直接使用我的库(v0.4.3)。见:https://github.com/sfosdal/oslo

答案 3 :(得分:1)

这是我对java.time.LocalDateTime的解决方案

implicit val localDateTimeOrdering: Ordering[LocalDateTime] =
  Ordering.by(x => x.atZone(ZoneId.of("UTC")).toEpochSecond)

答案 4 :(得分:0)

对隐式ordered进行略微修改应该可以解决问题。

type AsComparable[A] = A => Comparable[_ >: A]

implicit def ordered[A: AsComparable]: Ordering[A] = new Ordering[A] {
  def compare(x: A, y: A): Int = x compareTo y
}

现在,每种类型都可以与自身或超类型相媲美,但应该有Ordering