This is an automated email from the git hooks/post-receive script. New commit to branch develop in repository nuiton-utils. See https://gitlab.nuiton.org/nuiton/nuiton-utils.git commit c3bc8c32f06ad094cbed48ab8203011c2ac3b975 Author: Benjamin <poussin@codelutin.com> Date: Fri Sep 7 17:06:04 2018 +0200 Ajout du calcul de jours ouvrés (avec par l'implantation pour les vacances pour la france) --- src/main/java/org/nuiton/util/WorkdayUtil.java | 132 +++++++++++++++++++++ src/test/java/org/nuiton/util/WorkdayUtilTest.java | 77 ++++++++++++ 2 files changed, 209 insertions(+) diff --git a/src/main/java/org/nuiton/util/WorkdayUtil.java b/src/main/java/org/nuiton/util/WorkdayUtil.java new file mode 100644 index 0000000..271590e --- /dev/null +++ b/src/main/java/org/nuiton/util/WorkdayUtil.java @@ -0,0 +1,132 @@ +package org.nuiton.util; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.Year; +import java.time.temporal.ChronoUnit; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.function.Function; + +/** + * Permet de calculer le nombre de jour ouvré entre deux dates. + * + * du 3 au 3 donne 0. + * du 3 au 4 donne 1 (si 3 n'est pas un jour fermé) + */ +public class WorkdayUtil { + + public static long computeWorday(LocalDate start, LocalDate end, Set<DayOfWeek> weekWorkday, Function<Year, List<LocalDate>> publicHoliday) { + + // recherche tous les jours fériés des années entre les deux dates + Set<LocalDate> publicHolidays = new HashSet<>(); + for (int year = start.getYear(), lastYear = end.getYear(); year <= lastYear; year++) { + publicHolidays.addAll(publicHoliday.apply(Year.of(year))); + } + + // calcul le nombre de jour férié dans l'interval + long publicHolidayNumber = publicHolidays.stream() + // On garde que des jours fériés qui tombe un jour ouvré + .filter(d -> weekWorkday.contains(d.getDayOfWeek())) + // On garde que des jours fériés qui sont dans l'interval de date + .filter(d -> start.compareTo(d) * d.compareTo(end) >= 0) + .count(); + + // calcul le nombre de jour ouvré en semaine pleine + long days = ChronoUnit.DAYS.between(start, end); + long week = days / DayOfWeek.values().length; + + long result = week * weekWorkday.size(); + + // on calcul le nombre de jour ouvré de la dernière semaine non pleine + LocalDate lastDays = end.minusDays(days % DayOfWeek.values().length); + + while (lastDays.isBefore(end)) { + if (weekWorkday.contains(lastDays.getDayOfWeek())) { + result++; + } + lastDays = lastDays.plusDays(1); + } + + // on retranche les jours fériés + result -= publicHolidayNumber; + + return result; + } + + public static class FrenchPublicHoliday implements Function<Year, List<LocalDate>> { + + @Override + public List<LocalDate> apply(Year year) { + LocalDate easter = computeEaster(year); + + List<LocalDate> result = new LinkedList<>(); + + result.add(computeEasterMonday(easter)); + result.add(computeAscensionDay(easter)); + result.add(computeWhitMonday(easter)); + result.add(LocalDate.of(year.getValue(), 1, 1)); + result.add(LocalDate.of(year.getValue(), 5, 1)); + result.add(LocalDate.of(year.getValue(), 5, 8)); + result.add(LocalDate.of(year.getValue(), 7, 14)); + result.add(LocalDate.of(year.getValue(), 8, 15)); + result.add(LocalDate.of(year.getValue(), 11, 1)); + result.add(LocalDate.of(year.getValue(), 11, 11)); + result.add(LocalDate.of(year.getValue(), 12, 25)); + + return result; + } + } + + /** + * Calcul fait par la méthode de Butcher-Meeus (valide si année ≥ 1583) + * + * @param year l'année pour lequel on souhaite calculer le dimanche de paques + * @return la date du dimanche paques + */ + public static LocalDate computeEaster(Year year) { + int y = year.getValue(); + int n = y % 19; + + int c = y / 100; + int u = y % 100; + + int s = c / 4; + int t = c % 4; + + int p = (c + 8) / 25; + int q = (c - p + 1) / 3; + + int e = (19 * n + c - s - q + 15) % 30; + + int b = u / 4; + int d = u % 4; + + int L = (32 + 2 * t + 2 * b - e - d) % 7; + int h = (n + 11 * e + 22 * L) / 451; + + int m = (e + L - 7 * h + 114) / 31; + int j = (e + L - 7 * h + 114) % 31; + + LocalDate easterMonday = LocalDate.of(y, m, j + 1); + + return easterMonday; + } + + public static LocalDate computeEasterMonday(LocalDate easter) { + LocalDate easterMonday = easter.plusDays(1); + return easterMonday; + } + + public static LocalDate computeAscensionDay(LocalDate easter) { + LocalDate ascensionDay = easter.plusDays(39); + return ascensionDay; + } + + public static LocalDate computeWhitMonday(LocalDate easter) { + LocalDate whitMonday = easter.plusDays(50); + return whitMonday; + } +} diff --git a/src/test/java/org/nuiton/util/WorkdayUtilTest.java b/src/test/java/org/nuiton/util/WorkdayUtilTest.java new file mode 100644 index 0000000..139cb61 --- /dev/null +++ b/src/test/java/org/nuiton/util/WorkdayUtilTest.java @@ -0,0 +1,77 @@ +package org.nuiton.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.Year; +import java.util.EnumSet; +import java.util.Set; + +public class WorkdayUtilTest { + + @Test + public void testEasterAscensionDayWit() { + LocalDate easter2006 = WorkdayUtil.computeEaster(Year.of(2006)); + Assert.assertEquals(LocalDate.of(2006, 4, 16), easter2006); + + LocalDate easter2018 = WorkdayUtil.computeEaster(Year.of(2018)); + Assert.assertEquals(LocalDate.of(2018, 4, 2), WorkdayUtil.computeEasterMonday(easter2018)); + Assert.assertEquals(LocalDate.of(2018, 5, 10), WorkdayUtil.computeAscensionDay(easter2018)); + Assert.assertEquals(LocalDate.of(2018, 5, 21), WorkdayUtil.computeWhitMonday(easter2018)); + + LocalDate easter2019 = WorkdayUtil.computeEaster(Year.of(2019)); + Assert.assertEquals(LocalDate.of(2019, 4, 22), WorkdayUtil.computeEasterMonday(easter2019)); + Assert.assertEquals(LocalDate.of(2019, 5, 30), WorkdayUtil.computeAscensionDay(easter2019)); + Assert.assertEquals(LocalDate.of(2019, 6, 10), WorkdayUtil.computeWhitMonday(easter2019)); + + LocalDate easter2020 = WorkdayUtil.computeEaster(Year.of(2020)); + Assert.assertEquals(LocalDate.of(2020, 4, 13), WorkdayUtil.computeEasterMonday(easter2020)); + Assert.assertEquals(LocalDate.of(2020, 5, 21), WorkdayUtil.computeAscensionDay(easter2020)); + Assert.assertEquals(LocalDate.of(2020, 6, 1), WorkdayUtil.computeWhitMonday(easter2020)); + } + + @Test + public void testWorkDays() { + Set<DayOfWeek> weekWorkday = EnumSet.of(DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY); + WorkdayUtil.FrenchPublicHoliday publicHoliday = new WorkdayUtil.FrenchPublicHoliday(); + + { + LocalDate start = LocalDate.of(2017, 12, 22); + LocalDate end = LocalDate.of(2017, 12, 22); + + Assert.assertEquals(0, WorkdayUtil.computeWorday(start, end, weekWorkday, publicHoliday)); + } + { + LocalDate start = LocalDate.of(2017, 12, 22); + LocalDate end = LocalDate.of(2017, 12, 25); + + Assert.assertEquals(0, WorkdayUtil.computeWorday(start, end, weekWorkday, publicHoliday)); + } + { + LocalDate start = LocalDate.of(2017, 12, 22); + LocalDate end = LocalDate.of(2017, 12, 26); + + Assert.assertEquals(1, WorkdayUtil.computeWorday(start, end, weekWorkday, publicHoliday)); + } + { + LocalDate start = LocalDate.of(2017, 12, 22); + LocalDate end = LocalDate.of(2018, 1, 6); + + Assert.assertEquals(9, WorkdayUtil.computeWorday(start, end, weekWorkday, publicHoliday)); + } + { + LocalDate start = LocalDate.of(2017, 12, 25); + LocalDate end = LocalDate.of(2017, 12, 26); + + Assert.assertEquals(0, WorkdayUtil.computeWorday(start, end, weekWorkday, publicHoliday)); + } + { + LocalDate start = LocalDate.of(2017, 12, 25); + LocalDate end = LocalDate.of(2018, 1, 26); + + Assert.assertEquals(22, WorkdayUtil.computeWorday(start, end, weekWorkday, publicHoliday)); + } + } +} -- To stop receiving notification emails like this one, please contact nuiton.org SCM administrator <admin+scm@nuiton.org>.