Files
desktop-planer/desktop@marha.de/dates.js
2026-09-18 22:02:53 +02:00

129 lines
3.8 KiB
JavaScript

// Datumshilfen. Kalendertage sind Strings 'YYYY-MM-DD', Uhrzeiten 'HH:MM'.
// Monate sind 0-basiert wie bei JS Date.
export const WEEKDAYS = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
export const MONTHS = ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'];
function pad(n) {
return String(n).padStart(2, '0');
}
export function toDateString(date) {
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
}
export function fromDateString(s) {
const [y, m, d] = s.split('-').map(Number);
return new Date(y, m - 1, d);
}
export function today() {
return toDateString(new Date());
}
export function addDays(s, n) {
const date = fromDateString(s);
date.setDate(date.getDate() + n);
return toDateString(date);
}
// Montag der Woche, in der s liegt.
export function startOfWeek(s) {
const date = fromDateString(s);
const offset = (date.getDay() + 6) % 7;
return addDays(s, -offset);
}
export function weekDays(s) {
const monday = startOfWeek(s);
return Array.from({length: 7}, (_, i) => addDays(monday, i));
}
// 42 Tage (6 Wochen) ab dem Montag der Woche des Monatsersten.
export function monthGrid(year, month) {
const first = toDateString(new Date(year, month, 1));
const start = startOfWeek(first);
return Array.from({length: 42}, (_, i) => addDays(start, i));
}
export function isoWeek(s) {
const date = fromDateString(s);
// Der Donnerstag derselben Woche bestimmt das ISO-Jahr.
const thursday = new Date(date);
thursday.setDate(date.getDate() - ((date.getDay() + 6) % 7) + 3);
const firstThursday = new Date(thursday.getFullYear(), 0, 4);
firstThursday.setDate(firstThursday.getDate() - ((firstThursday.getDay() + 6) % 7) + 3);
return 1 + Math.round((thursday - firstThursday) / (7 * 24 * 3600 * 1000));
}
export function formatMonth(year, month) {
return `${MONTHS[month]} ${year}`;
}
// 'Do, 17.09.2026'
export function formatDate(s) {
const date = fromDateString(s);
return `${WEEKDAYS[(date.getDay() + 6) % 7]}, ${formatDateInput(s)}`;
}
// '17.09.2026'
export function formatDateInput(s) {
const [y, m, d] = s.split('-');
return `${d}.${m}.${y}`;
}
// '17.09.'
export function formatDayMonth(s) {
const [, m, d] = s.split('-');
return `${d}.${m}.`;
}
// Akzeptiert '17.09.2026', '17.9.26', '17.9.' (aktuelles Jahr) und '2026-09-17'.
export function parseDateInput(text) {
const t = text.trim();
let y, m, d;
let match = t.match(/^(\d{1,2})\.(\d{1,2})\.(\d{2,4})?$/);
if (match) {
d = Number(match[1]);
m = Number(match[2]);
y = match[3] === undefined ? new Date().getFullYear() : Number(match[3]);
if (y < 100)
y += 2000;
} else {
match = t.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/);
if (!match)
return null;
[y, m, d] = [Number(match[1]), Number(match[2]), Number(match[3])];
}
const date = new Date(y, m - 1, d);
if (date.getFullYear() !== y || date.getMonth() !== m - 1 || date.getDate() !== d)
return null;
return toDateString(date);
}
// Akzeptiert '9:00', '09:00', '9.30', '14' → 'HH:MM'.
export function parseTimeInput(text) {
const match = text.trim().match(/^(\d{1,2})(?:[:.](\d{2}))?$/);
if (!match)
return null;
const h = Number(match[1]);
const min = match[2] === undefined ? 0 : Number(match[2]);
if (h > 23 || min > 59)
return null;
return `${pad(h)}:${pad(min)}`;
}
export function timeToMinutes(t) {
const [h, m] = t.split(':').map(Number);
return h * 60 + m;
}
export function minutesToTime(minutes) {
return `${pad(Math.floor(minutes / 60))}:${pad(minutes % 60)}`;
}
export function hourOf(t) {
return Number(t.split(':')[0]);
}