Ein Termin von-bis belegt jeden Tag dazwischen

Zwei Fehler, nicht einer.

Der sichtbare: Die Kachel stand nur am Anfangstag. Wer im
Monatsraster auf den Mittwoch sah, sah nichts -- obwohl die Aktion
von Montag bis Freitag lief.

Der unsichtbare, und der ist der schlimmere: Der SERVER suchte
Eintraege, deren ANFANG im sichtbaren Fenster liegt. Eine Aktion vom
28.09. bis zum 05.10. kam im Oktober deshalb ueberhaupt nicht an --
nicht "nur am ersten Tag markiert", sondern gar nicht da. Wer im
Oktober plante, sah eine freie Woche, die belegt war. Jetzt
entscheidet die UEBERSCHNEIDUNG, nicht der Anfang.

Gebaut wurde es in nachTag() -- der einzigen Stelle, an der
Eintraege auf Tage verteilt werden. Monat, Woche, Liste und
Zeitstrahl holen sich alle dort; vier Ansichten einzeln
nachzuruesten waeren vier Stellen, an denen die fuenfte vergessen
wird.

Das Ende wird abgeleitet, nicht gepflegt: aus event_ende ODER aus
Uhrzeit plus Dauer. Ein Live von 22:00 ueber vier Stunden endet um
02:00 am naechsten Tag -- das stand bisher nirgends, obwohl die
Zahlen da waren.

Der Tagesdialog filterte selbst auf den Anfangstag. Im Raster war
der Mittwoch markiert, tippte man ihn an, stand da "An diesem Tag
steht nichts." Jetzt fragt er dieselbe Stelle wie das Raster.

pruef-zeitraum.mjs: 16 Pruefungen, beide Fehler einzeln, mit drei
Gegenproben (vor dem Anfang, nach dem Ende, Punkttermin).
pruef-terminregel.mjs weiterhin 35/0.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-20 19:20:18 +02:00
co-authored by Claude Opus 5
parent 947ea7ff49
commit d77dd216c5
5 changed files with 443 additions and 8 deletions
+126 -5
View File
@@ -601,11 +601,93 @@
statt verschluckt. */
const sichtbare = () => (daten ? daten.eintraege.filter((e) => zeigen[e.art] !== false) : []);
/* =====================================================================
EIN TERMIN VON--BIS STEHT AN JEDEM TAG DAZWISCHEN (20.09.2026)
Filipe: „wenn ich termine eintrage mit von bis, will ich dass die
ganze zeit markiert ist und nicht nur der anfang."
BISHER stand er nur am Anfangstag. Wer im Monatsraster auf den
Mittwoch sah, sah nichts -- obwohl die Aktion von Montag bis
Freitag lief. Genau in der Ansicht, in der man plant, war der
belegte Zeitraum unsichtbar, und man legte etwas mitten hinein.
WARUM GENAU HIER: `nachTag()` ist die EINZIGE Stelle, an der
Eintraege auf Tage verteilt werden -- Monat, Woche, Liste und
Zeitstrahl holen sich alle `karte.get(tag)`. Vier Ansichten
einzeln nachzuruesten waere vier Stellen, an denen die naechste
Ansicht vergessen wird.
DAS ENDE WIRD ABGELEITET, NICHT GEPFLEGT:
* `bis` -- Brettkarten mit event_ende
* Uhr + Dauer -- ein Live von 22:00 ueber 240 Minuten endet um
02:00 am naechsten Tag. Das stand bisher
NIRGENDS, obwohl die Zahlen da waren.
Eine Liste „diese Arten haben ein Ende" waere die Liste, die beim
naechsten Termintyp veraltet.
DIE KOPIEN AENDERN `tag` NICHT. Wer auf eine Kachel am Mittwoch
tippt, will den Termin bearbeiten -- und der faengt am Montag an.
Wuerde die Kopie `tag` auf den Mittwoch setzen, verschoebe ein
Speichern den Termin auf den Tag, an dem man zufaellig
hingetippt hat. Der Anzeigetag steht deshalb getrennt daneben. */
/** Der letzte Tag, an dem dieser Eintrag noch laeuft. */
function endTagVon(e) {
if (e.bis) return String(e.bis).slice(0, 10);
if (e.uhr && Number(e.dauer_min) > 0) {
const [st, mi] = e.uhr.split(':').map(Number);
const start = ausText(e.tag);
if (Number.isNaN(st) || Number.isNaN(start.getTime())) return e.tag;
/* AB MITTERNACHT RECHNEN, NICHT AB `ausText`. `ausText` legt den
Tag bewusst auf 12:00 UTC (damit Zeitzonen ihn nicht um einen
Tag verschieben) -- wer darauf die Uhrzeit ADDIERT, rechnet
zwoelf Stunden zu viel. Erster Anlauf ergab damit fuer
„13:00, 60 Minuten" den FOLGETAG. */
const mitternacht = Date.UTC(
start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate());
/* Minus eine Millisekunde: Ein Stream von 22:00 ueber genau zwei
Stunden endet um 00:00 -- er laeuft am naechsten Tag NICHT
mehr, auch wenn die Zahl dort steht. */
const endeMs = mitternacht
+ ((st * 60 + mi + Number(e.dauer_min)) * 60000) - 1;
return alsText(new Date(Math.max(endeMs, mitternacht)));
}
return e.tag;
}
/* Eine Obergrenze, die nicht schoen ist, aber ehrlich: Ein Eintrag
mit kaputtem Enddatum (Jahr 9999) wuerde sonst Millionen Kopien
bauen und den Browser anhalten. 400 Tage sind mehr als jede
Ansicht je zeigt -- die Grenze ist also nie im Weg und faengt nur
den Unfall ab. */
const SPANNE_MAX = 400;
function nachTag() {
const karte = new Map();
const lege = (tag, e) => {
if (!karte.has(tag)) karte.set(tag, []);
karte.get(tag).push(e);
};
for (const e of sichtbare()) {
if (!karte.has(e.tag)) karte.set(e.tag, []);
karte.get(e.tag).push(e);
const ende = endTagVon(e);
if (!ende || ende <= e.tag) { lege(e.tag, e); continue; }
const tage = Math.min(SPANNE_MAX,
Math.round((ausText(ende) - ausText(e.tag)) / 86400000) + 1);
let d = ausText(e.tag);
for (let i = 0; i < tage; i++) {
lege(alsText(d), {
...e,
/* Der Tag, an dem die Kachel steht -- NICHT `tag`. */
spann_tag: alsText(d),
spann_nr: i + 1,
spann_tage: tage,
spann_bis: ende,
spann_pos: i === 0 ? 'start' : (i === tage - 1 ? 'ende' : 'mitte'),
});
d = plus(d, 1);
}
}
return karte;
}
@@ -629,8 +711,38 @@
if (e.ziel) k.href = e.ziel;
k.style.setProperty('--pfarbe', e.farbe);
k.title = `${e.titel}${e.zusatz ? ' — ' + e.zusatz : ''}`
+ (e.serie_id ? ' — wiederholt sich' : '');
if (e.uhr) k.append(el('span', 'k-pille__zeit', e.uhr));
+ (e.serie_id ? ' — wiederholt sich' : '')
/* Der ganze Zeitraum, nicht nur „Tag 2/4": Wer am Mittwoch
draufzeigt, will wissen, WANN es anfing und aufhoert -- sonst
muss er selbst zurueckblaettern und zaehlen. */
+ (e.spann_tage > 1
? ` — läuft vom ${tagLang(e.tag)} bis ${tagLang(e.spann_bis)}`
+ ` (Tag ${e.spann_nr} von ${e.spann_tage})`
: '');
/* ---- LAEUFT UEBER MEHRERE TAGE (20.09.2026) --------------------
Drei Dinge unterscheiden die Kachel eines Zeitraums von der eines
Punkttermins, und alle drei sind noetig:
1. `data-spanne` -- daraus macht das Stilblatt einen
durchgehenden Balken: links angeschnitten, wo er gestern
schon lief, rechts angeschnitten, wo er morgen weiterlaeuft.
Man sieht an der FORM, dass es weitergeht, ohne ein Wort.
2. „Tag 2/4" statt der Uhrzeit auf den Folgetagen. Die Uhrzeit
gehoert zum Anfang; sie am Mittwoch zu wiederholen behauptet,
es ginge am Mittwoch um 20:00 wieder los.
3. Der ganze Zeitraum im Titel -- fuer Maus und Vorleseprogramm.
AUF DEM ANFANGSTAG BLEIBT ALLES WIE VORHER. Wer den Termin
eintraegt, sieht dort die Uhrzeit, die er eingetragen hat. */
if (e.spann_tage > 1) {
k.dataset.spanne = e.spann_pos;
k.style.setProperty('--spann-tage', String(e.spann_tage));
}
if (e.spann_tage > 1 && e.spann_pos !== 'start') {
k.append(el('span', 'k-pille__zeit k-pille__lauf',
`Tag ${e.spann_nr}/${e.spann_tage}`));
} else if (e.uhr) k.append(el('span', 'k-pille__zeit', e.uhr));
/* Das Zeichen steht im Raster VOR dem Titel, nicht dahinter: Eine
Zelle im Monatsraster ist gut 150 px breit, der Titel wird dort
abgeschnitten -- ein Zeichen am Ende wäre genau in der Ansicht
@@ -1355,7 +1467,16 @@
const liste = $('tagdialog-liste');
liste.replaceChildren();
const eintraege = sichtbare().filter((e) => e.tag === tag);
/* UEBER `nachTag()`, NICHT UEBER `e.tag` (20.09.2026).
Vorher stand hier ein eigener Filter auf den Anfangstag. Folge:
Im Monatsraster war die Aktion am Mittwoch markiert -- tippte man
die Zelle an, sagte der Tagesdialog „An diesem Tag steht
nichts." Zwei Antworten auf dieselbe Frage, und die zweite
widerspricht dem, was man gerade gesehen hat.
`nachTag()` ist die eine Stelle, die das entscheidet. */
const eintraege = nachTag().get(tag) || [];
if (!eintraege.length) {
liste.append(el('p', 'leise', 'An diesem Tag steht nichts.'));
} else {