diff --git a/README.md b/README.md
index 603ac93dfc573fa974102faa0b599f345acff428..115ef229d80deeda244f79c51bd31fed0e9725fb 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,4 @@
-i
-#            ScoDoc - Gestion de la scolarité - Version ScoDoc 9
+# ScoDoc - Gestion de la scolarité - Version ScoDoc 9
 
 (c) Emmanuel Viennet 1999 - 2022 (voir LICENCE.txt).
 
@@ -9,39 +8,34 @@ Documentation utilisateur: <https://scodoc.org>
 
 ## Version ScoDoc 9
 
-La version ScoDoc 9 est parue en septembre 2021.
-Elle représente une évolution majeure du projet, maintenant basé sur 
-Flask (au lieu de Zope) et sur **python 3.9+**. 
+La version ScoDoc 9 est parue en septembre 2021. Elle représente une évolution
+majeure du projet, maintenant basé sur Flask (au lieu de Zope) et sur **python
+3.9+**.
 
-La version 9.0 s'efforce de reproduire presque à l'identique le fonctionnement 
+La version 9.0 s'efforce de reproduire presque à l'identique le fonctionnement
 de ScoDoc7, avec des composants logiciels différents (Debian 11, Python 3,
 Flask, SQLAlchemy, au lien de Python2/Zope dans les versions précédentes).
 
+### État actuel (nov 22)
 
+- 9.3.x est en production
+- le prochain jalon est 9.4. Voir branches sur gitea.
 
-### État actuel (26 jan 22)
-
- - 9.1.5x (master) reproduit l'ensemble des fonctions de ScoDoc 7 (donc pas de BUT), sauf: 
-    - ancien module "Entreprises" (obsolète) et ajoute la gestion du BUT.
-
- - 9.2 (branche dev92) est la version de développement.
-
- 
 ### Lignes de commandes
 
 Voir [https://scodoc.org/GuideConfig](le guide de configuration).
 
-
 ## Organisation des fichiers
 
 L'installation comporte les fichiers de l'application, sous `/opt/scodoc/`, et
 les fichiers locaux (archives, photos, configurations, logs) sous
 `/opt/scodoc-data`. Par ailleurs, il y a évidemment les bases de données
-postgresql et la configuration du système Linux. 
+postgresql et la configuration du système Linux.
 
 ### Fichiers locaux
-Sous `/opt/scodoc-data`, fichiers et répertoires appartenant à l'utilisateur `scodoc`. 
-Ils ne doivent pas être modifiés à la main, sauf certains fichiers de configuration sous 
+
+Sous `/opt/scodoc-data`, fichiers et répertoires appartenant à l'utilisateur `scodoc`.
+Ils ne doivent pas être modifiés à la main, sauf certains fichiers de configuration sous
 `/opt/scodoc-data/config`.
 
 Le répertoire `/opt/scodoc-data` doit être régulièrement sauvegardé.
@@ -62,7 +56,7 @@ Principaux contenus:
 
 Installer ScoDoc 9 normalement ([voir la doc](https://scodoc.org/GuideInstallDebian11)).
 
-Puis remplacer `/opt/scodoc` par un clone du git. 
+Puis remplacer `/opt/scodoc` par un clone du git.
 
     sudo su
     mv /opt/scodoc /opt/off-scodoc # ou ce que vous voulez
@@ -76,7 +70,7 @@ Puis remplacer `/opt/scodoc` par un clone du git.
 
     # Et donner ce répertoire à l'utilisateur scodoc:
     chown -R scodoc.scodoc /opt/scodoc
-    
+
 Il faut ensuite installer l'environnement et le fichier de configuration:
 
     # Le plus simple est de piquer le virtualenv configuré par l'installeur:
@@ -100,10 +94,10 @@ Avant le premier lancement, créer cette base ainsi:
     flask db upgrade
 
 Cette commande n'est nécessaire que la première fois (le contenu de la base
-est effacé au début de chaque test, mais son schéma reste) et aussi si des 
+est effacé au début de chaque test, mais son schéma reste) et aussi si des
 migrations (changements de schéma) ont eu lieu dans le code.
 
-Certains tests ont besoin d'un département déjà créé, qui n'est pas créé par les 
+Certains tests ont besoin d'un département déjà créé, qui n'est pas créé par les
 scripts de tests:
 Lancer au préalable:
 
@@ -117,24 +111,24 @@ Ou avec couverture (`pip install pytest-cov`)
 
     pytest --cov=app --cov-report=term-missing --cov-branch tests/unit/*
 
-
 #### Utilisation des tests unitaires pour initialiser la base de dev
-On peut aussi utiliser les tests unitaires pour mettre la base 
-de données de développement dans un état connu, par exemple pour éviter de
-recréer à la main étudiants et semestres quand on développe. 
 
-Il suffit de positionner une variable d'environnement indiquant la BD 
-utilisée par les tests:
+On peut aussi utiliser les tests unitaires pour mettre la base de données de
+développement dans un état connu, par exemple pour éviter de recréer à la main
+étudiants et semestres quand on développe.
+
+Il suffit de positionner une variable d'environnement indiquant la BD utilisée
+par les tests:
 
     export SCODOC_TEST_DATABASE_URI=postgresql:///SCODOC_DEV
 
 (si elle n'existe pas, voir plus loin pour la créer) puis de les lancer
-normalement, par exemple: 
+normalement, par exemple:
 
     pytest tests/unit/test_sco_basic.py
 
-Il est en général nécessaire d'affecter ensuite un mot de passe à (au moins) 
-un utilisateur:
+Il est en général nécessaire d'affecter ensuite un mot de passe à (au moins) un
+utilisateur:
 
     flask user-password admin
 
@@ -178,12 +172,10 @@ Pour la visualisation, [snakeviz](https://jiffyclub.github.io/snakeviz/) est bie
 
     pip install snakeviz
 
-puis 
+puis
 
     snakeviz -s --hostname 0.0.0.0 -p 5555 /opt/scodoc-data/GET.ScoDoc......prof 
 
-
-
 # Paquet Debian 11
 
 Les scripts associés au paquet Debian (.deb) sont dans `tools/debian`. Le plus
@@ -191,5 +183,4 @@ important est `postinst`qui se charge de configurer le système (install ou
 upgrade de scodoc9).
 
 La préparation d'une release se fait à l'aide du script
-`tools/build_release.sh`. 
-
+`tools/build_release.sh`.
diff --git a/app/api/departements.py b/app/api/departements.py
index b498cd66772baf40a3a207a5cf489e02389f35f2..066197d3f9d01b715a1d1779dea7c2e1069bfdd3 100644
--- a/app/api/departements.py
+++ b/app/api/departements.py
@@ -257,9 +257,9 @@ def dept_formsemestres_courants(acronym: str):
         ]
     """
     dept = Departement.query.filter_by(acronym=acronym).first_or_404()
-    faked_date = request.args.get("faked_date")
-    if faked_date:
-        test_date = datetime.fromisoformat(faked_date)
+    date_courante = request.args.get("date_courante")
+    if date_courante:
+        test_date = datetime.fromisoformat(date_courante)
     else:
         test_date = app.db.func.now()
     # Les semestres en cours de ce département
@@ -281,9 +281,9 @@ def dept_formsemestres_courants_by_id(dept_id: int):
     """
     # Le département, spécifié par un id ou un acronyme
     dept = Departement.query.get_or_404(dept_id)
-    faked_date = request.args.get("faked_date")
-    if faked_date:
-        test_date = datetime.fromisoformat(faked_date)
+    date_courante = request.args.get("date_courante")
+    if date_courante:
+        test_date = datetime.fromisoformat(date_courante)
     else:
         test_date = app.db.func.now()
     # Les semestres en cours de ce département
diff --git a/app/api/etudiants.py b/app/api/etudiants.py
index f8728f444e56882bfe096a9a3790c84a2f5461f9..fcafae68ce5e4ab231982084c3ed984077eac773 100644
--- a/app/api/etudiants.py
+++ b/app/api/etudiants.py
@@ -76,9 +76,9 @@ def etudiants_courants(long=False):
 
     """
     allowed_depts = current_user.get_depts_with_permission(Permission.ScoView)
-    faked_date = request.args.get("faked_date")
-    if faked_date:
-        test_date = datetime.fromisoformat(faked_date)
+    date_courante = request.args.get("date_courante")
+    if date_courante:
+        test_date = datetime.fromisoformat(date_courante)
     else:
         test_date = app.db.func.now()
     etuds = Identite.query.filter(
diff --git a/app/api/evaluations.py b/app/api/evaluations.py
index 5fe479f2b00155cb5cb3206690946fde124db7e6..a8fb2c26ccb88c493e8cba9c32df96a925805002 100644
--- a/app/api/evaluations.py
+++ b/app/api/evaluations.py
@@ -22,6 +22,44 @@ from app.scodoc.sco_permissions import Permission
 import app.scodoc.sco_utils as scu
 
 
+@bp.route("/evaluation/<int:evaluation_id>")
+@api_web_bp.route("/evaluation/<int:evaluation_id>")
+@login_required
+@scodoc
+@permission_required(Permission.ScoView)
+def evaluation(evaluation_id: int):
+    """Description d'une évaluation.
+
+    {
+              'coefficient': 1.0,
+              'date_debut': '2016-01-04T08:30:00',
+              'date_fin': '2016-01-04T12:30:00',
+              'description': 'TP NI9219 Température',
+              'evaluation_type': 0,
+              'id': 15797,
+              'moduleimpl_id': 1234,
+              'note_max': 20.0,
+              'numero': 3,
+              'poids': {
+                'UE1.1': 1.0,
+                'UE1.2': 1.0,
+                'UE1.3': 1.0
+              },
+              'publish_incomplete': False,
+              'visi_bulletin': True
+            }
+    """
+    query = Evaluation.query.filter_by(id=evaluation_id)
+    if g.scodoc_dept:
+        query = (
+            query.join(ModuleImpl)
+            .join(FormSemestre)
+            .filter_by(dept_id=g.scodoc_dept_id)
+        )
+    e = query.first_or_404()
+    return jsonify(e.to_dict_api())
+
+
 @bp.route("/moduleimpl/<int:moduleimpl_id>/evaluations")
 @api_web_bp.route("/moduleimpl/<int:moduleimpl_id>/evaluations")
 @login_required
@@ -33,39 +71,16 @@ def evaluations(moduleimpl_id: int):
 
     moduleimpl_id : l'id d'un moduleimpl
 
-    Exemple de résultat :
-        [
-          {
-            "moduleimpl_id": 1,
-            "jour": "20/04/2022",
-            "heure_debut": "08h00",
-            "description": "eval1",
-            "coefficient": 1.0,
-            "publish_incomplete": false,
-            "numero": 0,
-            "id": 1,
-            "heure_fin": "09h00",
-            "note_max": 20.0,
-            "visibulletin": true,
-            "evaluation_type": 0,
-            "evaluation_id": 1,
-            "jouriso": "2022-04-20",
-            "duree": "1h",
-            "descrheure": " de 08h00 à 09h00",
-            "matin": 1,
-            "apresmidi": 0
-          },
-          ...
-        ]
+    Exemple de résultat : voir /evaluation
     """
-    query = Evaluation.query.filter_by(id=moduleimpl_id)
+    query = Evaluation.query.filter_by(moduleimpl_id=moduleimpl_id)
     if g.scodoc_dept:
         query = (
             query.join(ModuleImpl)
             .join(FormSemestre)
             .filter_by(dept_id=g.scodoc_dept_id)
         )
-    return jsonify([d.to_dict() for d in query])
+    return jsonify([e.to_dict_api() for e in query])
 
 
 @bp.route("/evaluation/<int:evaluation_id>/notes")
diff --git a/app/api/formsemestres.py b/app/api/formsemestres.py
index e80da766a0333be4e63d679d8dd1cd91188277d5..38794d625e6d704ededf2146e8d307474465823e 100644
--- a/app/api/formsemestres.py
+++ b/app/api/formsemestres.py
@@ -398,7 +398,7 @@ def etat_evals(formsemestre_id: int):
         for evaluation_id in modimpl_results.evaluations_etat:
             eval_etat = modimpl_results.evaluations_etat[evaluation_id]
             evaluation = Evaluation.query.get_or_404(evaluation_id)
-            eval_dict = evaluation.to_dict()
+            eval_dict = evaluation.to_dict_api()
             eval_dict["etat"] = eval_etat.to_dict()
 
             eval_dict["nb_inscrits"] = modimpl_results.nb_inscrits_module
diff --git a/app/models/evaluations.py b/app/models/evaluations.py
index 04ed7dce5994a91bffc54c8cafbcd6c1bba045c0..71d54d82ed9b09493282e4db2e3c4f8315911663 100644
--- a/app/models/evaluations.py
+++ b/app/models/evaluations.py
@@ -51,7 +51,7 @@ class Evaluation(db.Model):
             self.description[:16] if self.description else ''}">"""
 
     def to_dict(self) -> dict:
-        "Représentation dict, pour json"
+        "Représentation dict (riche, compat ScoDoc 7)"
         e = dict(self.__dict__)
         e.pop("_sa_instance_state", None)
         # ScoDoc7 output_formators
@@ -71,6 +71,34 @@ class Evaluation(db.Model):
         e["poids"] = self.get_ue_poids_dict()  # { ue_id : poids }
         return evaluation_enrich_dict(e)
 
+    def to_dict_api(self) -> dict:
+        "Représentation dict pour API JSON"
+        if self.jour is None:
+            date_debut = None
+            date_fin = None
+        else:
+            date_debut = datetime.datetime.combine(
+                self.jour, self.heure_debut or datetime.time(0, 0)
+            ).isoformat()
+            date_fin = datetime.datetime.combine(
+                self.jour, self.heure_fin or datetime.time(0, 0)
+            ).isoformat()
+
+        return {
+            "coefficient": self.coefficient,
+            "date_debut": date_debut,
+            "date_fin": date_fin,
+            "description": self.description,
+            "evaluation_type": self.evaluation_type,
+            "id": self.id,
+            "moduleimpl_id": self.moduleimpl_id,
+            "note_max": self.note_max,
+            "numero": self.numero,
+            "poids": self.get_ue_poids_dict(),
+            "publish_incomplete": self.publish_incomplete,
+            "visi_bulletin": self.visibulletin,
+        }
+
     def from_dict(self, data):
         """Set evaluation attributes from given dict values."""
         check_evaluation_args(data)
@@ -227,7 +255,7 @@ def evaluation_enrich_dict(e: dict):
     heure_fin_dt = e["heure_fin"] or datetime.time(8, 00)
     e["heure_debut"] = ndb.TimefromISO8601(e["heure_debut"])
     e["heure_fin"] = ndb.TimefromISO8601(e["heure_fin"])
-    e["jouriso"] = ndb.DateDMYtoISO(e["jour"])
+    e["jour_iso"] = ndb.DateDMYtoISO(e["jour"])
     heure_debut, heure_fin = e["heure_debut"], e["heure_fin"]
     d = ndb.TimeDuration(heure_debut, heure_fin)
     if d is not None:
diff --git a/app/scodoc/sco_evaluation_db.py b/app/scodoc/sco_evaluation_db.py
index 7aec908896c75847dbd4a682c286557cbbc0334d..09873bbe17ee1be226c8d92c31cd459055c71123 100644
--- a/app/scodoc/sco_evaluation_db.py
+++ b/app/scodoc/sco_evaluation_db.py
@@ -93,7 +93,7 @@ def do_evaluation_list(args, sortkey=None):
     # Attention: transformation fonction ScoDoc7 en SQLAlchemy
     cnx = ndb.GetDBConnexion()
     evals = _evaluationEditor.list(cnx, args, sortkey=sortkey)
-    # calcule duree (chaine de car.) de chaque evaluation et ajoute jouriso, matin, apresmidi
+    # calcule duree (chaine de car.) de chaque evaluation et ajoute jour_iso, matin, apresmidi
     for e in evals:
         evaluation_enrich_dict(e)
 
diff --git a/tests/api/README.md b/tests/api/README.md
index c8ae788391c55554354a9d93e05454c2b31e7b1d..483da78af947fe9589cc27426e52ebf63155f0d8 100644
--- a/tests/api/README.md
+++ b/tests/api/README.md
@@ -1,18 +1,19 @@
 # Tests unitaires de l'API ScoDoc
 
-Démarche générale: 
+Démarche générale:
 
  1. On génère une base SQL de test: voir
    `tools/fakedatabase/create_test_api_database.py`
 
-    
-    1. modifier /opt/scodoc/.env pour indiquer 
+    1. modifier /opt/scodoc/.env pour indiquer
+
     ```
     FLASK_ENV=test_api
     FLASK_DEBUG=1 
     ```
 
     2. En tant qu'utilisateur scodoc, lancer:
+
     ```
     tools/create_database.sh --drop SCODOC_TEST_API
     flask db upgrade
@@ -25,17 +26,20 @@ Démarche générale:
     ```
 
  2. On lance le serveur ScoDoc sur cette base
+
     ```
     flask run --host 0.0.0.0
     ```
 
  3. On lance les tests unitaires API
+
 ```
     pytest tests/api/test_api_departements.py
 ```
 
 Rappel: pour interroger l'API, il fait avoir un utilisateur avec (au moins) la permission
 ScoView dans tous les départements. Pour en créer un:
+
 ```
  flask user-create lecteur_api LecteurAPI @all
  flask user-password lecteur_api
diff --git a/tests/api/make_samples.py b/tests/api/make_samples.py
index 57a7b477bcf382a40763056cdd158424abbf2f80..576f12633c5f40cea52d14b06d725fcd5f1b9e8f 100644
--- a/tests/api/make_samples.py
+++ b/tests/api/make_samples.py
@@ -115,7 +115,7 @@ class Sample:
         pp(self.result, indent=4)
 
     def dump(self, file):
-        self.url = self.url.replace("?faked_date=2022-07-20", "")
+        self.url = self.url.replace("?date_courante=2022-07-20", "")
 
         file.write(f"#### {self.method} {self.url}\n")
         if len(self.content) > 0:
diff --git a/tests/api/test_api_evaluations.py b/tests/api/test_api_evaluations.py
index 59ff3c050b80223bec6a933a4ee0f6c5862c32fc..383f5fe5d972847902c6ca311510b9ae865cfac2 100644
--- a/tests/api/test_api_evaluations.py
+++ b/tests/api/test_api_evaluations.py
@@ -46,26 +46,17 @@ def test_evaluations(api_headers):
     for eval in list_eval:
         assert verify_fields(eval, EVALUATIONS_FIELDS) is True
         assert isinstance(eval["id"], int)
-        assert isinstance(eval["jour"], str)
-        assert isinstance(eval["heure_fin"], str)
         assert isinstance(eval["note_max"], float)
-        assert isinstance(eval["visibulletin"], bool)
+        assert isinstance(eval["visi_bulletin"], bool)
         assert isinstance(eval["evaluation_type"], int)
         assert isinstance(eval["moduleimpl_id"], int)
-        assert isinstance(eval["heure_debut"], str)
         assert eval["description"] is None or isinstance(eval["description"], str)
         assert isinstance(eval["coefficient"], float)
         assert isinstance(eval["publish_incomplete"], bool)
         assert isinstance(eval["numero"], int)
-        assert isinstance(eval["evaluation_id"], int)
         assert eval["date_debut"] is None or isinstance(eval["date_debut"], str)
         assert eval["date_fin"] is None or isinstance(eval["date_fin"], str)
         assert isinstance(eval["poids"], dict)
-        assert eval["jouriso"] is None or isinstance(eval["jouriso"], str)
-        assert isinstance(eval["duree"], str)
-        assert isinstance(eval["descrheure"], str)
-        assert isinstance(eval["matin"], int)
-        assert isinstance(eval["apresmidi"], int)
 
         assert eval["moduleimpl_id"] == moduleimpl_id
 
diff --git a/tests/api/tools_test_api.py b/tests/api/tools_test_api.py
index 794095fe3abd172483128eccef7ec7c9ea95f15d..e3b1158a8ba938023d37d1820049cd23a30f0ee8 100644
--- a/tests/api/tools_test_api.py
+++ b/tests/api/tools_test_api.py
@@ -545,27 +545,17 @@ FORMSEMESTRE_ETUS_GROUPS_FIELDS = {
 }
 
 EVALUATIONS_FIELDS = {
-    "id",
-    "jour",
-    "heure_fin",
-    "note_max",
-    "visibulletin",
-    "evaluation_type",
-    "moduleimpl_id",
-    "heure_debut",
-    "description",
     "coefficient",
-    "publish_incomplete",
-    "numero",
-    "evaluation_id",
     "date_debut",
     "date_fin",
+    "description",
+    "evaluation_type",
+    "id",
+    "note_max",
+    "numero",
     "poids",
-    "jouriso",
-    "duree",
-    "descrheure",
-    "matin",
-    "apresmidi",
+    "publish_incomplete",
+    "visi_bulletin",
 }
 
 EVALUATION_FIELDS = {