diff --git a/app/api/assiduites.py b/app/api/assiduites.py
index 36d31d9b7f4b78ac2169f9e91bd9eeeb739b3608..0644aa8820eb8ba5a3563f9fe2aeffbaa5b4340c 100644
--- a/app/api/assiduites.py
+++ b/app/api/assiduites.py
@@ -5,7 +5,8 @@
 ##############################################################################
 """ScoDoc 9 API : Assiduités"""
 
-from datetime import datetime
+from datetime import datetime, timedelta
+import re
 
 from flask import g, request
 from flask_json import as_json
@@ -39,6 +40,24 @@ from app.scodoc.sco_permissions import Permission
 from app.scodoc.sco_utils import json_error
 
 
+@bp.route("/assiduite/date_time_offset/<string:date_iso>")
+@api_web_bp.route("/assiduite/date_time_offset/<string:date_iso>")
+@scodoc
+@permission_required(Permission.ScoView)
+def date_time_offset(date_iso: str):
+    """L'offset dans le fuseau horaire du serveur pour la date indiquée.
+    Renvoie une chaîne de la forme "+04:00" (ISO 8601)
+
+    Exemple: `/assiduite/date_time_offset/2024-10-01` renvoie `'+02:00'`
+    """
+    if not re.match(r"^\d{4}-\d{2}-\d{2}$", date_iso):
+        json_error(
+            404,
+            message="date invalide",
+        )
+    return scu.get_local_timezone_offset(date_iso)
+
+
 @bp.route("/assiduite/<int:assiduite_id>")
 @api_web_bp.route("/assiduite/<int:assiduite_id>")
 @scodoc
@@ -843,6 +862,10 @@ def _create_one(
     elif fin.tzinfo is None:
         fin: datetime = scu.localize_datetime(fin)
 
+    # check duration: min 1 minute
+    if (deb is not None) and (fin is not None) and (fin - deb) < timedelta(seconds=60):
+        errors.append("durée trop courte")
+
     # cas 4 : desc
     desc: str = data.get("desc", None)
 
diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py
index 50f767a4912b95c80dbce4492f464f000451b81a..5aeb45364245283b61096a6b150522b8d67a5fc9 100644
--- a/app/scodoc/sco_utils.py
+++ b/app/scodoc/sco_utils.py
@@ -441,12 +441,17 @@ def localize_datetime(date: datetime.datetime) -> datetime.datetime:
     return new_date
 
 
-def get_local_timezone_offset() -> str:
+def get_local_timezone_offset(date_iso: str | None = None) -> str:
     """Récupère l'offset de la timezone du serveur, sous la forme
-    "+HH:MM"
+    "+HH:MM", pour le jour indiqué (date courante par défaut).
+    Par exemple get_local_timezone_offset("2024-10-30") == "+01:00"
     """
-    local_time = datetime.datetime.now().astimezone()
-    utc_offset = local_time.utcoffset()
+    the_time = (
+        datetime.datetime.now()
+        if date_iso is None
+        else datetime.datetime.fromisoformat(date_iso)
+    )
+    utc_offset = the_time.astimezone().utcoffset()
     total_seconds = int(utc_offset.total_seconds())
     offset_hours = total_seconds // 3600
     offset_minutes = (abs(total_seconds) % 3600) // 60
diff --git a/app/static/js/assiduites.js b/app/static/js/assiduites.js
index 70eeb75659a0eb8c1c1cbb8d3f9b83a4a6c0335c..68a3bf9bcec399925e2877d81442e48da8a95831 100644
--- a/app/static/js/assiduites.js
+++ b/app/static/js/assiduites.js
@@ -460,6 +460,19 @@ async function creerTousLesEtudiants(etuds) {
     .forEach((etud, index) => {
       etudsDiv.appendChild(creerLigneEtudiant(etud, index + 1));
     });
+  // Récupère l'offset timezone serveur pour la date sélectionnée
+  const date_iso = getSelectedDateIso();
+  try {
+    const res = await fetch(`../../api/assiduite/date_time_offset/${date_iso}`);
+    if (!res.ok) {
+      throw new Error("Network response was not ok");
+    }
+    const text = await res.text();
+    console.log(text);
+    SERVER_TIMEZONE_OFFSET = text;
+  } catch (error) {
+    console.error('Error:', error);
+  }
 }
 
 /**
@@ -609,7 +622,7 @@ async function actionAssiduite(etud, etat, type, assiduite = null) {
   const modimpl_id = $("#moduleimpl_select").val();
   if (assiduite && assiduite.etat.toLowerCase() === etat) type = "suppression";
 
-  const { deb, fin } = getPeriodAsDate(true); // en tz server
+  const { deb, fin } = getPeriodAsISO(); // chaines sans timezone pour l'API
   // génération d'un objet assiduité basique qui sera complété
   let assiduiteObjet = assiduite ?? {
     date_debut: deb,
@@ -722,9 +735,12 @@ function mettreToutLeMonde(etat, el = null) {
   const lignesEtuds = [...document.querySelectorAll("fieldset.btns_field")];
 
   const { deb, fin } = getPeriodAsDate(true); // tz server
+  const period_iso = getPeriodAsISO(); // chaines sans timezone pour l'API
+  const deb_iso = period_iso.deb;
+  const fin_iso = period_iso.fin;
   const assiduiteObjet = {
-    date_debut: deb,
-    date_fin: fin,
+    date_debut: deb_iso,
+    date_fin: fin_iso,
     etat: etat,
     moduleimpl_id: $("#moduleimpl_select").val(),
   };
@@ -741,14 +757,14 @@ function mettreToutLeMonde(etat, el = null) {
       .filter((e) => e.getAttribute("type") == "edition")
       .map((e) => Number(e.getAttribute("assiduite_id")));
 
-    // On récupère les assiduités conflictuelles mais qui sont comprisent
-    // Dans la plage de suppression
+    // On récupère les assiduités conflictuelles mais qui sont comprises
+    // dans la plage de suppression
     const unDeleted = {};
     lignesEtuds
       .filter((e) => e.getAttribute("type") == "conflit")
       .forEach((e) => {
         const etud = etuds.get(Number(e.getAttribute("etudid")));
-        // On récupère les assiduités couvertent par la plage de suppression
+        // On récupère les assiduités couvertes par la plage de suppression
         etud.assiduites.forEach((a) => {
           const date_debut = new Date(a.date_debut);
           const date_fin = new Date(a.date_fin);
@@ -756,8 +772,8 @@ function mettreToutLeMonde(etat, el = null) {
           // (qui intersectent la plage de suppression)
           if (
             Date.intersect(
-              { deb: deb, fin: fin },
-              { deb: date_debut, fin: date_fin }
+              { deb: deb, fin: fin }, // la plage, en Date avec timezone serveur
+              { deb: date_debut, fin: date_fin } // dates de l'assiduité avec leur timezone
             )
           ) {
             // Si l'assiduité est couverte par la plage de suppression
diff --git a/app/templates/assiduites/widgets/timeline.j2 b/app/templates/assiduites/widgets/timeline.j2
index ddc96ad52ad0600a6fe499e3e8b98e07a8235a2a..8abd18d29a273d100199b81c906c4d9e80fc81ad 100644
--- a/app/templates/assiduites/widgets/timeline.j2
+++ b/app/templates/assiduites/widgets/timeline.j2
@@ -12,7 +12,7 @@
     </div>
 </div>
 <script>
-    const SERVER_TIMEZONE_OFFSET = "{{ scu.get_local_timezone_offset() }}";
+    var SERVER_TIMEZONE_OFFSET = "{{ scu.get_local_timezone_offset() }}"; // modifié par creerTousLesEtudiants()
     const timelineContainer = document.querySelector(".timeline-container");
     const periodTimeLine = document.querySelector(".period");
     const t_start = {{ t_start }};
@@ -336,7 +336,14 @@
         const [hours, minutes] = time.split(separator).map((el) => Number(el))
         return hours + minutes / 60
     }
-    // Renvoie les valeurs de la période sous forme de date
+    // La date ISO du datepicker
+    function getSelectedDateIso() {
+        return $("#date")
+            .datepicker("getDate")
+            .format("yyyy-mm-dd")
+            .substring(0, 10); // récupération que de la date, pas des heures
+    }
+    // Renvoie les valeurs de la période sous forme de Date
     // Les heures sont récupérées depuis la timeline
     // la date est récupérée depuis un champ "#date" (datepicker)
     function getPeriodAsDate(add_server_tz = false) {
@@ -344,10 +351,7 @@
         deb = numberToTime(deb);
         fin = numberToTime(fin);
 
-        const dateStr = $("#date")
-        .datepicker("getDate")
-        .format("yyyy-mm-dd")
-        .substring(0, 10); // récupération que de la date, pas des heures
+        const dateStr = getSelectedDateIso();
 
         // Les heures deb et fin sont telles qu'affichées, c'est à dire
         // en heure locale DU SERVEUR (des étudiants donc)
@@ -357,6 +361,22 @@
             fin: new Date(`${dateStr}T${fin}${offset}`)
         }
     }
+    // Renvoie les valeurs de la période sous forme de chaine ISO sans time zone.
+    function getPeriodAsISO() {
+        let [deb, fin] = getPeriodValues();
+        deb = numberToTime(deb);
+        fin = numberToTime(fin);
+
+        const dateStr = $("#date")
+        .datepicker("getDate")
+        .format("yyyy-mm-dd")
+        .substring(0, 10); // récupération que de la date, pas des heures
+        // retourne des chaines ISO sans timezone
+        return {
+            deb : `${dateStr}T${deb}`,
+            fin : `${dateStr}T${fin}`
+        }
+    }
     // Sauvegarde les valeurs de la période dans le local storage
     function savePeriodInLocalStorage(){
         const dates = getPeriodValues();
diff --git a/sco_version.py b/sco_version.py
index 90af92cbdf034386767965cceab5020d613d007d..a3ff9daf74819d41c26757979b37cf0a38179baf 100644
--- a/sco_version.py
+++ b/sco_version.py
@@ -3,7 +3,7 @@
 
 "Infos sur version ScoDoc"
 
-SCOVERSION = "9.7.34"
+SCOVERSION = "9.7.35"
 
 SCONAME = "ScoDoc"
 
diff --git a/tests/api/test_api_assiduites.py b/tests/api/test_api_assiduites.py
index c860e573d4c1bafac7d52461a09e645feb064936..97fcacc380459ea3965cd8703ab5c8a6000ea771 100644
--- a/tests/api/test_api_assiduites.py
+++ b/tests/api/test_api_assiduites.py
@@ -7,6 +7,7 @@ Ecrit par HARTMANN Matthias
 
 import datetime
 from random import randint
+import re
 from types import NoneType
 
 from app.scodoc import sco_utils as scu
@@ -449,3 +450,16 @@ def test_route_delete(api_admin_headers):
     assert len(res["errors"]) == 3
 
     assert all(i["message"] == "Assiduite non existante" for i in res["errors"])
+
+
+def test_date_time_offset(api_headers):
+    """test de la route /assiduites/date_time_offset"""
+
+    reply = GET(
+        path="/assiduite/date_time_offset/2024-10-29",
+        headers=api_headers,
+        dept=DEPT_ACRONYM,
+        raw=True,
+    )
+    # offset ISO 8601 de la forme +/-hh:mm
+    assert re.match(r"^(Z|[+-]\d{2}:\d{2})$", reply.text)
diff --git a/tests/api/test_api_permissions.py b/tests/api/test_api_permissions.py
index f94ce12e8039b6a81696b53e2cdcda6b99735c3e..c6fefc8102527c32dd9fb18fd4fa4ed68dd2366b 100755
--- a/tests/api/test_api_permissions.py
+++ b/tests/api/test_api_permissions.py
@@ -42,6 +42,7 @@ def test_permissions(api_headers):
         "acronym": "TAPI",
         "code_type": "etudid",
         "code": 1,
+        "date_iso": "2024-10-29",
         "dept_id": 1,
         "dept_ident": "TAPI",
         "dept": "TAPI",