La saisie et les requêtes de dates pour la prosopographie (1ère partie)

Avertissement : Cet article est en cours de rédaction mais il est publié pour permettre une discussion sur ce sujet.

Depuis 2012, date de mon arrivée à l’UMS, je travaille avec deux enseignantes-chercheuses de Celtique, Mannaig Thomas et Nelly Blanchard à une base de données prosopographique des auteurs de langue bretonne. Cette base de données a été créée dans le cadre du projet PRELIB dont une des ambitions est de comprendre les raisons qui ont poussé des personnes à écrire et à publier en breton. En effet, écrire en breton, langue de tradition orale, ne va pas de soi et résulte d’un choix qui peut être influencé par la fréquentation de personnes rencontrées dans des lieux de sociabilité tels que des cercles littéraires, des associations ou des mouvements politiques.

La base contient des informations du type : François Jaffrennou est né le 15 mars 1879 à Carnoët, il a étudié au Collège Notre-Dame-de-Bon-Secours à Guingamp vers 1891 puis a débuté des études de droit à Rennes en 1899. Il a contribué aux revues An Oaled, War Sao, Buez Breiz. Il a été secrétaire de la section Langue et Littérature Bretonne de l’Union Régionaliste Bretonne à partir du 14 aout 1898. Il est l’auteur de Oberou yaouankiz, Ganedigez eun emzao, Le dictionnaire français-breton de poche.

Dans cette base de données relationnelle, conçue avec mySQL, la plupart des dates (par ex. une date de naissance) ne sont pas saisies dans un seul champ sous la forme d’une date complète (un jour, un mois, une année) mais dans trois champs séparant la saisie du jour, du mois et de l’année. Du point de vue du stockage, les dates ne sont pas stockées au format SQL DATE mais dans trois champs SQL de type INTEGER (un chiffre entier).

Les bases de données relationnelles ne permettent pas la saisie d’intervalles de temps. Elles ne permettent la saisie de données temporelles que sous la forme de dates (avec obligatoirement un jour, un mois, une année). Or les données historiques sont souvent imprécises et il n’est pas rare que l’on ne connaisse pas la date complète d’un événement (une date de naissance, la date à laquelle un individu a été élu président d’une association, etc.). La séparation de la saisie a donc été envisagée sous la forme de trois champs séparés pour le jour, le mois et l’année en attendant de trouver une solution plus orthodoxe.

Dans les bases de données SQL, les données de type date sont stockées au format aaaa-mm-jj (je parle bien ici du stockage dans la base et non pas de la saisie, le stockage dans ce format n’empêchant pas la saisie dans un formulaire web de dates au format français jj/mm/aaaa). La date du 3 juillet 1896 sera donc stockée sous la forme 1896-07-03.

On pourrait alors envisager de stocker une date incomplète en remplaçant le jour ou le mois par des zéros. Par exemple, si l’on sait que la personne est née en 1896 sans aucune précision sur le mois ou le jour de naissance, on pourrait stocker la date 1896-00-00 dans la base. Et si l’on sait au moins qu’elle est née en juillet 1896 de stocker la date 1896-07-00.

Mais cette solution amène d’autres problèmes : Premièrement, Django, le framework qui sert à élaborer les formulaires de saisie de notre base ne permet pas la saisie de dates non « valides » et l’adaptation de Django pour ajouter cette fonctionnalité ne semble pas chose aisée (Tout du moins si l’on en juge par la question How to deal with “partial” dates (2010-00-00) from MySQL in Django? posée sur le site de questions-réponses Stack Overflow en juin 2010).

Deuxièmement, il faudrait aussi adapter Django pour l’affichage des dates incomplètes. Car une personne souhaitant consulter la base comprendra peut-être qu’une personne est née en juillet 1896 mais comprendra moins l’affichage de 1896-07-00 ou 00/07/1896.

D’autre part les requêtes dans la base ne donnent pas des résultats attendus. En partant de la table prelib_participe_collectif qui stocke les participations d’individus à des collectifs, j’ai saisi des dates d’entrées dont certaines sont incomplètes (la saisie a été faite directement dans la base avec phpMyAdmin, sans passer par Django) : 0000-05-03 (le 3 mai d’une année indéterminée ?), 1898-08-14, 1959-00-00 (l’année 1959 ?), 1959-05-00 (le mois de mai 1959 ?), 1959-06-08, 2015-08-09.

Or la requête qui devrait permettre de récupérer les dates d’entrées dans des collectifs postérieures au 16 mai 1959 ne renvoie que 1959-06-08 et 2015-08-09 :

SELECT `date_entree`
FROM `prelib_participe_collectif`
WHERE `date_entree` > ‘1959-05-16’
ORDER BY `id_participe_collectif`

Alors que la requête qui devrait permettre de récupérer les dates d’entrées dans les collectifs antérieures au 16 mai 1959 renvoie les dates 0000-05-03, 1898-08-14, 1959-00-00, 1959-05-00 :

SELECT `id_participe_collectif`, `date_entree`
FROM `prelib_participe_collectif`
WHERE `date_entree` < ‘1959-05-16’
ORDER BY `id_participe_collectif`

Cela vient du fait que 1959-00-00 reste une date et n’est pas considérée par mySQL comme l’année 1959 soit une durée entre le 1er janvier 1959 à 0h et le 31 décembre 1959 à minuit. mySQL doit probablement comparer les années (1959 = 1959) puis les mois (00 < 05) puis les jours (00 < 16) de ces deux « dates » et en déduire que 1959-00-00 < 1959-05-16.

Ce qui amène à la constatation suivante : Les « dates » incomplètes sont en fait des durées (l’année 1959, le mois de mai 1959, d’avril à juin 1959). Il faudrait donc plutôt stocker une date de début et une date de fin quand on ne connait pas la date exacte d’un événement.

A ce propos, les développeurs de l’outil de création de bibliothèques numériques CollectiveAccess sont même allés plus loin puisqu’ils stockent toutes les métadonnées temporelles décrivant un document sous forme de durées. Ainsi la date du 7 juin 2007 est stockée sous la forme des deux dates (à la seconde près) du 7 juin 2007 à 00:00:00 et du 7 juin 2007 à 24:59:59. L’avantage de cette solution est que les deux dates sont stockées dans le format SQL TIMESTAMP prévu à cet effet. On bénéficie alors de tous les avantages des requêtes sur les dates en SQL.

Ce changement de paradigme du stockage d’une date vers le stockage d’une durée change aussi les requêtes. On ne fait plus de requête pour trouver les dates d’entrées dans un collectif antérieures au 16 mai 1959 pour reprendre l’exemple précédent, mais pour trouver des intervalles de temps terminés avant l’intervalle de temps du 16 mai 1959 à 00:00:00 au 16 mai à 24:59:59 ou des intervalles de temps dans lequel le 16 mai 1959 est compris.

Que donneraient donc les requêtes SQL sur des dates uniquement stockées sous forme d’intervalles temporels ? Ne seront-elles pas trop complexes ?

Autre piste : Le stockage en RDF offre-t-il des avantages pour le stockage des dates et à quoi ressemblerai des requêtes sur des durées avec SPARQL ?