├── .circleci └── config.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── jours_feries_france └── __init__.py ├── setup.cfg ├── setup.py └── tests └── test.py /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | workflows: 2 | version: 2 3 | test: 4 | jobs: 5 | - test-2.7 6 | - test-3.5 7 | - test-3.6 8 | - test-latest 9 | jobs: 10 | test-3.6: &test-template 11 | docker: 12 | - image: circleci/python:3.6 13 | environment: 14 | PYTHON_VERSION=3.6 15 | working_directory: ~/repo 16 | steps: 17 | - checkout 18 | 19 | - run: 20 | name: Write Python version to file 21 | command: | 22 | echo $PYTHON_VERSION > /tmp/PYTHON_VERSION 23 | cat /tmp/PYTHON_VERSION 24 | - restore_cache: 25 | keys: 26 | - v1-dependencies-{{ checksum "setup.py" }}-{{ checksum "/tmp/PYTHON_VERSION" }} 27 | - run: 28 | name: Install dependencies 29 | command: | 30 | python -m venv venv || virtualenv -p /usr/bin/python2.7 venv 31 | . venv/bin/activate 32 | pip install -e .[dev] 33 | - save_cache: 34 | paths: 35 | - ./venv 36 | key: v1-dependencies-{{ checksum "setup.py" }}-{{ checksum "/tmp/PYTHON_VERSION" }} 37 | 38 | - run: 39 | name: Run test suite 40 | command: | 41 | . venv/bin/activate 42 | nosetests . 43 | test-3.5: 44 | <<: *test-template 45 | docker: 46 | - image: circleci/python:3.5 47 | environment: 48 | PYTHON_VERSION=3.5 49 | test-2.7: 50 | <<: *test-template 51 | docker: 52 | - image: circleci/python:2.7 53 | environment: 54 | PYTHON_VERSION=2.7 55 | test-latest: 56 | <<: *test-template 57 | docker: 58 | - image: circleci/python:latest 59 | environment: 60 | PYTHON_VERSION=latest 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.egg-info 2 | *.pyc 3 | build 4 | data 5 | dist 6 | main 7 | venv 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changements 2 | 3 | ## 0.7.0 - 2020-05-15 4 | 5 | - ⚠️ Utilisation des noms des jours fériés en vigueur dans le code du travail 6 | - ⚠️ Changement du nom des méthodes pour chaque jour férié pour correspondre au code du travail 7 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Etalab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Software License](https://img.shields.io/badge/License-MIT-orange.svg?style=flat-square)](https://github.com/etalab/jours-feries-france/blob/master/LICENSE.md) 2 | ![CircleCI](https://img.shields.io/circleci/project/github/etalab/jours-feries-france.svg?style=flat-square) 3 | ![PyPI - Downloads](https://img.shields.io/pypi/dm/jours-feries-france.svg?style=flat-square) 4 | 5 | # Jours fériés France 6 | Cette librairie calcule les jours fériés en France. Vous pouvez découvrir plus de détails sur les jours fériés français sur [service-public.fr](https://www.service-public.fr/particuliers/vosdroits/F2405). 7 | 8 | Cette librairie fonctionne à partir de la version 2.7 de Python. 9 | 10 | ## Installation 11 | ``` 12 | pip install jours-feries-france 13 | ``` 14 | 15 | ## Usage 16 | ```python 17 | import datetime 18 | 19 | from jours_feries_france import JoursFeries 20 | 21 | # Obtenir les jours fériés pour une année, pour la métropole 22 | res = JoursFeries.for_year(2018) 23 | # res est un dictionnaire 24 | # { 25 | # '1er janvier': datetime.date(2018, 1, 1), 26 | # 'Lundi de Pâques': datetime.date(2018, 4, 2), 27 | # '1er mai': datetime.date(2018, 5, 1), 28 | # '8 mai': datetime.date(2018, 5, 8), 29 | # 'Ascension': datetime.date(2018, 5, 10), 30 | # 'Lundi de Pentecôte': datetime.date(2018, 5, 21), 31 | # '14 juillet': datetime.date(2018, 7, 14), 32 | # 'Assomption': datetime.date(2018, 8, 15), 33 | # 'Toussaint': datetime.date(2018, 11, 1), 34 | # '11 novembre': datetime.date(2018, 11, 11), 35 | # 'Jour de Noël': datetime.date(2018, 12, 25) 36 | # } 37 | 38 | # Vous pouvez aussi obtenir certains jours fériés en tant que datetime.date 39 | print (JoursFeries.lundi_paques(2018)) 40 | print (JoursFeries.ascension(2018)) 41 | print (JoursFeries.lundi_pentecote(2018)) 42 | 43 | # Obtenir les jours fériés pour une zone spécifique 44 | res = JoursFeries.for_year(2018, zone="Alsace-Moselle") 45 | 46 | # Quelques fonctions d'aide 47 | JoursFeries.is_bank_holiday(datetime.date(2019, 12, 25), zone="Métropole") 48 | # -> True 49 | JoursFeries.next_bank_holiday(datetime.date(2019, 12, 24), zone="Métropole") 50 | # -> ('Noël', datetime.date(2019, 12, 25)) 51 | ``` 52 | 53 | ### Zones disponibles 54 | Les zones suivantes sont disponibles : 55 | - `Métropole` (par défaut) 56 | - `Alsace-Moselle` 57 | - `Guadeloupe` 58 | - `Guyane` 59 | - `La Réunion` 60 | - `Martinique` 61 | - `Mayotte` 62 | - `Nouvelle-Calédonie` 63 | - `Polynésie Française` 64 | - `Saint-Barthélémy` 65 | - `Saint-Martin` 66 | - `Saint-Pierre-et-Miquelon` 67 | - `Wallis-et-Futuna` 68 | 69 | Ces zones sont disponibles dans une constante : 70 | ```python 71 | from jours_feries_france import JoursFeries 72 | 73 | print(JoursFeries.ZONES) 74 | # [ 75 | # 'Métropole', 'Alsace-Moselle', 'Guadeloupe', 76 | # 'Guyane', 'Martinique', 'Mayotte', 'Nouvelle-Calédonie', 77 | # 'La Réunion', 'Polynésie Française', 'Saint-Barthélémy', 78 | # 'Saint-Martin', 'Wallis-et-Futuna', 'Saint-Pierre-et-Miquelon' 79 | # ] 80 | ``` 81 | 82 | ### Noms des jours fériés 83 | Les noms des jours fériés sont fixés d'[après le code du travail](#sources). 84 | 85 | Pour les zones `Métropole` (par défaut), `Nouvelle-Calédonie`, `Polynésie Française`, `Saint-Pierre-et-Miquelon` et `Wallis-et-Futuna`, les jours fériés sont orthographiés de la façon suivante : 86 | - `1er janvier` 87 | - `Lundi de Pâques` 88 | - `1er mai` 89 | - `8 mai` 90 | - `Ascension` 91 | - `Lundi de Pentecôte` 92 | - `14 juillet` 93 | - `Assomption` 94 | - `Toussaint` 95 | - `11 novembre` 96 | - `Jour de Noël` 97 | 98 | Pour la zone `Alsace-Moselle`, il existe 2 jours fériés supplémentaires, orthographiés de la façon suivante : 99 | - `2ème jour de Noël` 100 | - `Vendredi saint` 101 | 102 | Pour les zones `Guadeloupe`, `Guyane`, `La Réunion`, `Martinique`, `Mayotte`, `Saint-Barthélémy` et `Saint-Martin`, il existe un jour férié supplémentaire, orthographié de la façon suivante : 103 | - `Abolition de l'esclavage` 104 | 105 | ### Noms des méthodes Python 106 | 107 | Vous pouvez calculer chaque jour férié individuellement à l'aide d'une méthode spécifique. 108 | 109 | ```python 110 | from jours_feries_france import JoursFeries 111 | 112 | year = 2020 113 | zone = 'Métropole' 114 | 115 | print("1er janvier", JoursFeries.premier_janvier(year)) 116 | print("1er mai", JoursFeries.premier_mai(year)) 117 | print("8 mai", JoursFeries.huit_mai(year)) 118 | print("14 juillet", JoursFeries.quatorze_juillet(year)) 119 | print("Assomption", JoursFeries.assomption(year)) 120 | print("Toussaint", JoursFeries.toussaint(year)) 121 | print("11 novembre", JoursFeries.onze_novembre(year)) 122 | print("Jour de Noël", JoursFeries.jour_noel(year)) 123 | print("Lundi de Pâques", JoursFeries.lundi_paques(year)) 124 | print("Ascension", JoursFeries.ascension(year)) 125 | print("Lundi de Pentecôte", JoursFeries.lundi_pentecote(year)) 126 | print("Vendredi saint", JoursFeries.vendredi_saint(year, zone)) 127 | print("2ème jour de Noël", JoursFeries.deuxieme_jour_noel(year, zone)) 128 | print("Abolition de l'esclavage", JoursFeries.abolition_esclavage(year, zone)) 129 | ``` 130 | 131 | Certaines méthodes acceptent une `zone` en paramètre car ce jour férié est spécifique à certaines zones. Si ce jour férié n'est pas férié pour la zone passée en argument, vous aurez la valeur `None` en retour au lieu d'une date. 132 | 133 | ## Données 134 | Si vous souhaitez simplement un export, consultez le jeu de données ["Jours fériés en France"](https://www.data.gouv.fr/fr/datasets/jours-feries-en-france/) sur data.gouv.fr. 135 | 136 | ## Sources 137 | La liste des jours fériés est définie [dans le code du travail](#sources). 138 | 139 | Certaines commémorations locales ou professionnelles sont également des jours fériés, parmi lesquelles : 140 | - Saint-Éloi (reconnu jour férié par certaines conventions collectives dans la métallurgie) ; 141 | - Sainte-Barbe (pour les salariés travaillant dans les mines) ; 142 | - Mi-carême dans certains DOM. 143 | 144 | Ces fêtes locales ou professionnelles ne sont pas disponibles dans cette librairie. 145 | 146 | - [Code du travail : articles L3133-1 à L3133-3](https://www.legifrance.gouv.fr/affichCode.do?idSectionTA=LEGISCTA000033008129&cidTexte=LEGITEXT000006072050) 147 | - [Code du travail - Article L3422-2](https://www.legifrance.gouv.fr/affichCodeArticle.do?idArticle=LEGIARTI000035902463&cidTexte=LEGITEXT000006072050) 148 | -------------------------------------------------------------------------------- /jours_feries_france/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from datetime import date, timedelta 5 | 6 | 7 | class JoursFeries(object): 8 | ZONES = [ 9 | "Métropole", 10 | "Alsace-Moselle", 11 | "Guadeloupe", 12 | "Guyane", 13 | "Martinique", 14 | "Mayotte", 15 | "Nouvelle-Calédonie", 16 | "La Réunion", 17 | "Polynésie Française", 18 | "Saint-Barthélémy", 19 | "Saint-Martin", 20 | "Wallis-et-Futuna", 21 | "Saint-Pierre-et-Miquelon", 22 | ] 23 | 24 | def __init__(self): 25 | super(JoursFeries, self).__init__() 26 | 27 | @staticmethod 28 | def check_zone(zone): 29 | zone = zone or "Métropole" 30 | 31 | if zone not in JoursFeries.ZONES: 32 | valid_values = ", ".join(JoursFeries.ZONES) 33 | raise ValueError( 34 | "%s is invalid. Supported values: %s" % (zone, valid_values) 35 | ) 36 | 37 | return zone 38 | 39 | @staticmethod 40 | def is_bank_holiday(date, zone=None): 41 | return date in JoursFeries.for_year(date.year, zone).values() 42 | 43 | @staticmethod 44 | def next_bank_holiday(date, zone=None): 45 | while not JoursFeries.is_bank_holiday(date, zone): 46 | date = date + timedelta(days=1) 47 | 48 | return [ 49 | (k, v) 50 | for k, v in JoursFeries.for_year(date.year, zone).items() 51 | if v == date 52 | ][0] 53 | 54 | @staticmethod 55 | def for_year(year, zone=None): 56 | JoursFeries.check_zone(zone) 57 | 58 | bank_holidays = { 59 | "1er janvier": JoursFeries.premier_janvier(year), 60 | "1er mai": JoursFeries.premier_mai(year), 61 | "8 mai": JoursFeries.huit_mai(year), 62 | "14 juillet": JoursFeries.quatorze_juillet(year), 63 | "Assomption": JoursFeries.assomption(year), 64 | "Toussaint": JoursFeries.toussaint(year), 65 | "11 novembre": JoursFeries.onze_novembre(year), 66 | "Jour de Noël": JoursFeries.jour_noel(year), 67 | "Lundi de Pâques": JoursFeries.lundi_paques(year), 68 | "Ascension": JoursFeries.ascension(year), 69 | "Lundi de Pentecôte": JoursFeries.lundi_pentecote(year), 70 | "Vendredi saint": JoursFeries.vendredi_saint(year, zone), 71 | "2ème jour de Noël": JoursFeries.deuxieme_jour_noel(year, zone), 72 | "Abolition de l'esclavage": JoursFeries.abolition_esclavage(year, zone), 73 | } 74 | 75 | bank_holidays = {k: v for k, v in bank_holidays.items() if v} 76 | 77 | return { 78 | k: v for k, v in sorted(bank_holidays.items(), key=lambda item: item[1]) 79 | } 80 | 81 | @staticmethod 82 | def paques(year): 83 | if year < 1886: 84 | return None 85 | a = year % 19 86 | b = year // 100 87 | c = year % 100 88 | d = (19 * a + b - b // 4 - ((b - (b + 8) // 25 + 1) // 3) + 15) % 30 89 | e = (32 + 2 * (b % 4) + 2 * (c // 4) - d - (c % 4)) % 7 90 | f = d + e - 7 * ((a + 11 * d + 22 * e) // 451) + 114 91 | month = f // 31 92 | day = f % 31 + 1 93 | return date(year, month, day) 94 | 95 | @staticmethod 96 | def lundi_paques(year): 97 | if year >= 1886: 98 | return JoursFeries.paques(year) + timedelta(days=1) 99 | return None 100 | 101 | @staticmethod 102 | def vendredi_saint(year, zone): 103 | if zone == JoursFeries.check_zone("Alsace-Moselle"): 104 | return JoursFeries.paques(year) - timedelta(days=2) 105 | return None 106 | 107 | @staticmethod 108 | def ascension(year): 109 | if year >= 1802: 110 | return JoursFeries.paques(year) + timedelta(days=39) 111 | return None 112 | 113 | @staticmethod 114 | def lundi_pentecote(year): 115 | if year >= 1886: 116 | return JoursFeries.paques(year) + timedelta(days=50) 117 | return None 118 | 119 | @staticmethod 120 | def premier_janvier(year): 121 | if year > 1810: 122 | return date(year, 1, 1) 123 | return None 124 | 125 | @staticmethod 126 | def premier_mai(year): 127 | if year > 1919: 128 | return date(year, 5, 1) 129 | return None 130 | 131 | @staticmethod 132 | def huit_mai(year): 133 | if (1953 <= year <= 1959) or year > 1981: 134 | return date(year, 5, 8) 135 | return None 136 | 137 | @staticmethod 138 | def quatorze_juillet(year): 139 | if year >= 1880: 140 | return date(year, 7, 14) 141 | return None 142 | 143 | @staticmethod 144 | def toussaint(year): 145 | if year >= 1802: 146 | return date(year, 11, 1) 147 | return None 148 | 149 | @staticmethod 150 | def assomption(year): 151 | if year >= 1802: 152 | return date(year, 8, 15) 153 | return None 154 | 155 | @staticmethod 156 | def onze_novembre(year): 157 | if year >= 1918: 158 | return date(year, 11, 11) 159 | return None 160 | 161 | @staticmethod 162 | def jour_noel(year): 163 | if year >= 1802: 164 | return date(year, 12, 25) 165 | return None 166 | 167 | @staticmethod 168 | def deuxieme_jour_noel(year, zone): 169 | if zone == JoursFeries.check_zone("Alsace-Moselle"): 170 | return date(year, 12, 26) 171 | return None 172 | 173 | @staticmethod 174 | def abolition_esclavage(year, zone): 175 | if zone == JoursFeries.check_zone("Mayotte") and year >= 1983: 176 | return date(year, 4, 27) 177 | 178 | if zone == JoursFeries.check_zone("Martinique") and year >= 1983: 179 | return date(year, 5, 22) 180 | 181 | if zone == JoursFeries.check_zone("Guadeloupe") and year >= 1983: 182 | return date(year, 5, 27) 183 | 184 | if zone == JoursFeries.check_zone("Saint-Martin"): 185 | if year >= 2018: 186 | return date(year, 5, 28) 187 | elif year >= 1983: 188 | return date(year, 5, 27) 189 | 190 | if zone == JoursFeries.check_zone("Guyane") and year >= 1983: 191 | return date(year, 6, 10) 192 | 193 | if zone == JoursFeries.check_zone("Saint-Barthélémy") and year >= 1983: 194 | return date(year, 10, 9) 195 | 196 | if zone == JoursFeries.check_zone("La Réunion") and year >= 1981: 197 | return date(year, 12, 20) 198 | 199 | return None 200 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.md 3 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup( 4 | name="jours_feries_france", 5 | license="MIT", 6 | packages=["jours_feries_france"], 7 | version="0.7.0", 8 | description="Jours fériés en France, en métropole et en outre-mer.", 9 | author="Etalab", 10 | author_email="info@data.gouv.fr", 11 | url="https://github.com/etalab/jours-feries-france", 12 | keywords=["bank-holidays", "jours-feries", "france"], 13 | extras_require={"dev": ["nose"]}, 14 | python_requires=">=2.7,<4", 15 | long_description=open("README.md").read(), 16 | long_description_content_type="text/markdown", 17 | classifiers=[ 18 | "Development Status :: 5 - Production/Stable", 19 | "Intended Audience :: Developers", 20 | "Topic :: Software Development :: Libraries", 21 | "License :: OSI Approved :: MIT License", 22 | "Programming Language :: Python :: 3", 23 | "Programming Language :: Python :: 2.7", 24 | "Programming Language :: Python :: 3.5", 25 | "Programming Language :: Python :: 3.6", 26 | "Programming Language :: Python :: 3.7", 27 | ], 28 | ) 29 | -------------------------------------------------------------------------------- /tests/test.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | import unittest 5 | from datetime import date 6 | 7 | from jours_feries_france import JoursFeries 8 | 9 | 10 | class TestDatasetParser(unittest.TestCase): 11 | def test_validates_region(self): 12 | with self.assertRaises(ValueError): 13 | JoursFeries.for_year(2018, zone="foo") 14 | 15 | def test_is_bank_holiday(self): 16 | self.assertTrue(JoursFeries.is_bank_holiday(date(2019, 12, 25))) 17 | self.assertTrue( 18 | JoursFeries.is_bank_holiday(date(2019, 12, 25), zone="Métropole") 19 | ) 20 | self.assertTrue( 21 | JoursFeries.is_bank_holiday(date(2019, 12, 26), zone="Alsace-Moselle") 22 | ) 23 | 24 | self.assertFalse(JoursFeries.is_bank_holiday(date(2019, 12, 26))) 25 | self.assertFalse( 26 | JoursFeries.is_bank_holiday(date(2019, 12, 26), zone="Métropole") 27 | ) 28 | 29 | def test_next_bank_holiday(self): 30 | self.assertEquals( 31 | ("11 novembre", date(2018, 11, 11)), 32 | JoursFeries.next_bank_holiday(date(2018, 11, 10)), 33 | ) 34 | 35 | self.assertEquals( 36 | ("11 novembre", date(2018, 11, 11)), 37 | JoursFeries.next_bank_holiday(date(2018, 11, 11), zone="Métropole"), 38 | ) 39 | 40 | self.assertEquals( 41 | ("Jour de Noël", date(2018, 12, 25)), 42 | JoursFeries.next_bank_holiday(date(2018, 12, 11), zone="Métropole"), 43 | ) 44 | 45 | def test_for_year(self): 46 | self.assertDictEqual( 47 | JoursFeries.for_year(2018), 48 | { 49 | "1er janvier": date(2018, 1, 1), 50 | "Lundi de Pâques": date(2018, 4, 2), 51 | "1er mai": date(2018, 5, 1), 52 | "8 mai": date(2018, 5, 8), 53 | "Ascension": date(2018, 5, 10), 54 | "Lundi de Pentecôte": date(2018, 5, 21), 55 | "14 juillet": date(2018, 7, 14), 56 | "Assomption": date(2018, 8, 15), 57 | "Toussaint": date(2018, 11, 1), 58 | "11 novembre": date(2018, 11, 11), 59 | "Jour de Noël": date(2018, 12, 25), 60 | }, 61 | ) 62 | 63 | self.assertDictEqual( 64 | JoursFeries.for_year(2020), 65 | { 66 | "11 novembre": date(2020, 11, 11), 67 | "Ascension": date(2020, 5, 21), 68 | "Assomption": date(2020, 8, 15), 69 | "14 juillet": date(2020, 7, 14), 70 | "1er mai": date(2020, 5, 1), 71 | "1er janvier": date(2020, 1, 1), 72 | "Lundi de Pâques": date(2020, 4, 13), 73 | "Jour de Noël": date(2020, 12, 25), 74 | "Lundi de Pentecôte": date(2020, 6, 1), 75 | "Toussaint": date(2020, 11, 1), 76 | "8 mai": date(2020, 5, 8), 77 | }, 78 | ) 79 | 80 | def test_for_year_in_alsace(self): 81 | self.assertDictEqual( 82 | JoursFeries.for_year(2018, zone="Alsace-Moselle"), 83 | { 84 | "11 novembre": date(2018, 11, 11), 85 | "Ascension": date(2018, 5, 10), 86 | "Assomption": date(2018, 8, 15), 87 | "14 juillet": date(2018, 7, 14), 88 | "1er mai": date(2018, 5, 1), 89 | "1er janvier": date(2018, 1, 1), 90 | "Lundi de Pâques": date(2018, 4, 2), 91 | "Jour de Noël": date(2018, 12, 25), 92 | "Lundi de Pentecôte": date(2018, 5, 21), 93 | "Toussaint": date(2018, 11, 1), 94 | "8 mai": date(2018, 5, 8), 95 | "Vendredi saint": date(2018, 3, 30), 96 | "2ème jour de Noël": date(2018, 12, 26), 97 | }, 98 | ) 99 | 100 | self.assertDictEqual( 101 | JoursFeries.for_year(2020, zone="Alsace-Moselle"), 102 | { 103 | "11 novembre": date(2020, 11, 11), 104 | "Ascension": date(2020, 5, 21), 105 | "Assomption": date(2020, 8, 15), 106 | "14 juillet": date(2020, 7, 14), 107 | "1er mai": date(2020, 5, 1), 108 | "1er janvier": date(2020, 1, 1), 109 | "Lundi de Pâques": date(2020, 4, 13), 110 | "Jour de Noël": date(2020, 12, 25), 111 | "Lundi de Pentecôte": date(2020, 6, 1), 112 | "Toussaint": date(2020, 11, 1), 113 | "8 mai": date(2020, 5, 8), 114 | "Vendredi saint": date(2020, 4, 10), 115 | "2ème jour de Noël": date(2020, 12, 26), 116 | }, 117 | ) 118 | 119 | def testPaques(self): 120 | self.assertEquals(JoursFeries.paques(1954), date(1954, 4, 18)) 121 | self.assertEquals(JoursFeries.paques(1981), date(1981, 4, 19)) 122 | self.assertEquals(JoursFeries.paques(2049), date(2049, 4, 18)) 123 | 124 | def testNamesAllZones(self): 125 | def names(holidays): 126 | return set(holidays.keys()) 127 | 128 | base = set( 129 | [ 130 | "1er janvier", 131 | "1er mai", 132 | "8 mai", 133 | "14 juillet", 134 | "Assomption", 135 | "Toussaint", 136 | "11 novembre", 137 | "Jour de Noël", 138 | "Lundi de Pâques", 139 | "Ascension", 140 | "Lundi de Pentecôte", 141 | ] 142 | ) 143 | 144 | extra_holidays = [ 145 | ["Alsace-Moselle", set(["Vendredi saint", "2ème jour de Noël"])], 146 | ["Guadeloupe", set(["Abolition de l'esclavage"])], 147 | ["Guyane", set(["Abolition de l'esclavage"])], 148 | ["Martinique", set(["Abolition de l'esclavage"])], 149 | ["Mayotte", set(["Abolition de l'esclavage"])], 150 | ["Nouvelle-Calédonie", set()], 151 | ["La Réunion", set(["Abolition de l'esclavage"])], 152 | ["Polynésie Française", set()], 153 | ["Saint-Barthélémy", set(["Abolition de l'esclavage"])], 154 | ["Saint-Martin", set(["Abolition de l'esclavage"])], 155 | ["Wallis-et-Futuna", set()], 156 | ["Saint-Pierre-et-Miquelon", set()], 157 | ] 158 | 159 | self.assertSetEqual(names(JoursFeries.for_year(2020, "Métropole")), base) 160 | 161 | for test in extra_holidays: 162 | zone, holidays = test 163 | self.assertEquals( 164 | names(JoursFeries.for_year(2020, zone)), base.union(holidays) 165 | ) 166 | 167 | self.assertEquals( 168 | JoursFeries.ZONES, ["Métropole"] + [e[0] for e in extra_holidays] 169 | ) 170 | 171 | def testAbolition_esclavage(self): 172 | tests = [ 173 | ("Mayotte", date(2020, 4, 27)), 174 | ("Martinique", date(2020, 5, 22)), 175 | ("Guadeloupe", date(2020, 5, 27)), 176 | ("Saint-Martin", date(2020, 5, 28)), 177 | ("Guyane", date(2020, 6, 10)), 178 | ("Saint-Barthélémy", date(2020, 10, 9)), 179 | ("La Réunion", date(2020, 12, 20)), 180 | ] 181 | 182 | zones = set() 183 | for test in tests: 184 | zone, expected_date = test 185 | zones.add(zone) 186 | self.assertEquals( 187 | JoursFeries.abolition_esclavage(2020, zone), expected_date 188 | ) 189 | 190 | for zone in [z for z in JoursFeries.ZONES if z not in zones]: 191 | self.assertEquals(JoursFeries.abolition_esclavage(2020, zone), None) 192 | 193 | # Saint-Martin 194 | self.assertEquals( 195 | JoursFeries.abolition_esclavage(2017, "Saint-Martin"), date(2017, 5, 27) 196 | ) 197 | self.assertEquals( 198 | JoursFeries.abolition_esclavage(2018, "Saint-Martin"), date(2018, 5, 28) 199 | ) 200 | 201 | # Gestion des dates antérieures au décret officiel relatif à la commémoration de l'abolition de l'esclavage 202 | # https://www.legifrance.gouv.fr/loda/id/JORFTEXT000000336997/ 203 | 204 | # Mayotte 205 | self.assertEquals( 206 | JoursFeries.abolition_esclavage(1982, "Mayotte"), None 207 | ) 208 | self.assertEquals( 209 | JoursFeries.abolition_esclavage(1983, "Mayotte"), date(1983, 4, 27) 210 | ) 211 | 212 | # Martinique 213 | self.assertEquals( 214 | JoursFeries.abolition_esclavage(1982, "Martinique"), None 215 | ) 216 | self.assertEquals( 217 | JoursFeries.abolition_esclavage(1983, "Martinique"), date(1983, 5, 22) 218 | ) 219 | 220 | # Guadeloupe 221 | self.assertEquals( 222 | JoursFeries.abolition_esclavage(1982, "Guadeloupe"), None 223 | ) 224 | self.assertEquals( 225 | JoursFeries.abolition_esclavage(1983, "Guadeloupe"), date(1983, 5, 27) 226 | ) 227 | 228 | # Saint-Martin 229 | self.assertEquals( 230 | JoursFeries.abolition_esclavage(1982, "Saint-Martin"), None 231 | ) 232 | self.assertEquals( 233 | JoursFeries.abolition_esclavage(1983, "Saint-Martin"), date(1983, 5, 27) 234 | ) 235 | 236 | # Guyane 237 | self.assertEquals( 238 | JoursFeries.abolition_esclavage(1982, "Guyane"), None 239 | ) 240 | self.assertEquals( 241 | JoursFeries.abolition_esclavage(1983, "Guyane"), date(1983, 6, 10) 242 | ) 243 | 244 | # Saint-Barthélémy 245 | self.assertEquals( 246 | JoursFeries.abolition_esclavage(1982, "Saint-Barthélémy"), None 247 | ) 248 | self.assertEquals( 249 | JoursFeries.abolition_esclavage(1983, "Saint-Barthélémy"), date(1983, 10, 9) 250 | ) 251 | 252 | # La Réunion 253 | self.assertEquals( 254 | JoursFeries.abolition_esclavage(1980, "La Réunion"), None 255 | ) 256 | self.assertEquals( 257 | JoursFeries.abolition_esclavage(1981, "La Réunion"), date(1981, 12, 20) 258 | ) 259 | --------------------------------------------------------------------------------