diff --git a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Periode.kt b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Periode.kt index 3b03e541..f05c5140 100644 --- a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Periode.kt +++ b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Periode.kt @@ -13,6 +13,8 @@ data class Periode( fun tilTidslinjePeriodeMedDato() = TidslinjePeriodeMedDato(verdi, fom, tom) } +fun Periode.tilTidslinje(): Tidslinje = listOf(this).tilTidslinje() + fun List>.tilTidslinje(): Tidslinje = this .map { it.tilTidslinjePeriodeMedDato() } @@ -24,6 +26,14 @@ fun List>.filtrerIkkeNull(): List> = fun List>.verdier(): List = this.map { it.verdi } +fun Periode.omfatter(tidspunkt: LocalDate) = + when { + fom == null && tom == null -> true + fom == null -> tom!!.isSameOrAfter(tidspunkt) + tom == null -> fom.isSameOrBefore(tidspunkt) + else -> fom.isSameOrBefore(tidspunkt) && tom.isSameOrAfter(tidspunkt) + } + data class IkkeNullbarPeriode( val verdi: T, val fom: LocalDate, diff --git a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Tidslinje.kt b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Tidslinje.kt index 8a096747..7e00e0e7 100644 --- a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Tidslinje.kt +++ b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Tidslinje.kt @@ -1,7 +1,6 @@ package no.nav.familie.tidslinje import no.nav.familie.tidslinje.utvidelser.klipp -import no.nav.familie.tidslinje.utvidelser.kombinerMed import no.nav.familie.tidslinje.utvidelser.map import no.nav.familie.tidslinje.utvidelser.mapper import no.nav.familie.tidslinje.utvidelser.tilPerioder @@ -48,7 +47,7 @@ open class Tidslinje( } } - fun erTom() = innhold.sumOf { it.lengde } == 0 + fun erTom() = innhold.sumOf { it.lengde } == 0L /** * Kalkulerer slutttidspunkt som en LocalDate. @@ -56,8 +55,8 @@ open class Tidslinje( * Om tidslinja er uendelig, kastes det et unntak */ fun kalkulerSluttTidspunkt(): LocalDate { - val antallTidsEnheter: Int = this.innhold.sumOf { it.lengde } - val sluttTidspunkt = this.startsTidspunkt.plus(antallTidsEnheter.toLong() - 1, mapper[this.tidsEnhet]) + val antallTidsEnheter = this.innhold.sumOf { it.lengde } + val sluttTidspunkt = this.startsTidspunkt.plus(antallTidsEnheter - 1, mapper[this.tidsEnhet]) return when (this.tidsEnhet) { TidsEnhet.ÅR -> sluttTidspunkt.with(TemporalAdjusters.lastDayOfYear()) @@ -67,6 +66,16 @@ open class Tidslinje( } } + fun kopier(): Tidslinje = + Tidslinje( + startsTidspunkt = startsTidspunkt, + perioder = innhold, + tidsEnhet = tidsEnhet, + ).also { + it.tittel = tittel + it.foreldre.addAll(foreldre) + } + private fun kalkulerSluttTidspunkt(sluttDato: LocalDate): LocalDate = when (this.tidsEnhet) { TidsEnhet.ÅR -> sluttDato.with(TemporalAdjusters.lastDayOfYear()) @@ -143,59 +152,12 @@ fun tomTidslinje( tidsEnhet: TidsEnhet = TidsEnhet.DAG, ): Tidslinje = Tidslinje(startsTidspunkt = startsTidspunkt ?: PRAKTISK_TIDLIGSTE_DAG, emptyList(), tidsEnhet) -fun Map>.leftJoin( - høyreTidslinjer: Map>, - kombinator: (V?, H?) -> R?, -): Map> { - val venstreTidslinjer = this - val venstreNøkler = venstreTidslinjer.keys - - return venstreNøkler.associateWith { nøkkel -> - val venstreTidslinje = venstreTidslinjer.getOrDefault(nøkkel, tomTidslinje()) - val høyreTidslinje = høyreTidslinjer.getOrDefault(nøkkel, tomTidslinje()) - - venstreTidslinje.kombinerMed(høyreTidslinje, kombinator) - } -} - -fun Map>.outerJoin( - høyreTidslinjer: Map>, - kombinator: (V?, H?) -> R?, -): Map> { - val venstreTidslinjer = this - val alleNøkler = venstreTidslinjer.keys + høyreTidslinjer.keys - - return alleNøkler.associateWith { nøkkel -> - val venstreTidslinje = venstreTidslinjer.getOrDefault(nøkkel, tomTidslinje()) - val høyreTidslinje = høyreTidslinjer.getOrDefault(nøkkel, tomTidslinje()) - - venstreTidslinje.kombinerMed(høyreTidslinje, kombinator) - } -} - -fun Map>.outerJoin( - tidslinjer2: Map>, - tidslinjer3: Map>, - kombinator: (A?, B?, C?) -> R?, -): Map> { - val tidslinjer1 = this - val alleNøkler = tidslinjer1.keys + tidslinjer2.keys + tidslinjer3.keys - - return alleNøkler.associateWith { nøkkel -> - val tidslinje1 = tidslinjer1.getOrDefault(nøkkel, tomTidslinje()) - val tidslinje2 = tidslinjer2.getOrDefault(nøkkel, tomTidslinje()) - val tidslinje3 = tidslinjer3.getOrDefault(nøkkel, tomTidslinje()) - - tidslinje1.kombinerMed(tidslinje2, tidslinje3, kombinator) - } -} - fun Tidslinje.beskjærEtter(tidslinje: Tidslinje<*>): Tidslinje = this.klipp(tidslinje.startsTidspunkt, tidslinje.kalkulerSluttTidspunkt()) fun Tidslinje.inneholder(verdi: T): Boolean = this.tilPerioder().any { it.verdi == verdi } -fun Tidslinje.mapVerdi(mapper: (T?) -> R): Tidslinje = +fun Tidslinje.mapVerdi(mapper: (T?) -> R?): Tidslinje = this.map { periodeVerdi -> when (periodeVerdi) { is Verdi, diff --git a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/TidslinjePeriode.kt b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/TidslinjePeriode.kt index 50b150fe..6d516d53 100644 --- a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/TidslinjePeriode.kt +++ b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/TidslinjePeriode.kt @@ -1,6 +1,6 @@ package no.nav.familie.tidslinje -const val INF = 1_000_000_000 +const val INF = 1_000_000_000L sealed class PeriodeVerdi( protected val _verdi: T?, @@ -45,7 +45,7 @@ class Null : PeriodeVerdi(null) { */ data class TidslinjePeriode( val periodeVerdi: PeriodeVerdi, - var lengde: Int, + var lengde: Long, var erUendelig: Boolean = false, ) { init { @@ -60,7 +60,7 @@ data class TidslinjePeriode( } } - constructor(periodeVerdi: T?, lengde: Int, erUendelig: Boolean = false) : this( + constructor(periodeVerdi: T?, lengde: Long, erUendelig: Boolean = false) : this( if (periodeVerdi == null) { Null() } else { diff --git a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Utils.kt b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Utils.kt index 8a81ca4b..84cc240a 100644 --- a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Utils.kt +++ b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/Utils.kt @@ -6,9 +6,12 @@ import java.time.LocalDate val PRAKTISK_TIDLIGSTE_DAG = LocalDate.of(0, 1, 1) val PRAKTISK_SENESTE_DAG = LocalDate.MAX.minusYears(1) -fun LocalDate.diffIDager(annen: LocalDate): Int = +fun LocalDate.diffIDager(annen: LocalDate): Long = Duration // legger på én dag på sluttdatoen siden den er exlusive .between(this.atStartOfDay(), annen.plusDays(1).atStartOfDay()) .toDaysPart() - .toInt() + +fun LocalDate.isSameOrBefore(toCompare: LocalDate): Boolean = this.isBefore(toCompare) || this == toCompare + +fun LocalDate.isSameOrAfter(toCompare: LocalDate): Boolean = this.isAfter(toCompare) || this == toCompare diff --git a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/BiFunksjon.kt b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/BiFunksjon.kt new file mode 100644 index 00000000..bfb8b27c --- /dev/null +++ b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/BiFunksjon.kt @@ -0,0 +1,267 @@ +package no.nav.familie.tidslinje.utvidelser + +import no.nav.familie.tidslinje.INF +import no.nav.familie.tidslinje.PeriodeVerdi +import no.nav.familie.tidslinje.Tidslinje +import no.nav.familie.tidslinje.TidslinjePeriode +import no.nav.familie.tidslinje.Udefinert +import java.time.LocalDate + +/** + * Beregner en ny tidslinje ved bruk av [kombineringsfunksjon] basert på tidslinjene this og [annen]. + * Går gjennom alle periodene i hver tidslinje og beregner nye perioder. + * Hver nye periode som blir lagt inn i den resulterende tidslinja starter der den forrige stoppet og + * har lengde lik det minste tidsrommet hvor input tidslinjene har konstant verdi. + * Påfølgende perioder med lik verdi, blir slått sammen til en periode i den resulterende tidslinja. + * [kombineringsfunksjon] blir brukt for å beregne verdiene til de generete periodene basert på verdiene til input tidslinjene i + * de respektive tidsrommene. Om en av input-tidslinjene er uendleig(dvs at den siste perioden har uendelig varighet), vil + * også den resulterende tidslinja være uendelig. + * [PeriodeVerdi] er en wrapper-classe som blir brukt for å håndtere no.nav.familie.tidslinje.Udefinert og no.nav.familie.tidslinje.Null. [kombineringsfunksjon] + * må ta høyde for at input kan være av en av disse typene, og definere hvordan disse situasjonene håndteres. + * MERK: operator skal returnere enten Udefindert, no.nav.familie.tidslinje.Null eller no.nav.familie.tidslinje.PeriodeVerdi. + */ +fun Tidslinje.biFunksjon( + annen: Tidslinje, + kombineringsfunksjon: (elem1: PeriodeVerdi, elem2: PeriodeVerdi) -> PeriodeVerdi, +): Tidslinje { + val tidslinjePerioder: MutableList> = mutableListOf() + var kopi1 = this + var kopi2 = annen + + if (this.tidsEnhet != annen.tidsEnhet) { + kopi1 = this.konverterTilDag() + kopi2 = annen.konverterTilDag() + } + + val (kopi3, kopi4) = konverterTilSammeLengde(kopi1, kopi2) + + val it1: Iterator> = kopi3.innhold.iterator() + val it2: Iterator> = kopi4.innhold.iterator() + + var tidslinjePeriode1: TidslinjePeriode? = null + var tidslinjePeriode2: TidslinjePeriode? = null + + var lengde1 = 0L + var lengde2 = 0L + + while (it1.hasNext() || it2.hasNext()) { + tidslinjePeriode1 = tidslinjePeriode1.takeIf { lengde1 > 0 } ?: it1.next() + tidslinjePeriode2 = tidslinjePeriode2.takeIf { lengde2 > 0 } ?: it2.next() + + lengde1 = lengde1.takeIf { it > 0 } ?: tidslinjePeriode1.lengde + lengde2 = lengde2.takeIf { it > 0 } ?: tidslinjePeriode2.lengde + + if (tidslinjePeriode1.erUendelig && tidslinjePeriode2.erUendelig) { + tidslinjePerioder.add( + tidslinjePeriode1.biFunksjon( + operand = tidslinjePeriode2, + lengde = INF, + erUendelig = true, + operator = kombineringsfunksjon, + ), + ) + break + } + + val minLengde = minOf(lengde1, lengde2) + tidslinjePerioder.add( + tidslinjePeriode1.biFunksjon( + operand = tidslinjePeriode2, + lengde = minLengde, + erUendelig = false, + operator = kombineringsfunksjon, + ), + ) + + lengde1 -= minLengde + lengde2 -= minLengde + } + + val resultatTidslinje = Tidslinje(kopi3.startsTidspunkt, tidslinjePerioder, kopi3.tidsEnhet) + + @Suppress("UNCHECKED_CAST") + resultatTidslinje.foreldre.add(kopi3 as Tidslinje) + @Suppress("UNCHECKED_CAST") + resultatTidslinje.foreldre.add(kopi4 as Tidslinje) + + return resultatTidslinje.medTittel(this.tittel) +} + +fun Tidslinje.biFunksjon( + tidslinje2: Tidslinje, + tidslinje3: Tidslinje, + kombineringsfunksjon: (PeriodeVerdi, PeriodeVerdi, PeriodeVerdi) -> PeriodeVerdi, +): Tidslinje { + val tidslinjePerioder: MutableList> = mutableListOf() + var kopi1 = this + var kopi2 = tidslinje2 + var kopi3 = tidslinje3 + + val erUlikTidsEnhet = this.tidsEnhet != tidslinje2.tidsEnhet || this.tidsEnhet != tidslinje3.tidsEnhet + + if (erUlikTidsEnhet) { + kopi1 = this.konverterTilDag() + kopi2 = tidslinje2.konverterTilDag() + kopi3 = tidslinje3.konverterTilDag() + } + + val (kopi4, kopi5, kopi6) = konverterTilSammeLengde(kopi1, kopi2, kopi3) + + val it1: Iterator> = kopi4.innhold.iterator() + val it2: Iterator> = kopi5.innhold.iterator() + val it3: Iterator> = kopi6.innhold.iterator() + + var tidslinjePeriode1: TidslinjePeriode? = null + var tidslinjePeriode2: TidslinjePeriode? = null + var tidslinjePeriode3: TidslinjePeriode? = null + + var lengde1 = 0L + var lengde2 = 0L + var lengde3 = 0L + + while (it1.hasNext() || it2.hasNext() || it3.hasNext()) { + tidslinjePeriode1 = tidslinjePeriode1.takeIf { lengde1 > 0 } ?: it1.next() + tidslinjePeriode2 = tidslinjePeriode2.takeIf { lengde2 > 0 } ?: it2.next() + tidslinjePeriode3 = tidslinjePeriode3.takeIf { lengde3 > 0 } ?: it3.next() + + lengde1 = lengde1.takeIf { it > 0 } ?: tidslinjePeriode1.lengde + lengde2 = lengde2.takeIf { it > 0 } ?: tidslinjePeriode2.lengde + lengde3 = lengde3.takeIf { it > 0 } ?: tidslinjePeriode3.lengde + + if (tidslinjePeriode1.erUendelig && tidslinjePeriode2.erUendelig && tidslinjePeriode3.erUendelig) { + tidslinjePerioder.add( + tidslinjePeriode1.biFunksjon( + operand1 = tidslinjePeriode2, + operand2 = tidslinjePeriode3, + lengde = INF, + erUendelig = true, + operator = kombineringsfunksjon, + ), + ) + break + } + + val minLengde = minOf(lengde1, lengde2, lengde3) + tidslinjePerioder.add( + tidslinjePeriode1.biFunksjon( + operand1 = tidslinjePeriode2, + operand2 = tidslinjePeriode3, + lengde = minLengde, + erUendelig = false, + operator = kombineringsfunksjon, + ), + ) + + lengde1 -= minLengde + lengde2 -= minLengde + lengde3 -= minLengde + } + + val resultatTidslinje = Tidslinje(kopi4.startsTidspunkt, tidslinjePerioder, kopi4.tidsEnhet) + + @Suppress("UNCHECKED_CAST") + resultatTidslinje.foreldre.add(kopi4 as Tidslinje) + @Suppress("UNCHECKED_CAST") + resultatTidslinje.foreldre.add(kopi5 as Tidslinje) + @Suppress("UNCHECKED_CAST") + resultatTidslinje.foreldre.add(kopi6 as Tidslinje) + + return resultatTidslinje.medTittel(this.tittel) +} + +fun Tidslinje.biFunksjonSnitt( + operand: Tidslinje, + operator: (elem1: PeriodeVerdi, elem2: PeriodeVerdi) -> PeriodeVerdi, +): Tidslinje { + val startsTidspunkt = + if (this.startsTidspunkt < operand.startsTidspunkt) operand.startsTidspunkt else this.startsTidspunkt + + val sluttTidspunkt1 = this.kalkulerSluttTidspunkt() + val sluttTidspunkt2 = operand.kalkulerSluttTidspunkt() + + val sluttTidspunkt = if (sluttTidspunkt1 < sluttTidspunkt2) sluttTidspunkt1 else sluttTidspunkt2 + + return this + .biFunksjon(operand, operator) + .klipp(startsTidspunkt, sluttTidspunkt) +} + +/** + * Konverterer to input-tidslinjer til å bli av samme lengde. Dette gjør den ved å legge til en "padding" bestående av en periode + * med lengde lik differansen mellom de to tidspunktene og verdi gitt av [nullVerdi] til tidslinjen. + * Antar tidslinjene er av samme tidsenhet!! + */ +private fun konverterTilSammeLengde( + tidslinje1: Tidslinje, + tidslinje2: Tidslinje, +): Pair, Tidslinje> { + val kopi1 = tidslinje1.kopier() + val kopi2 = tidslinje2.kopier() + + val tidligsteStartTidspunkt = listOf(kopi1, kopi2).minOf { it.startsTidspunkt } + val senesteSluttTidspunkt = listOf(kopi1, kopi2).maxOf { it.kalkulerSluttTidspunkt() } + val erUendelig = listOf(kopi1, kopi2).any { it.innhold.isNotEmpty() && it.innhold.last().erUendelig } + + settStarttidspunkt(kopi1, tidligsteStartTidspunkt) + settStarttidspunkt(kopi2, tidligsteStartTidspunkt) + + settSlutttidspunkt(kopi1, senesteSluttTidspunkt, erUendelig) + settSlutttidspunkt(kopi2, senesteSluttTidspunkt, erUendelig) + + return Pair(kopi1, kopi2) +} + +private fun konverterTilSammeLengde( + tidslinje1: Tidslinje, + tidslinje2: Tidslinje, + tidslinje3: Tidslinje, +): Triple, Tidslinje, Tidslinje> { + val kopi1 = tidslinje1.kopier() + val kopi2 = tidslinje2.kopier() + val kopi3 = tidslinje3.kopier() + + val tidligsteStartTidspunkt = listOf(kopi1, kopi2, kopi3).minOf { it.startsTidspunkt } + val senesteSluttTidspunkt = listOf(kopi1, kopi2, kopi3).maxOf { it.kalkulerSluttTidspunkt() } + val erUendelig = listOf(kopi1, kopi2, kopi3).any { it.innhold.isNotEmpty() && it.innhold.last().erUendelig } + + settStarttidspunkt(kopi1, tidligsteStartTidspunkt) + settStarttidspunkt(kopi2, tidligsteStartTidspunkt) + settStarttidspunkt(kopi3, tidligsteStartTidspunkt) + + settSlutttidspunkt(kopi1, senesteSluttTidspunkt, erUendelig) + settSlutttidspunkt(kopi2, senesteSluttTidspunkt, erUendelig) + settSlutttidspunkt(kopi3, senesteSluttTidspunkt, erUendelig) + + return Triple(kopi1, kopi2, kopi3) +} + +private fun settSlutttidspunkt( + tidslinje: Tidslinje, + senesteSluttTidspunkt: LocalDate, + erUendelig: Boolean, +) { + val sluttTidspunkt = tidslinje.kalkulerSluttTidspunkt() + if (sluttTidspunkt < senesteSluttTidspunkt) { + val lengde = + if (erUendelig) { + INF + } else { + sluttTidspunkt + .until(senesteSluttTidspunkt.plusDays(1), mapper[tidslinje.tidsEnhet]) + } + tidslinje.innhold += listOf(TidslinjePeriode(Udefinert(), lengde, erUendelig)) + } +} + +private fun settStarttidspunkt( + tidslinje: Tidslinje, + tidligsteStartTidspunkt: LocalDate, +) { + if (tidslinje.startsTidspunkt > tidligsteStartTidspunkt) { + val diffFraTidligsteStartTidspunkt = + tidligsteStartTidspunkt.until(tidslinje.startsTidspunkt, mapper[tidslinje.tidsEnhet]) + tidslinje.innhold = + listOf(TidslinjePeriode(Udefinert(), diffFraTidligsteStartTidspunkt, false)) + tidslinje.innhold + tidslinje.startsTidspunkt = tidligsteStartTidspunkt + } +} diff --git a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/JoinTidslinjer.kt b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/JoinTidslinjer.kt new file mode 100644 index 00000000..99e61e32 --- /dev/null +++ b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/JoinTidslinjer.kt @@ -0,0 +1,85 @@ +package no.nav.familie.tidslinje.utvidelser + +import no.nav.familie.tidslinje.PeriodeVerdi +import no.nav.familie.tidslinje.Tidslinje +import no.nav.familie.tidslinje.tomTidslinje + +fun Map>.join( + høyreTidslinjer: Map>, + kombinator: (V?, H?) -> R?, +): Map> { + val venstreTidslinjer = this + val alleNøkler = venstreTidslinjer.keys.intersect(høyreTidslinjer.keys) + + return alleNøkler.associateWith { nøkkel -> + val venstreTidslinje = venstreTidslinjer.getOrDefault(nøkkel, tomTidslinje()) + val høyreTidslinje = høyreTidslinjer.getOrDefault(nøkkel, tomTidslinje()) + + venstreTidslinje.kombinerMed(høyreTidslinje, kombinator) + } +} + +fun Map>.leftJoin( + høyreTidslinjer: Map>, + kombinator: (V?, H?) -> R?, +): Map> { + val venstreTidslinjer = this + val venstreNøkler = venstreTidslinjer.keys + + return venstreNøkler.associateWith { nøkkel -> + val venstreTidslinje = venstreTidslinjer.getOrDefault(nøkkel, tomTidslinje()) + val høyreTidslinje = høyreTidslinjer.getOrDefault(nøkkel, tomTidslinje()) + + venstreTidslinje.kombinerMed(høyreTidslinje, kombinator) + } +} + +fun Map>.outerJoin( + høyreTidslinjer: Map>, + kombinator: (V?, H?) -> R?, +): Map> { + val venstreTidslinjer = this + val alleNøkler = venstreTidslinjer.keys + høyreTidslinjer.keys + + return alleNøkler.associateWith { nøkkel -> + val venstreTidslinje = venstreTidslinjer.getOrDefault(nøkkel, tomTidslinje()) + val høyreTidslinje = høyreTidslinjer.getOrDefault(nøkkel, tomTidslinje()) + + venstreTidslinje.kombinerMed(høyreTidslinje, kombinator) + } +} + +fun Map>.outerJoin( + tidslinjer2: Map>, + tidslinjer3: Map>, + kombinator: (A?, B?, C?) -> R?, +): Map> { + val tidslinjer1 = this + val alleNøkler = tidslinjer1.keys + tidslinjer2.keys + tidslinjer3.keys + + return alleNøkler.associateWith { nøkkel -> + val tidslinje1 = tidslinjer1.getOrDefault(nøkkel, tomTidslinje()) + val tidslinje2 = tidslinjer2.getOrDefault(nøkkel, tomTidslinje()) + val tidslinje3 = tidslinjer3.getOrDefault(nøkkel, tomTidslinje()) + + tidslinje1.kombinerMed(tidslinje2, tidslinje3, kombinator) + } +} + +fun List>.join( + operand: Tidslinje, + operator: (elem1: PeriodeVerdi, elem2: PeriodeVerdi) -> PeriodeVerdi, +): List> = this.mapIndexed { _, tidslinjeBarn -> tidslinjeBarn.biFunksjon(operand, kombineringsfunksjon = operator) } + +fun List>.join( + operand: List>, + operator: (elem1: PeriodeVerdi, elem2: PeriodeVerdi) -> PeriodeVerdi, +): List> { + if (this.size != operand.size) throw IllegalArgumentException("Listene må ha lik lengde") + return this.mapIndexed { index, tidslinjeBarn -> + tidslinjeBarn.biFunksjon( + operand[index], + kombineringsfunksjon = operator, + ) + } +} diff --git a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/KombinerTidslinjer.kt b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/KombinerTidslinjer.kt index ad375cc5..4a7cc3db 100644 --- a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/KombinerTidslinjer.kt +++ b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/KombinerTidslinjer.kt @@ -5,6 +5,7 @@ import no.nav.familie.tidslinje.PRAKTISK_TIDLIGSTE_DAG import no.nav.familie.tidslinje.Tidslinje import no.nav.familie.tidslinje.Udefinert import no.nav.familie.tidslinje.Verdi +import no.nav.familie.tidslinje.tilPeriodeVerdi import no.nav.familie.tidslinje.tomTidslinje fun Collection>.slåSammen(): Tidslinje> { @@ -35,7 +36,7 @@ fun Collection>.slåSammen(): Tidslinje> { } } -fun Collection>.kombiner(listeKombinator: (Iterable) -> R): Tidslinje = +fun Collection>.kombiner(listeKombinator: (Iterable) -> R?): Tidslinje = this.slåSammen().map { when (it) { is Verdi -> { @@ -47,3 +48,22 @@ fun Collection>.kombiner(listeKombinator: (Iterable) -> R is Udefinert -> Udefinert() } } + +fun Tidslinje.kombinerMed( + annen: Tidslinje, + kombineringsfunksjon: (elem1: T?, elem2: R?) -> RESULTAT?, +): Tidslinje = + this.biFunksjon(annen) { periodeverdiVenstre, periodeverdiHøyre -> + kombineringsfunksjon(periodeverdiVenstre.verdi, periodeverdiHøyre.verdi) + .tilPeriodeVerdi() + } + +fun Tidslinje.kombinerMed( + tidslinje2: Tidslinje, + tidslinje3: Tidslinje, + kombineringsfunksjon: (elem1: T?, elem2: R?, elem3: S?) -> RESULTAT?, +): Tidslinje = + this.biFunksjon(tidslinje2, tidslinje3) { periodeVerdi1, periodeVerdi2, periodeVerdi3 -> + kombineringsfunksjon(periodeVerdi1.verdi, periodeVerdi2.verdi, periodeVerdi3.verdi) + .tilPeriodeVerdi() + } diff --git a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/PeriodeUtvidelser.kt b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/PeriodeUtvidelser.kt index 500121a5..a91ba6ff 100644 --- a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/PeriodeUtvidelser.kt +++ b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/PeriodeUtvidelser.kt @@ -11,11 +11,20 @@ import no.nav.familie.tidslinje.TidslinjePeriode */ fun TidslinjePeriode.biFunksjon( operand: TidslinjePeriode, - lengde: Int, + lengde: Long, erUendelig: Boolean, operator: (elem1: PeriodeVerdi, elem2: PeriodeVerdi) -> PeriodeVerdi, ): TidslinjePeriode = TidslinjePeriode(operator(this.periodeVerdi, operand.periodeVerdi), lengde, erUendelig) +fun TidslinjePeriode.biFunksjon( + operand1: TidslinjePeriode, + operand2: TidslinjePeriode, + lengde: Long, + erUendelig: Boolean, + operator: (PeriodeVerdi, PeriodeVerdi, PeriodeVerdi) -> PeriodeVerdi, +): TidslinjePeriode = + TidslinjePeriode(operator(this.periodeVerdi, operand1.periodeVerdi, operand2.periodeVerdi), lengde, erUendelig) + fun List>.slåSammenLike(): List> = this.fold(emptyList()) { acc, tidslinjePeriode -> val sisteElementIAcc = acc.lastOrNull() diff --git a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/TidslinjeUtvidelser.kt b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/TidslinjeUtvidelser.kt index d84221ea..81600077 100644 --- a/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/TidslinjeUtvidelser.kt +++ b/tidslinje/src/main/kotlin/no/nav/familie/tidslinje/utvidelser/TidslinjeUtvidelser.kt @@ -11,10 +11,9 @@ import no.nav.familie.tidslinje.TidslinjePeriode import no.nav.familie.tidslinje.TidslinjePeriodeMedDato import no.nav.familie.tidslinje.Udefinert import no.nav.familie.tidslinje.filtrerIkkeNull -import no.nav.familie.tidslinje.tilPeriodeVerdi +import no.nav.familie.tidslinje.omfatter import java.time.LocalDate import java.time.temporal.ChronoUnit -import kotlin.math.absoluteValue val TIDENES_ENDE = LocalDate.MAX @@ -26,145 +25,35 @@ val mapper = TidsEnhet.DAG to ChronoUnit.DAYS, ) -fun List>.join( - operand: Tidslinje, - operator: (elem1: PeriodeVerdi, elem2: PeriodeVerdi) -> PeriodeVerdi, -): List> = this.mapIndexed { _, tidslinjeBarn -> tidslinjeBarn.biFunksjon(operand, kombineringsfunksjon = operator) } - -fun List>.join( - operand: List>, - operator: (elem1: PeriodeVerdi, elem2: PeriodeVerdi) -> PeriodeVerdi, -): List> { - if (this.size != operand.size) throw IllegalArgumentException("Listene må ha lik lengde") - return this.mapIndexed { index, tidslinjeBarn -> - tidslinjeBarn.biFunksjon( - operand[index], - kombineringsfunksjon = operator, - ) - } -} - fun Tidslinje.medTittel(tittel: String): Tidslinje { this.tittel = tittel return this } -/** - * Konverterer to input-tidslinjer til å bli av samme lengde. Dette gjør den ved å legge til en "padding" bestående av en periode - * med lengde lik differansen mellom de to tidspunktene og verdi gitt av [nullVerdi] til tidslinjen. - * Antar tidslinjene er av samme tidsenhet!! - */ -private fun konverterTilSammeLengde( - tidslinje1: Tidslinje, - tidslinje2: Tidslinje, -): Pair, Tidslinje> { - val kopi1 = Tidslinje(tidslinje1.startsTidspunkt, tidslinje1.innhold, tidsEnhet = tidslinje1.tidsEnhet) - val kopi2 = Tidslinje(tidslinje2.startsTidspunkt, tidslinje2.innhold, tidsEnhet = tidslinje2.tidsEnhet) - - kopi1.tittel = tidslinje1.tittel - kopi2.tittel = tidslinje2.tittel - - kopi1.foreldre.addAll(tidslinje1.foreldre) - kopi2.foreldre.addAll(tidslinje2.foreldre) - - val udefinert1 = Udefinert() - val udefinert2 = Udefinert() - - var tidsenhetForskjell = - kopi1.startsTidspunkt - .until(kopi2.startsTidspunkt, mapper[kopi1.tidsEnhet]) - .toInt() - .absoluteValue - - if (kopi1.startsTidspunkt > kopi2.startsTidspunkt) { - kopi1.innhold = listOf(TidslinjePeriode(udefinert1, tidsenhetForskjell, false)) + kopi1.innhold - kopi1.startsTidspunkt = kopi2.startsTidspunkt - } else if (kopi2.startsTidspunkt > kopi1.startsTidspunkt) { - kopi2.innhold = listOf(TidslinjePeriode(udefinert2, tidsenhetForskjell, false)) + kopi2.innhold - kopi2.startsTidspunkt = kopi1.startsTidspunkt - } - - if (kopi1.kalkulerSluttTidspunkt() != kopi2.kalkulerSluttTidspunkt()) { - if (kopi1.innhold.isNotEmpty() && kopi1.innhold.last().erUendelig) { - kopi2.innhold = kopi2.innhold + - listOf( - TidslinjePeriode( - periodeVerdi = udefinert2, - lengde = INF, - erUendelig = true, - ), - ) - return Pair(kopi1, kopi2) - } else if (kopi2.innhold.isNotEmpty() && kopi2.innhold.last().erUendelig) { - kopi1.innhold = - kopi1.innhold + listOf(TidslinjePeriode(periodeVerdi = udefinert1, lengde = INF, erUendelig = true)) - return Pair(kopi1, kopi2) - } - - if (kopi1.kalkulerSluttTidspunkt() < kopi2.kalkulerSluttTidspunkt()) { - tidsenhetForskjell = - kopi1 - .kalkulerSluttTidspunkt() - .until( - kopi2.kalkulerSluttTidspunkt().plusDays(1), - mapper[kopi1.tidsEnhet], - ).toInt() - .absoluteValue - kopi1.innhold = kopi1.innhold + listOf(TidslinjePeriode(udefinert1, tidsenhetForskjell, false)) - } else if (kopi2.kalkulerSluttTidspunkt() < kopi1.kalkulerSluttTidspunkt()) { - tidsenhetForskjell = - kopi1 - .kalkulerSluttTidspunkt() - .plusDays(1) - .until( - kopi2.kalkulerSluttTidspunkt(), - mapper[kopi1.tidsEnhet], - ).toInt() - .absoluteValue - kopi2.innhold = kopi2.innhold + listOf(TidslinjePeriode(udefinert2, tidsenhetForskjell, false)) - } - } - - return Pair(kopi1, kopi2) -} - /** * Tar inn en tidslinje av en vilkårlig tidsenhet (sålangt kan det kun være MÅNED eller DAG) og returnerer den som DAG. */ fun Tidslinje.konverterTilDag(): Tidslinje { if (this.tidsEnhet == TidsEnhet.DAG) return this - var tidspunkt = this.startsTidspunkt - - when (this.tidsEnhet) { - TidsEnhet.UKE -> { - for (periode in this.innhold) { - val nyttTidspunkt = tidspunkt.plusWeeks(periode.lengde.toLong()) - periode.lengde = tidspunkt.until(nyttTidspunkt, ChronoUnit.DAYS).toInt() - tidspunkt = nyttTidspunkt - } - } + val kopi = this.kopier() + var tidspunkt = kopi.startsTidspunkt - TidsEnhet.MÅNED -> { - for (periode in this.innhold) { - val nyttTidspunkt = tidspunkt.plusMonths(periode.lengde.toLong()) - periode.lengde = tidspunkt.until(nyttTidspunkt, ChronoUnit.DAYS).toInt() - tidspunkt = nyttTidspunkt + for (periode in kopi.innhold) { + val nyttTidspunkt = + when (kopi.tidsEnhet) { + TidsEnhet.UKE -> tidspunkt.plusWeeks(periode.lengde) + TidsEnhet.MÅNED -> tidspunkt.plusMonths(periode.lengde) + TidsEnhet.ÅR -> tidspunkt.plusYears(periode.lengde) + else -> tidspunkt } - } - - else -> { - for (periode in this.innhold) { - val nyttTidspunkt = tidspunkt.plusYears(periode.lengde.toLong()) - periode.lengde = tidspunkt.until(nyttTidspunkt, ChronoUnit.DAYS).toInt() - tidspunkt = nyttTidspunkt - } - } + periode.lengde = tidspunkt.until(nyttTidspunkt, ChronoUnit.DAYS) + tidspunkt = nyttTidspunkt } - this.tidsEnhet = TidsEnhet.DAG + kopi.tidsEnhet = TidsEnhet.DAG - return this + return kopi } /** @@ -293,7 +182,7 @@ fun Tidslinje.høyreShift(antall: Int = 1): Tidslinje = */ fun Tidslinje.splittPåMåned(): MutableList>> { var nåværendeMåned = this.startsTidspunkt - var antallDagerIgjenIMåned = this.startsTidspunkt.lengthOfMonth() - this.startsTidspunkt.dayOfMonth + 1 + var antallDagerIgjenIMåned = this.startsTidspunkt.lengthOfMonth() - this.startsTidspunkt.dayOfMonth + 1L var månedListe: MutableList> = mutableListOf() // representerer periodene innad i en måned @@ -328,18 +217,18 @@ fun Tidslinje.splittPåMåned(): MutableList>> { månedListe = mutableListOf() lengde -= antallDagerIgjenIMåned nåværendeMåned = nåværendeMåned.plusMonths(1) - antallDagerIgjenIMåned = nåværendeMåned.lengthOfMonth() + antallDagerIgjenIMåned = nåværendeMåned.lengthOfMonth().toLong() } // kommer koden hit betyr det at gjenstående lengde til perioden er mindre enn antallDagerIgjenIMåned if (lengde > 0) { månedListe.add(TidslinjePeriode(periode.periodeVerdi, lengde)) antallDagerIgjenIMåned -= lengde - if (antallDagerIgjenIMåned == 0) { + if (antallDagerIgjenIMåned == 0L) { listeAvMåneder.add(månedListe) månedListe = mutableListOf() nåværendeMåned = nåværendeMåned.plusMonths(1) - antallDagerIgjenIMåned = nåværendeMåned.lengthOfMonth() + antallDagerIgjenIMåned = nåværendeMåned.lengthOfMonth().toLong() } else if (index + 1 == this.innhold.size) { // om vi er på siste periode er vi ferdige og månedListe kan addes. listeAvMåneder.add(månedListe) } @@ -366,8 +255,8 @@ private fun klippeOperator( } fun Tidslinje.klipp( - startsTidspunkt: LocalDate, - sluttTidspunkt: LocalDate, + startsTidspunkt: LocalDate = this.startsTidspunkt, + sluttTidspunkt: LocalDate = kalkulerSluttTidspunkt(), ): Tidslinje { val foreldre = this.foreldre @@ -387,7 +276,7 @@ fun Tidslinje.klipp( .until( justertSluttTidspunkt, mapper[this.tidsEnhet], - ).toInt(), + ), ), ), this.tidsEnhet, @@ -414,125 +303,6 @@ fun Tidslinje.klipp( .medTittel(this.tittel) } -fun Tidslinje.biFunksjonSnitt( - operand: Tidslinje, - operator: (elem1: PeriodeVerdi, elem2: PeriodeVerdi) -> PeriodeVerdi, -): Tidslinje { - val startsTidspunkt = - if (this.startsTidspunkt < operand.startsTidspunkt) operand.startsTidspunkt else this.startsTidspunkt - - val sluttTidspunkt1 = this.kalkulerSluttTidspunkt() - val sluttTidspunkt2 = operand.kalkulerSluttTidspunkt() - - val sluttTidspunkt = if (sluttTidspunkt1 < sluttTidspunkt2) sluttTidspunkt1 else sluttTidspunkt2 - - return this - .biFunksjon(operand, operator) - .klipp(startsTidspunkt, sluttTidspunkt) -} - -/** - * Beregner en ny tidslinje ved bruk av [kombineringsfunksjon] basert på tidslinjene this og [annen]. - * Går gjennom alle periodene i hver tidslinje og beregner nye perioder. - * Hver nye periode som blir lagt inn i den resulterende tidslinja starter der den forrige stoppet og - * har lengde lik det minste tidsrommet hvor input tidslinjene har konstant verdi. - * Påfølgende perioder med lik verdi, blir slått sammen til en periode i den resulterende tidslinja. - * [kombineringsfunksjon] blir brukt for å beregne verdiene til de generete periodene basert på verdiene til input tidslinjene i - * de respektive tidsrommene. Om en av input-tidslinjene er uendleig(dvs at den siste perioden har uendelig varighet), vil - * også den resulterende tidslinja være uendelig. - * [PeriodeVerdi] er en wrapper-classe som blir brukt for å håndtere no.nav.familie.tidslinje.Udefinert og no.nav.familie.tidslinje.Null. [kombineringsfunksjon] - * må ta høyde for at input kan være av en av disse typene, og definere hvordan disse situasjonene håndteres. - * MERK: operator skal returnere enten Udefindert, no.nav.familie.tidslinje.Null eller no.nav.familie.tidslinje.PeriodeVerdi. - */ -fun Tidslinje.biFunksjon( - annen: Tidslinje, - kombineringsfunksjon: (elem1: PeriodeVerdi, elem2: PeriodeVerdi) -> PeriodeVerdi, -): Tidslinje { - val lst: MutableList> = mutableListOf() - var kopi1 = this - var kopi2 = annen - - if (this.tidsEnhet != annen.tidsEnhet) { - kopi1 = this.konverterTilDag() - kopi2 = annen.konverterTilDag() - } - - val (kopi3, kopi4) = konverterTilSammeLengde(kopi1, kopi2) - - val it1: Iterator> = kopi3.innhold.iterator() - val it2: Iterator> = kopi4.innhold.iterator() - - var tmpTidslinjePeriode: TidslinjePeriode - - var tidslinjePeriode1: TidslinjePeriode? = null - var tidslinjePeriode2: TidslinjePeriode? = null - - var lengde1 = 0 - var lengde2 = 0 - - while (it1.hasNext() || it2.hasNext()) { - tidslinjePeriode1 = tidslinjePeriode1 ?: it1.next() - tidslinjePeriode2 = tidslinjePeriode2 ?: it2.next() - - if (tidslinjePeriode2.erUendelig && tidslinjePeriode1.erUendelig) { - lst.add( - tidslinjePeriode1.biFunksjon( - operand = tidslinjePeriode2, - lengde = INF, - erUendelig = true, - operator = kombineringsfunksjon, - ), - ) - break - } - - lengde1 = if (lengde1 <= 0) tidslinjePeriode1.lengde else lengde1 - lengde2 = if (lengde2 <= 0) tidslinjePeriode2.lengde else lengde2 - - while (lengde1 > 0 && lengde2 > 0) { - if (lengde1 < lengde2) { - lengde2 -= lengde1 - tmpTidslinjePeriode = - tidslinjePeriode1.biFunksjon( - operand = tidslinjePeriode2, - lengde = lengde1, - erUendelig = false, - operator = kombineringsfunksjon, - ) - lengde1 = 0 - } else { - lengde1 -= lengde2 - tmpTidslinjePeriode = - tidslinjePeriode1.biFunksjon( - operand = tidslinjePeriode2, - lengde = lengde2, - erUendelig = false, - operator = kombineringsfunksjon, - ) - lengde2 = 0 - } - lst.add(tmpTidslinjePeriode) - } - - if (lengde1 <= 0) { - tidslinjePeriode1 = null - } - if (lengde2 <= 0) { - tidslinjePeriode2 = null - } - } - - val resultatTidslinje = Tidslinje(kopi3.startsTidspunkt, lst, kopi3.tidsEnhet) - - @Suppress("UNCHECKED_CAST") - resultatTidslinje.foreldre.add(kopi3 as Tidslinje) - @Suppress("UNCHECKED_CAST") - resultatTidslinje.foreldre.add(kopi4 as Tidslinje) - - return resultatTidslinje - .medTittel(this.tittel) -} - /** * Beregner en ny tidslinje ved bruk av [operator] basert på tidslinjene this og [operand]. * Går gjennom alle periodene i hver tidslinje og beregner nye perioder. @@ -626,6 +396,10 @@ fun Tidslinje.fjernForeldre(): Tidslinje { fun Tidslinje.hentVerdier(): List = this.innhold.slåSammenLike().map { it.periodeVerdi.verdi } +fun Tidslinje.verdiPåTidspunkt(tidspunkt: LocalDate): V? = this.tilPerioder().verdiPåTidspunkt(tidspunkt) + +fun Collection>.verdiPåTidspunkt(tidspunkt: LocalDate): V? = this.firstOrNull { it.omfatter(tidspunkt) }?.verdi + /** * Summerer opp tiden for hver periode og legger inn i en TidslinjePeriodeMedDato * @@ -699,31 +473,6 @@ private fun LocalDate.leggTil( TidsEnhet.ÅR -> this.plusYears(antall) } -fun Tidslinje.kombinerMed( - annen: Tidslinje, - kombineringsfunksjon: (elem1: T?, elem2: R?) -> RESULTAT?, -): Tidslinje = - this.biFunksjon(annen) { periodeverdiVenstre, periodeverdiHøyre -> - kombineringsfunksjon(periodeverdiVenstre.verdi, periodeverdiHøyre.verdi) - .tilPeriodeVerdi() - } - -fun Tidslinje.kombinerMed( - tidslinje2: Tidslinje, - tidslinje3: Tidslinje, - kombineringsfunksjon: (elem1: T?, elem2: R?, elem3: S?) -> RESULTAT?, -): Tidslinje { - val tidslinje1Og2: Tidslinje> = - this.biFunksjon(tidslinje2) { elem1PeriodeVerdi, elem2PeriodeVerdi -> - Pair(elem1PeriodeVerdi.verdi, elem2PeriodeVerdi.verdi).tilPeriodeVerdi() - } - - return tidslinje1Og2.biFunksjon(tidslinje3) { elem1Og2, elem3PeriodeVerdi -> - val (elem1, elem2) = elem1Og2.verdi ?: Pair(null, null) - kombineringsfunksjon(elem1, elem2, elem3PeriodeVerdi.verdi).tilPeriodeVerdi() - } -} - fun Tidslinje.tilPerioder(): List> = this.tilTidslinjePerioderMedDato().map { it.tilPeriode() } fun Tidslinje.tilPerioderIkkeNull(): List> = this.tilPerioder().filtrerIkkeNull() diff --git a/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/KonverterTidTest.kt b/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/KonverterTidTest.kt index b7637fd0..b938f83f 100644 --- a/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/KonverterTidTest.kt +++ b/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/KonverterTidTest.kt @@ -1,11 +1,14 @@ package no.nav.familie.tidslinje.utvidelser import no.nav.familie.tidslinje.INF +import no.nav.familie.tidslinje.Periode import no.nav.familie.tidslinje.TidsEnhet import no.nav.familie.tidslinje.Tidslinje import no.nav.familie.tidslinje.TidslinjePeriode import no.nav.familie.tidslinje.Verdi +import no.nav.familie.tidslinje.tilTidslinje import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test import java.time.LocalDate @@ -22,8 +25,8 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -52,10 +55,10 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.DAYS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -84,10 +87,10 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.DAYS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -119,11 +122,11 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(5, dato5Start.until(dato5Slutt, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(5, dato5Start.until(dato5Slutt, ChronoUnit.DAYS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -155,11 +158,11 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(5, dato5Start.until(dato5Slutt, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(5, dato5Start.until(dato5Slutt, ChronoUnit.DAYS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -189,11 +192,11 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(1.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(2.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(3.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(4.0, dato4Start.until(dato4Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(5.0, dato5Start.until(dato5Slutt, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(1.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(2.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(3.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(4.0, dato4Start.until(dato4Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(5.0, dato5Start.until(dato5Slutt, ChronoUnit.DAYS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -353,11 +356,11 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(1.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(2.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(3.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(4.0, dato4Start.until(dato4Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(5.0, dato5Start.until(dato5Slutt, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(1.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(2.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(3.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(4.0, dato4Start.until(dato4Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(5.0, dato5Start.until(dato5Slutt, ChronoUnit.DAYS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -408,11 +411,11 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(true, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(false, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(true, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(true, dato4Start.until(dato4Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(false, dato5Start.until(dato5Slutt, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(true, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(false, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(true, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(true, dato4Start.until(dato4Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(false, dato5Start.until(dato5Slutt, ChronoUnit.DAYS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -451,11 +454,11 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(1.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(2.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(3.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(4.0, dato4Start.until(dato4Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(5.0, dato5Start.until(dato5Slutt, ChronoUnit.DAYS).toInt() + 1, true), + TidslinjePeriode(1.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(2.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(3.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(4.0, dato4Start.until(dato4Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(5.0, dato5Start.until(dato5Slutt, ChronoUnit.DAYS) + 1, true), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -502,9 +505,9 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(5.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(7.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(15.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(5.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(7.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(15.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -537,9 +540,9 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(5.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(7.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(15.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(5.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(7.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(15.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -588,9 +591,9 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(5.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(7.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(15.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1, erUendelig = true), + TidslinjePeriode(5.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(7.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(15.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1, erUendelig = true), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -630,9 +633,9 @@ class KonverterTidTest { val tmp = listOf( - TidslinjePeriode(5.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(7.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(15.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS).toInt() + 1, erUendelig = true), + TidslinjePeriode(5.0, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(7.0, dato2Start.until(dato2Slutt, ChronoUnit.DAYS) + 1), + TidslinjePeriode(15.0, dato3Start.until(dato3Slutt, ChronoUnit.DAYS) + 1, erUendelig = true), ) val tidslinje = Tidslinje(dato1Start, tmp) @@ -647,4 +650,23 @@ class KonverterTidTest { Assertions.assertEquals(correct, tidslinjeMåned.innhold.map { it.periodeVerdi.verdi!!.toInt() }.toList()) assertTrue(tidslinjeMåned.innhold.last().erUendelig) } + + @Test fun `konvertering fra månedtidslinje til dagtidslinje skal beholde uendelighet`() { + val perioder = listOf(Periode(verdi = 'a', fom = LocalDate.now(), tom = null)) + + val månedTidslinje = + perioder.tilTidslinje().konverterTilMåned { _, månedListe -> + månedListe.single().single().periodeVerdi + } + + val dagTidslinje = månedTidslinje.konverterTilDag() + + val faktiskLengde = dagTidslinje.innhold.sumOf { it.lengde } + + val månedTidslinjeStart = månedTidslinje.startsTidspunkt + val månedTidslinjeSlutt = månedTidslinje.kalkulerSluttTidspunkt() + val forventetLengde = månedTidslinjeStart.until(månedTidslinjeSlutt, ChronoUnit.DAYS) + 1 + + assertEquals(forventetLengde, faktiskLengde) + } } diff --git a/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/OmregningTest.kt b/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/OmregningTest.kt index 7d6b1b62..67c3dd8b 100644 --- a/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/OmregningTest.kt +++ b/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/OmregningTest.kt @@ -25,10 +25,10 @@ class OmregningTest { val tmp = listOf( - TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.WEEKS).toInt() + 1), - TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.WEEKS).toInt() + 1), - TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.WEEKS).toInt() + 1), - TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.WEEKS).toInt() + 1), + TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.WEEKS) + 1), + TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.WEEKS) + 1), + TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.WEEKS) + 1), + TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.WEEKS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp, tidsEnhet = TidsEnhet.UKE) @@ -60,10 +60,10 @@ class OmregningTest { val tmp = listOf( - TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.MONTHS).toInt() + 1), - TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.MONTHS).toInt() + 1), - TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.MONTHS).toInt() + 1), - TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.MONTHS).toInt() + 1), + TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.MONTHS) + 1), + TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.MONTHS) + 1), + TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.MONTHS) + 1), + TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.MONTHS) + 1), ) val tidslinje = Tidslinje(dato1Start, tmp, tidsEnhet = TidsEnhet.MÅNED) @@ -95,10 +95,10 @@ class OmregningTest { val tidslinjePerioder = listOf( - TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.YEARS).toInt() + 1), - TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.YEARS).toInt() + 1), - TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.YEARS).toInt() + 1), - TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.YEARS).toInt() + 1), + TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.YEARS) + 1), + TidslinjePeriode(2, dato2Start.until(dato2Slutt, ChronoUnit.YEARS) + 1), + TidslinjePeriode(3, dato3Start.until(dato3Slutt, ChronoUnit.YEARS) + 1), + TidslinjePeriode(4, dato4Start.until(dato4Slutt, ChronoUnit.YEARS) + 1), ) val tidslinje = Tidslinje(dato1Start, tidslinjePerioder, tidsEnhet = TidsEnhet.ÅR) @@ -119,10 +119,10 @@ class OmregningTest { val dato1Start = LocalDate.of(2022, 1, 1) val dato1Slutt = LocalDate.of(2023, 12, 31) - val tmpÅR = listOf(TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.YEARS).toInt() + 1)) - val tmpMåned = listOf(TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.MONTHS).toInt() + 1)) - val tmpUke = listOf(TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.WEEKS).toInt() + 1)) - val tmpDag = listOf(TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS).toInt() + 1)) + val tmpÅR = listOf(TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.YEARS) + 1)) + val tmpMåned = listOf(TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.MONTHS) + 1)) + val tmpUke = listOf(TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.WEEKS) + 1)) + val tmpDag = listOf(TidslinjePeriode(1, dato1Start.until(dato1Slutt, ChronoUnit.DAYS) + 1)) val tidslinjeÅR = Tidslinje(dato1Start, tmpÅR, tidsEnhet = TidsEnhet.ÅR) val tidslinjeMåned = Tidslinje(dato1Start, tmpMåned, tidsEnhet = TidsEnhet.MÅNED) diff --git a/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/TidslinjeListeTest.kt b/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/TidslinjeListeTest.kt index 29d93bde..9ff4083c 100644 --- a/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/TidslinjeListeTest.kt +++ b/tidslinje/src/test/kotlin/no/nav/familie/tidslinje/utvidelser/TidslinjeListeTest.kt @@ -122,8 +122,8 @@ class TidslinjeListeTest { Tidslinje( start1, listOf( - TidslinjePeriode(true, start1.until(stopp1, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(false, start2.until(stopp2, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(true, start1.until(stopp1, ChronoUnit.DAYS) + 1), + TidslinjePeriode(false, start2.until(stopp2, ChronoUnit.DAYS) + 1), ), ) @@ -137,8 +137,8 @@ class TidslinjeListeTest { Tidslinje( start1, listOf( - TidslinjePeriode(true, start1.until(stopp1, ChronoUnit.DAYS).toInt() + 1), - TidslinjePeriode(false, start2.until(stopp2, ChronoUnit.DAYS).toInt() + 1), + TidslinjePeriode(true, start1.until(stopp1, ChronoUnit.DAYS) + 1), + TidslinjePeriode(false, start2.until(stopp2, ChronoUnit.DAYS) + 1), ), )