jeudu 15 janvier 2026

Agenda minimaliste en HTML pur

Agenda très simple qui tient sur une seule page HTML sans les nuisances habituellement abondantes pour ce genre d'application.

Solution ultra simple

Préparatifs

Prenons ce petit fichier HTML :

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8>
<title></title>
</head>
<body>
    <b>jeudi 01 janvier 2026</b>
    <textarea name='0' rows='3' cols='75></textarea>
    <b>vendredi 02 janvier 2026</b>
    <textarea name='1' rows='3' cols='75></textarea>
    <b>samedi 03 janvier 2026</b>
</body>
</html>

Dans un navigateur, Firefox dans mon cas, on obtient ceci

jeudi 01 janvier 2026 vendredi 02 janvier 2026 samedi 03 janvier 2026

Sous chaque date on dispose d'une plage de saisie dans laquelle on peut ajouter, modifier ou supprimer du texte. Ensuite il suffit d'enregistrer le fichier, les modifications seront conservées.

L'inconvénient c'est qu'il faut écrire toutes les dates souhaitées et le code HTML qui va avec.

Fabrique du fichier annuel

Le code an.c est un petit programme qui prend pour argument un entier, l'année (e.g. an 2026) et produit un fichier html comme celui du paragraphe précédent pour tous les jours de l'année, chaque date est suivie de sa plage de saisie.

Programme C/Gtk

Toute honte bue, je dois avouer qu'au départ j'avais oublié l'existence du tag <textarea> si bien que je m'étais fendu d'un programme en C et Gtk4 que j'avais nommé plan dont le fichier source est là plan.c.

Comme ci dessus je préparais un fichier ne comprenant que les dates de l'année comme suit (sans les textarea, donc) :

<body>
    <h3 id="0>jeudi 01 janvier 20026</h3>
    <h3 id="1>vendredi 02 janvier 2026</h3>
    ...
    <h3 id="364>jeudi 31 décembre 20026</h3>
</body>

Merci à chatGPT pour la partie Gtk4.

Mon petit progrmme se lancait avec pour argument jj ou jj/mm ou jj//mm/yy qui est la date pour laquelle on veut éditer les informations. (Il prend le mois courant et/ou l'année courante si la date n'est pas complète.)

Il affiche alors une fenêtre comme ci-contre. Elle contient les informations déjà présentes pour la date considérée s'il y en a.

Une fois l'édition terminée, on clique sur le bouton OK pour enregistrer les modifications ou sur Cancel pour annuler.

La raison qui m'a amené à rédiger ce paragraphe peu glorieux, est que pour l'occasion j'avais codé une «librairie» que j'exposerai au paragraphe suivant.

Le module Day

Le module time.h m'énerve.

Dans la struct tm les jours du mois sont comptés de 1 à 31 mais les mois de 0 à 11. C'est d'une incohérence ! L'année à partir de 1900, mais la fonction time renvoie un entier long en secondes (pourquoi pas des nano secondes ?) mais à partir 1970. On perd son time à ajouter 126, ou 1 ou à les retrancher.

Si on veut utiliser le tm_wday ou tm_yday il ne faut pas négliger de faire un mktime. On perd aussi son temps dans les conversions entre les struct tm et time_t.

Depuis le temps que je me disais qu'il fallait faire une module pour les dates sans s'emmerder avec les heures d'hiver et d'été, sans diviser par 3600*24.

Voilà qui est fait cf. Day.h et Day.c.

Pour l'écrire je me suis inspiré des sources de python 3.14.

Voici l'interface Day.h :

#ifndef _MRD_DAY_H_
#define _MRD_DAY_H_
    
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
    
/**
    month day d ∈ [1, 31] or d ∈ [1, 30] or less for february
    montt m ∈ [1, 12]
    year y the full year
*/
typedef struct Day {
    int d, m, y;
} Day_t;
    
/**
Giving a string "" , "d", "d/m", "d/m/y" Day(s) sets a Day_t
Day("") is today
Uses the current data as defaults
*/
Day_t Day(char *);
    
/**
like tm_yday or toordinal in python
Returns the ordinal of the day in its year
*/
int Day_yday(Day_t day);
    
/*
The converse of Day_yday
*/
Day_t Day_from_yday(int, int);
    
/**
European string i.e. 'full day' 'day of the month' 'full month' 'full year'
e.g. 'Sunday 25 january 2026'
One can change it in the source Day.c
*/
char * Day_Str(Day_t, char*);
    
/**
    Day_str(day, s) => s = "25/01/2026"
    puts in s a kind of toString
    One can change the line strftime for his standard
*/
char * Day_str(Day_t day, char* s);
    
#endif

Et voilà mon petit programme pour tester ce code :

#include  "Day.h"
#include <locale.h>
#include <string.h>
    
// Ansi : Cyan, Rouge et Normaal
#define C "\e[0;36m"
#define R "\e[0;31m"
#define N "\e[m"
    
int main(int argc, char *argv[]) 
{
    setlocale(LC_TIME, "");
    char buf[128] = {0};
    int n;
    
    puts("\nEnter a day : '' | 'd' | 'd/m' | 'd/m/Y' or Ctrl-D to quit");
    
    while(printf("\n%sfgets(buf, 128, stdin)%s >\t\t", C, N) && 
                fgets(buf, 128, stdin)) {
        
        Day_t day = Day(buf);
        
        printf("Short day string %sDay_str()%s:\t\t%s\n", 
            C, N, Day_str(day, buf));
    
        printf("Full day string %sDay_Str()%s:\t\t%s\n", 
            C, N, Day_Str(day, buf));
    
        printf("Ordinal Day_yday :\t\t\t%s%d%s\n", 
            R, n = Day_yday(day), N);
    
        Day_t jour = Day_from_yday(n, day.y);
    
        printf("Recover this day from its ordinal(%s%d%s),\n", 
            R, n, N);
    
        printf("%sDay_from_yday()%s:\t\t\t%s\n", 
            C, N, Day_str(day, buf));
    
        printf("Let's check its ordinal:\t\t%s%d%s\n", 
            R, n = Day_yday(jour), N);
    
    }
}

J'ai surtout voulu tester que Day_yday et Day_from_yday fonctionnaient bien.

Sur github an et Day-in-C.




Réalisé avec Qlam - LGPL