CalendrierOuvre.kt
72 lignes · 2515 octets
package fr.ebii.card2vcf.planning import java.time.DayOfWeek import java.time.LocalDate import java.time.format.DateTimeFormatter /** * Calendrier ouvré d'un projet — port de `Server/src/services/calendrier.rs`. * * Les durées de tâches se comptent en jours **ouvrés** selon le rythme du * projet (`joursOuvres` : 5 = lun-ven, 6 = lun-sam, 7 = tous les jours). Une * tâche ne peut donc pas calculer sa fin seule : il lui faut le calendrier de * son projet. Sans ce port, le téléphone afficherait une fin différente de * celle du diagramme web. * * Les deux implémentations sont tenues par les mêmes cas de test : * `Server/tests/calendrier.rs` et `CalendrierOuvreTest`. */ class CalendrierOuvre(joursOuvres: Int) { /** Un rythme hors de 5-7 (donnée abîmée) retombe sur 7, comportement historique. */ private val rythme: Int = when (joursOuvres) { 5 -> 5 6 -> 6 else -> 7 } fun estOuvre(jour: LocalDate): Boolean = when (jour.dayOfWeek) { DayOfWeek.SATURDAY -> rythme >= 6 DayOfWeek.SUNDAY -> rythme >= 7 else -> true } /** Premier jour ouvré à partir de [jour] inclus. */ fun caler(jour: LocalDate): LocalDate { var j = jour while (!estOuvre(j)) j = j.plusDays(1) return j } /** Avance de [n] jours ouvrés depuis [jour], calé au préalable. */ fun avancer(jour: LocalDate, n: Int): LocalDate { var j = caler(jour) repeat(maxOf(n, 0)) { j = caler(j.plusDays(1)) } return j } /** Nombre de jours ouvrés dans `[debut, fin]` inclus ; 0 si l'intervalle est inversé. */ fun compter(debut: LocalDate, fin: LocalDate): Int { var n = 0 var j = debut while (!j.isAfter(fin)) { if (estOuvre(j)) n++ j = j.plusDays(1) } return n } /** Dernier jour inclus. Une durée nulle vaut un jour : jamais de période vide. */ fun fin(debut: LocalDate, dureeJours: Int): LocalDate = avancer(debut, maxOf(dureeJours, 1) - 1) /** « 09/01 → 13/01 », ou le jour seul si la tâche tient sur une journée. */ fun periodeAffichee(debut: LocalDate, dureeJours: Int): String { val f = fin(debut, dureeJours) val d = caler(debut) return if (d == f) d.format(FORMAT) else "${d.format(FORMAT)} → ${f.format(FORMAT)}" } private companion object { val FORMAT: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM") } }
GitRust