(refonte complète de la page le 13/10/2009)
La date de Pâques est assez complexe à calculer et encore plus à comprendre. Mais elle est importante pour calculer les jours fériés qui y sont liés.
Les différentes méthodes sont ici: http://users.chariot.net.au/~gmarts/eastalg.htm
J'ai choisi de programmer la méthode Hodges: http://users.chariot.net.au/~gmarts/eastalg.htm#EasterHodges
J'ai vérifié ensuite avec toutes les dates ici: http://www.dioceserimouski.com/ch/paquesdates.html
Ce calcul n'est valable que pour le calendrier grégorien avec des dates comprises entre 1583 et 4100 (ce qui devrait suffire pour les jours fériés ).
Codage:
def datepaques(an): """Calcule la date de Pâques d'une année donnée an (=nombre entier)""" a=an//100 b=an%100 c=(3*(a+25))//4 d=(3*(a+25))%4 e=(8*(a+11))//25 f=(5*a+b)%19 g=(19*f+c-e)%30 h=(f+11*g)//319 j=(60*(5-d)+b)//4 k=(60*(5-d)+b)%4 m=(2*j-k-g+h)%7 n=(g-h+m+114)//31 p=(g-h+m+114)%31 jour=p+1 mois=n return [jour, mois, an] # Exemple d'utilisation: print paques(2008) # affiche [23, 3, 2008]
L'année voulue est toujours donnée en année complète (type 2008) et pas en raccourcis (type 08).
Il ensuite facile de calculer les dates des jours fériés France avec une fonction qui ajoute et retranche les dates:
Jeudi de l'ascension = Pâques +39
Lundi de Pentecôte = Pâques + 50
Etc…
Les calculs internes avec les dates se font en date-liste d=[13,10,2009] pour éviter les conversions inutiles. Mais on a besoin de fonction de conversion pour:
1er cas: J'ai une date sous forme de chaîne de caractères c=“13/10/2009”, je veux la transformer en date liste: d=[13,10,2009]:
def dateliste(c, sep='/'): """Transforme une date chaîne 'j/m/a' en une date liste [j,m,a]""" j, m, a = c.split(sep) return [int(j), int(m), int(a)]
Et le contraire: j'ai une date-liste d=[13,10,2009] et je veux la transformer en date-chaîne c=“13/10/2009”
def datechaine(d, sep='/'): """Transforme une date liste=[j,m,a] en une date chaîne 'jj/mm/aaaa'""" return ("%02d" + sep + "%02d" + sep + "%0004d") % (d[0], d[1], d[2])
Dans les 2 cas, on peut préciser le séparateur qui est '/' par défaut. Avec cela, on peut convertir “13/10/2009” ou “13-10-2009” ou “13:10:2009” ou avec n'importe quel autre séparateur.
Les 2 codes suivants permettent d'additionner ou de soustraire un certain nombre de jours à une date donnée, et de trouver la nouvelle date.
Ces codes ne sont pas très subtils (calcul jour par jour) mais ils sont faciles à comprendre et sont suffisamment rapides ici.
Fonction pour additionner n jours (n>=0) à la date d=[j,m,a]:
def jourplus(d, n=1): """Donne la date du nième jour suivant d=[j, m, a] (n>=0)""" j, m, a = d fm = [0,31,28,31,30,31,30,31,31,30,31,30,31] if (a%4==0 and a%100!=0) or a%400==0: # bissextile? fm[2] = 29 for i in xrange(0,n): j += 1 if j > fm[m]: j = 1 m += 1 if m>12: m = 1 a += 1 return [j,m,a]
Fonction pour soustraire n jours (n<=0) à la date d=[j,m,a]:
def jourmoins(d, n=-1): """Donne la date du nième jour précédent d=[j, m, a] (n<=0)""" j, m, a = d fm = [0,31,28,31,30,31,30,31,31,30,31,30,31] if (a%4==0 and a%100!=0) or a%400==0: # bissextile? fm[2] = 29 for i in xrange(0,abs(n)): j -= 1 if j < 1: m -= 1 if m<1: m = 12 a -= 1 j = fm[m] return [j,m,a]
Le but est de dire si une date donnée d=[j,m,a] est un lundi, mardi, …
J'ai choisi l'algorithme de Maurice Kraitchik (1882–1957), et je l'ai trouvé ici: http://cosmos2000.chez.com/Vendredi13/KraitchikMethode.html.
La 1ère fonction donne le numéro du jour de semaine (1 pour lundi, 2 pour mardi, …, 7 pour dimanche).
La seconde fonction renvoie le jour de semaine en texte. Ex: “Mercredi” pour n=3.
def numjoursem(d): """Donne le numéro du jour de la semaine d'une date d=[j,m,a] lundi=1, mardi=2, ..., dimanche=7 Algorithme de Maurice Kraitchik (1882–1957)""" j, m, a = d if m<3: m += 12 a -= 1 n = (j +2*m + (3*(m+1))//5 +a + a//4 - a//100 + a//400 +2) % 7 return [6, 7, 1, 2, 3, 4, 5][n] def joursem(d): """Donne le jour de semaine en texte à partir de son numéro lundi=1, mardi=2, ..., dimanche=7""" return ["", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi", "dimanche"][numjoursem(d)]
Voilà. On a toutes les fonctions nécessaires pour calculer les jours fériés!
Ma référence pour les jours fériés France: http://fr.wikipedia.org/wiki/F%C3%AAtes_et_jours_f%C3%A9ri%C3%A9s_en_France
Les fonctions ci-dessous renvoient la liste des jours fériés France à partir d'une année quelconque.
Ces fonctions utilisent uniquement les fonctions décrites ci-dessus sur cette page
Le 2ème paramètre numérique est optionnel:
Vous pouvez adapter les jours fériés selon votre situation, région, pays, besoins et évolution de la législation.
Pour ce qui concerne le lundi de la Pentecôte, vous faites comme vous avez compris…
J'ai découpé en 2 fonctions:
L'avantage de ce découpage en 2 fonctions est qu'on peut utiliser la 1ère fonction pour d'autres calculs.
Pour la seconde fonction, on peut préciser le séparateur à utiliser pour stocker la date sous forme de date-chaine ('/' par défaut)
Première fonction
def joursferiesliste(an, sd=0): """Liste des jours fériés France en date-liste de l'année an (nb entier). sd=0 (=defaut): tous les jours fériés. sd=1: idem sans les sammedis-dimanches. sd=2: tous + les 2 jours fériés supplémentaires d'Alsace-Moselle. sd=3: idem sd=2 sans les samedis-dimanches""" F = [] # =liste des dates des jours feries en date-liste d=[j,m,a] L = [] # =liste des libelles du jour ferie dp = datepaques(an) # Jour de l'an d = [1,1,an] nj = numjoursem(d) if (sd==0) or (sd==1 and nj<6) or (sd==2) or (sd==3 and nj<6): F.append(d) L.append(u"Jour de l'an") # Vendredi saint (pour l'Alsace-Moselle) d = jourmoins(dp, -2) if sd>=2: F.append(d) L.append(u"Vendredi saint") # Dimanche de Paques d = dp if (sd==0) or (sd==2): F.append(d) L.append(u"Dimanche de Pâques") # Lundi de Paques d = jourplus(dp, +1) F.append(d) L.append(u"Lundi de Pâques") # Fête du travail d = [1,5,an] nj = numjoursem(d) if (sd==0) or (sd==1 and nj<6) or (sd==2) or (sd==3 and nj<6): F.append(d) L.append(u"Fête du travail") # Victoire des allies 1945 d = [8,5,an] nj = numjoursem(d) if (sd==0) or (sd==1 and nj<6) or (sd==2) or (sd==3 and nj<6): F.append(d) L.append(u"Victoire des alliés 1945") # Jeudi de l'Ascension d = jourplus(dp, +39) F.append(d) L.append(u"Jeudi de l'Ascension") # Dimanche de Pentecote d = jourplus(dp, +49) if (sd==0) or (sd==2): F.append(d) L.append(u"Dimanche de Pentecôte") # Lundi de Pentecote d = jourplus(d, +1) F.append(d) L.append(u"Lundi de Pentecôte") # Fete Nationale d = [14,7,an] nj = numjoursem(d) if (sd==0) or (sd==1 and nj<6) or (sd==2) or (sd==3 and nj<6): F.append(d) L.append(u"Fête Nationale") # Assomption d = [15,8,an] nj = numjoursem(d) if (sd==0) or (sd==1 and nj<6) or (sd==2) or (sd==3 and nj<6): F.append(d) L.append(u"Assomption") # Toussaint d = [1,11,an] nj = numjoursem(d) if (sd==0) or (sd==1 and nj<6) or (sd==2) or (sd==3 and nj<6): F.append(d) L.append(u"Toussaint") # Armistice 1918 d = [11,11,an] nj = numjoursem(d) if (sd==0) or (sd==1 and nj<6) or (sd==2) or (sd==3 and nj<6): F.append(d) L.append(u"Armistice 1918") # Jour de Noel d = [25,12,an] nj = numjoursem(d) if (sd==0) or (sd==1 and nj<6) or (sd==2) or (sd==3 and nj<6): F.append(d) L.append(u"Jour de Noël") # Saint Etienne (pour l'Alsace-Moselle) d = [26,12,an] nj = numjoursem(d) if (sd==2) or (sd==3 and nj<6): F.append(d) L.append(u"Saint Etienne") return F, L
Seconde fonction:
def joursferies(an, sd=0, sep='/'): """Liste des jours fériés France en date-chaine de l'année an (nb entier). sd=0 (=defaut): tous les jours fériés. sd=1: idem sans les sammedis-dimanches. sd=2: tous + les 2 jours fériés supplémentaires d'Alsace-Moselle. sd=3: idem sd=2 sans les samedis-dimanches""" C = [] J = [] F, L = joursferiesliste(an, sd) for i in xrange(0,len(F)): C.append(datechaine(F[i])) # conversion des dates-liste en dates-chaine J.append(joursem(F[i])) # ajout du jour de semaine return C, J, L
Exemple d'utilisation: tous les jours fériés (sd=0, valeur par défaut)
F, J, L = joursferies(2009,0,'/') for i in xrange(0,len(F)): print F[i], "%10s" % (J[i]), L[i]
Ce qui affiche:
01/01/2009 jeudi Jour de l'an 12/04/2009 dimanche Dimanche de Pâques 13/04/2009 lundi Lundi de Pâques 01/05/2009 vendredi Fête du travail 08/05/2009 vendredi Victoire des alliés 1945 21/05/2009 jeudi Jeudi de l'Ascension 31/05/2009 dimanche Dimanche de Pentecôte 01/06/2009 lundi Lundi de Pentecôte 14/07/2009 mardi Fête Nationale 15/08/2009 samedi Assomption 01/11/2009 dimanche Toussaint 11/11/2009 mercredi Armistice 1918 25/12/2009 vendredi Jour de Noël
Et sans les samedis-dimanches (sd=1):
F, J, L = joursferies(2009,1,'/') for i in xrange(0,len(F)): print F[i], "%10s" % (J[i]), L[i]
Ce qui affiche:
01/01/2009 jeudi Jour de l'an 13/04/2009 lundi Lundi de Pâques 01/05/2009 vendredi Fête du travail 08/05/2009 vendredi Victoire des alliés 1945 21/05/2009 jeudi Jeudi de l'Ascension 01/06/2009 lundi Lundi de Pentecôte 14/07/2009 mardi Fête Nationale 11/11/2009 mercredi Armistice 1918 25/12/2009 vendredi Jour de Noël
Dit si une date d=[j,m,a] est fériée France:
Le paramètre sd a la même signification que précédemment, mais il ne faut pas se tromper avec la date qu'on donne: si on met un jour férié tombant un samedi avec sd=1, le verdict sera: non férié.
def estferie(d,sd=0): """estferie(d,sd=0): => dit si une date d=[j,m,a] donnée est fériée France si la date est fériée, renvoie son libellé sinon, renvoie une chaine vide""" j,m,a = d F, L = joursferiesliste(a, sd) for i in xrange(0, len(F)): if j==F[i][0] and m==F[i][1] and a==F[i][2]: return L[i] return ""
Exemple d'utilisation:
print estferie([1,1,2009]) Jour de l'an print estferie([2,1,2009]) <= chaine vide print estferie([10,4,2009],sd=3) Vendredi saint
Le principe est simple: on part d'une 1ère date d1, et on teste toutes les dates une à une jusqu'à d2. On incrémente un compteur uniquement si la date testée n'est ni un samedi, ni un dimanche, ni un jour férié. On renvoie le compteur à la fin
def nbjoursouvres(d1,d2,sd=1): """Calcule le nombre de jours ouvrés entre 2 dates (format d=[j,m,a]). d1 doit être une date antérieure à d2 d1 et d2, bornes de l'intervalle d1->d2, sont testés sd==1: élimination des samedis, dimanches et jours fériés sd==3: idem pour l'Alsace-Moselle sd=0 et sd=2 n'ont pas de sens ici """ j1, m1, a1 = d1 j2, m2, a2 = d2 F, L = joursferiesliste(a1, sd) n = 0 d = [j1, m1, a1] while True: if (d not in F) and numjoursem(d)<6: n += 1 if d[0]==j2 and d[1]==m2 and d[2]==a2: break d = jourplus(d, +1) if d[2]!=a2: a2 = d[2] F, L = joursferiesliste(a2, sd) return n
Exemple:
print nbjoursouvres([29,4,2009],[5,5,2009],sd=1) 4 print nbjoursouvres([24,12,2009],[2,1,2010],sd=1) 5