Rotatory anlegen: Morning-Meeting-Moderation auslosen und nach Nextcloud schreiben
Express-App mit JSON-Speicher unter VCH_DATA_DIR, Monatskalender mit Fotos, Personen mit Rollen und Teilzeit-Freitagen, Abwesenheiten, Feiertage je Bundesland, faire Zufallsauslosung mit Fixieren und Neu-Auslosen. Nextcloud: CalDAV-Discovery, Zielkalender wählbar, Termine je Werktag schreiben und aktualisieren, Abwesenheiten aus Kalender importieren, Personen samt Fotos aus dem Systemadressbuch übernehmen. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
commit
95756778d8
26 files changed
+4697
No files matched your search
@@ -0,0 +1,66 @@
|
||||
import { addDays } from './scheduler.js';
|
||||
|
||||
const pad = (n) => String(n).padStart(2, '0');
|
||||
const iso = (y, m, d) => `${y}-${pad(m)}-${pad(d)}`;
|
||||
|
||||
/** Ostersonntag nach der Gauß'schen Osterformel (Meeus/Jones/Butcher). */
|
||||
export function easterSunday(year) {
|
||||
const a = year % 19;
|
||||
const b = Math.floor(year / 100);
|
||||
const c = year % 100;
|
||||
const d = Math.floor(b / 4);
|
||||
const e = b % 4;
|
||||
const f = Math.floor((b + 8) / 25);
|
||||
const g = Math.floor((b - f + 1) / 3);
|
||||
const h = (19 * a + b - d - g + 15) % 30;
|
||||
const i = Math.floor(c / 4);
|
||||
const k = c % 4;
|
||||
const l = (32 + 2 * e + 2 * i - h - k) % 7;
|
||||
const m = Math.floor((a + 11 * h + 22 * l) / 451);
|
||||
const month = Math.floor((h + l - 7 * m + 114) / 31);
|
||||
const day = ((h + l - 7 * m + 114) % 31) + 1;
|
||||
return iso(year, month, day);
|
||||
}
|
||||
|
||||
export const BUNDESLAENDER = {
|
||||
'': 'Nur bundesweite Feiertage',
|
||||
BW: 'Baden-Württemberg', BY: 'Bayern', BE: 'Berlin', BB: 'Brandenburg', HB: 'Bremen',
|
||||
HH: 'Hamburg', HE: 'Hessen', MV: 'Mecklenburg-Vorpommern', NI: 'Niedersachsen',
|
||||
NW: 'Nordrhein-Westfalen', RP: 'Rheinland-Pfalz', SL: 'Saarland', SN: 'Sachsen',
|
||||
ST: 'Sachsen-Anhalt', SH: 'Schleswig-Holstein', TH: 'Thüringen',
|
||||
};
|
||||
|
||||
function bussUndBettag(year) {
|
||||
// Mittwoch vor dem 23. November
|
||||
let d = iso(year, 11, 22);
|
||||
while (new Date(d + 'T00:00:00Z').getUTCDay() !== 3) d = addDays(d, -1);
|
||||
return d;
|
||||
}
|
||||
|
||||
/** Gesetzliche Feiertage eines Jahres, bundesweit plus die des gewählten Bundeslands. */
|
||||
export function germanHolidays(year, state = '') {
|
||||
const easter = easterSunday(year);
|
||||
const all = [
|
||||
{ date: iso(year, 1, 1), name: 'Neujahr' },
|
||||
{ date: iso(year, 1, 6), name: 'Heilige Drei Könige', states: ['BW', 'BY', 'ST'] },
|
||||
{ date: iso(year, 3, 8), name: 'Internationaler Frauentag', states: ['BE', 'MV'] },
|
||||
{ date: addDays(easter, -2), name: 'Karfreitag' },
|
||||
{ date: addDays(easter, 1), name: 'Ostermontag' },
|
||||
{ date: iso(year, 5, 1), name: 'Tag der Arbeit' },
|
||||
{ date: addDays(easter, 39), name: 'Christi Himmelfahrt' },
|
||||
{ date: addDays(easter, 50), name: 'Pfingstmontag' },
|
||||
{ date: addDays(easter, 60), name: 'Fronleichnam', states: ['BW', 'BY', 'HE', 'NW', 'RP', 'SL'] },
|
||||
{ date: iso(year, 8, 15), name: 'Mariä Himmelfahrt', states: ['SL', 'BY'] },
|
||||
{ date: iso(year, 9, 20), name: 'Weltkindertag', states: ['TH'] },
|
||||
{ date: iso(year, 10, 3), name: 'Tag der Deutschen Einheit' },
|
||||
{ date: iso(year, 10, 31), name: 'Reformationstag', states: ['BB', 'HB', 'HH', 'MV', 'NI', 'SN', 'ST', 'SH', 'TH'] },
|
||||
{ date: iso(year, 11, 1), name: 'Allerheiligen', states: ['BW', 'BY', 'NW', 'RP', 'SL'] },
|
||||
{ date: bussUndBettag(year), name: 'Buß- und Bettag', states: ['SN'] },
|
||||
{ date: iso(year, 12, 25), name: '1. Weihnachtstag' },
|
||||
{ date: iso(year, 12, 26), name: '2. Weihnachtstag' },
|
||||
];
|
||||
return all
|
||||
.filter((h) => !h.states || h.states.includes(state))
|
||||
.map(({ date, name }) => ({ date, name, auto: true }))
|
||||
.sort((a, b) => a.date.localeCompare(b.date));
|
||||
}
|
||||
Reference in new issue
Block a user