Home > Blockchain >  Kotlin Koans Comparison Exercise. Why does this solution not work?
Kotlin Koans Comparison Exercise. Why does this solution not work?

Time:11-19

Just setting off on trying to learn some Kotlin I've read the official solution and understand it but this is what I came up with on my own first.

Question:

Learn about operator overloading and how the different conventions for operations like ==, <,   work in Kotlin. Add the function compareTo to the class MyDate to make it comparable. After this, the code below date1 < date2 should start to compile.

Note that when you override a member in Kotlin, the override modifier is mandatory.

My Answer:

import java.time.Duration
import java.time.LocalDate

data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) : Comparable<MyDate> {
    override fun compareTo(other: MyDate): Int {
        val dateA = LocalDate.of(this.year, this.month, this.dayOfMonth)
        val dateB = LocalDate.of(other.year, other.month, other.dayOfMonth)
        return Duration.between(dateA, dateB).toDays().toInt()
    }
}

fun test(date1: MyDate, date2: MyDate) {
    // this code should compile:
    println(date1 < date2)
} 

I went at this thinking I would work out the difference between the two in days and just return it. but the error I get is "Unsupported unit: Seconds" What does this mean in this context. I believe I'm returning the correct type from compareTo as an int. What am I missing here?

This is the official solution for reference

data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) : Comparable<MyDate> {
    override fun compareTo(other: MyDate) = when {
        year != other.year -> year - other.year
        month != other.month -> month - other.month
        else -> dayOfMonth - other.dayOfMonth
    }
}

fun test(date1: MyDate, date2: MyDate) {
    // this code should compile:
    println(date1 < date2)
}

Different approach but I would expect the tests to pass both ways

CodePudding user response:

Duration is time based, and works with Temporals that supports seconds. From between:

The specified temporal objects must support the SECONDS unit. For full accuracy, either the NANOS unit or the NANO_OF_SECOND field should be supported.

LocalDate does not support seconds. You should instead use Period.between, or ChronoUnit.DAYS.between.

Another mistake is that you are comparing the dates in the reverse order of the official solution. ChronoUnit.DAYS.between(dateA, dateB).toInt() would give a positive number if dateA (this) is before dateB (the parameter). If you look at the official solution, compareTo returns a positive number if this is after the parameter.

Therefore, you should do:

override fun compareTo(other: MyDate): Int {
    val dateA = LocalDate.of(this.year, this.month, this.dayOfMonth)
    val dateB = LocalDate.of(other.year, other.month, other.dayOfMonth)
    // note the switched order
    return ChronoUnit.DAYS.between(dateB, dateA).toInt()
}
  • Related