Vacances en PL/pgsql

Pour le boulot, j'avais besoin de remplir une table avec les jours fériés d'une année. On me demandait surtout de récupérer les infos d'un fichier fourni par l'utilisateur. L'idée de concevoir un décodeur de fichier au format vCalendar m'amusait moyennement. L'idée de demander à mes clients d'enregistrer les jours fériés dans un fichier dont je fournissais le format me plaisait encore moins. Très facile pour moi, très gênant pour mes clients.

Bêtement, je me suis demandé si je ne pouvais pas calculer ces dates car je n'ai besoin que des jours fériés français. J'ai donc traîné un peu sur wikipedia. Avec cette page, j'ai constaté qu'à peu près tous les jours sont fixes, sauf deux fêtes religieuses : Pâques et l'Ascension. J'ai même trouvé un lien vers une formule mathématique permettant de calculer facilement ces dates.

J'ai commencé par écrire une procédure stockée pour calculer la date du lundi de Pâques en ne lui fournissant que l'année :

create or replace function paques(annee integer) returns timestamp as $$
declare
  a integer;
  b integer;
  r date;
begin
a := (19*(annee % 19) + 24) % 30;
b := (2*(annee % 4) + 4*(annee % 7) + 6*a + 5) % 7;
select (annee::text||'-03-31')::date + (a+b-9) into r;
return r;
end;
$$ language plpgsql;

Puis, une pour l'ascension (jeudi de la semaine des 40 jours après Pâques, d'où l'utilisation de la procédure stockée précédente) :

create or replace function ascension(annee integer) returns timestamp as $$
declare
  r    date;
begin
select paques(annee)::date + 40 into r;
select r + (4 - extract(dow from r))::integer into r;
return r;
end;
$$ language plpgsql;

Enfin, j'ai ajouté une procédure qui enregistre tous jours fériés français d'une année en lui indiquant l'année, si on souhaite supprimer les jours fériés déjà saisis pour cette année et si on habite en Alsace ou en Moselle (ces deux départements disposent de deux jours fériés supplémentaires... chanceux :) ) :

create or replace function vacances(annee integer, supp_anciens boolean, alsace_moselle boolean) returns boolean as $$
declare
  f integer;
begin
-- on regarde s'il existe déjà des jours fériés dans la table pour cette année
select fid into f from feries where date_part('year', fdate)=annee;
if found then
  -- soit on les supprime, soit on quitte sans rien faire
  if supp_anciens then
    delete from feries where date_part('year', fdate)=annee;
  else
    return false;
  end if;
end if;

-- on insère les éléments nécessaires
insert into feries (flibelle, fdate) values ('Jour de l''an'::text, (annee::text||'-01-01')::date);
insert into feries (flibelle, fdate) values ('Pâques'::text, paques(annee)::date + 1);
insert into feries (flibelle, fdate) values ('Ascension'::text, ascension(annee)::date);
insert into feries (flibelle, fdate) values ('Fête du travail'::text, (annee::text||'-05-01')::date);
insert into feries (flibelle, fdate) values ('Victoire 1945'::text, (annee::text||'-05-08')::date);
insert into feries (flibelle, fdate) values ('Fête nationale'::text, (annee::text||'-07-14')::date);
insert into feries (flibelle, fdate) values ('Assomption'::text, (annee::text||'-08-15')::date);
insert into feries (flibelle, fdate) values ('La toussaint'::text, (annee::text||'-11-01')::date);
insert into feries (flibelle, fdate) values ('Armistice 1918'::text, (annee::text||'-11-11')::date);
insert into feries (flibelle, fdate) values ('Noël'::text, (annee::text||'-12-25')::date);

-- insertion des deux jours supplémentaires dans le cas de l'Alsace et la Moselle
if alsace_moselle then
  insert into feries (flibelle, fdate) values ('Vendredi saint'::text, paques(annee)::date - 2);
  insert into feries (flibelle, fdate) values ('Lendemain de Noël'::text, (annee::text||'-12-26')::date);
end if;

return true;
end;
$$ language plpgsql;

La valeur renvoyée indique si des données ont été insérées ou non.

Commentaires

1. Le mercredi, février 8 2006, 09:03 par christophe

Chouette, ça me rappelle mes cours de PL/SQL ;)

J'imagine que tu vas écrire d'autres fonctions ou des triggers qui appelleront eux-même la fonction vacances ?

2. Le mercredi, février 8 2006, 20:08 par Guillaume Lelarge

En fait, mon interface permet de saisir une année. Je n'ai plus qu'à faire un simple "select vacances(2005);" (avec 2005 comme exemple d'année saisie) et tout est inséré automatiquement.

J'aurais pû tout mettre au niveau du client au prix de plusieurs allers/retours entre le client et la base de données (pas bien grave). J'ai surtout écrit ces fonctions pour m'amuser et tester certaines choses.

3. Le lundi, avril 16 2007, 11:11 par fab

Bonjour,
Ton calcul des jours fériés m'a interessé;
Aurais-tu les mêmes fonctions en PL/SQL ?
Ou mieux, aurais-tu disponibles une table avec les jours fériés de 2001 à 2099 par exemple ?
Merci

4. Le mardi, avril 17 2007, 00:06 par Guillaume Lelarge

Ni l'un ni l'autre, désolé.

Ajouter un commentaire

Les commentaires peuvent être formatés en utilisant une syntaxe wiki simplifiée.

Fil des commentaires de ce billet