我想使用java.time.LocalDate
和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>
而不是Comparable<LocalDate>
。我怎样才能编写自己的Imred使用,> =运算符/方法来比较LocalDate
的?
编辑:
我找到了一种使用隐式类的方法:
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")
但我更喜欢像Scala那样为所有实现Comparable<T>
的Java类做的事情。你只需要在你的代码中使用import scala.math.Ordering.Implicits._
。 Scala实现它像:
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
/ Comparable<ChronoLocalDate>
的方法。任何的想法?
您可以使用Ordering.by
为任何类型创建排序,给定从该类型到已经具有排序的函数的函数 - 在本例中为Long
:
implicit val localDateOrdering: Ordering[LocalDate] = Ordering.by(_.toEpochDay)
LocalDate.toEpochDay
is clear, though maybe relatively slow...answer by @tzach-zohar很棒,因为它最明显的是什么;你在大纪元日订购:
implicit val localDateOrdering: Ordering[LocalDate] = Ordering.by(_.toEpochDay)
但是,如果你看一下implementation of toEpochDay
,你会发现它相对复杂 - 18行代码,4个分区,3个条件和isLeapYear()
调用 - 结果值没有缓存,所以每次比较都会重新计算,如果要对大量的LocalDate
s进行分类,这可能会很昂贵。
LocalDate.compareTo
is probably more performant...implementation of LocalDate.compareTo
更简单 - 只有2个条件,没有分区 - 这就是java.lang.Comparable
to scala.math.Ordering
提供的scala.math.Ordering.Implicits._
的隐式转换所带来的,只要它有效!但正如你所说,它没有,因为LocalDate
继承自Comparable<ChronoLocalDate>
而不是Comparable<LocalDate>
。利用它的一种方法可能是......
import scala.math.Ordering.Implicits._
implicit val localDateOrdering: Ordering[LocalDate] =
Ordering.by(identity[ChronoLocalDate])
...这可以让你通过将它们投射到LocalDate
s来订购ChronoLocalDate
s,并使用Ordering[ChronoLocalDate]
给你的scala.math.Ordering.Implicits._
!
与Scala 2.12一起引入的lambda syntax for SAM types可以完成构建new Ordering
的非常简短的工作:
implicit val localDateOrdering: Ordering[LocalDate] = _ compareTo _
......我认为这最终成为我个人的最爱!简洁,仍然相当清楚,并使用(我认为)最佳表现的比较方法。
这是我使用的解决方案:
定义两个含义。第一个使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
这是我对java.time.LocalDateTime
的解决方案
implicit val localDateTimeOrdering: Ordering[LocalDateTime] =
Ordering.by(x => x.atZone(ZoneId.of("UTC")).toEpochSecond)
对隐含的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
。