76 lines
2.3 KiB
TypeScript
76 lines
2.3 KiB
TypeScript
export const BERLIN_TIME_ZONE = 'Europe/Berlin';
|
|
|
|
export type CalendarDay = {
|
|
date: string;
|
|
dayNumber: number;
|
|
inSelectedMonth: boolean;
|
|
isToday: boolean;
|
|
};
|
|
|
|
const berlinDateFormatter = new Intl.DateTimeFormat('en-CA', {
|
|
timeZone: BERLIN_TIME_ZONE,
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit'
|
|
});
|
|
|
|
function padded(value: number) {
|
|
return String(value).padStart(2, '0');
|
|
}
|
|
|
|
function dateParts(value: string | Date) {
|
|
const parts = berlinDateFormatter.formatToParts(
|
|
typeof value === 'string' ? new Date(value) : value
|
|
);
|
|
const read = (type: Intl.DateTimeFormatPartTypes) =>
|
|
Number(parts.find((part) => part.type === type)?.value);
|
|
return { year: read('year'), month: read('month'), day: read('day') };
|
|
}
|
|
|
|
export function berlinDateKey(value: string | Date) {
|
|
const parts = dateParts(value);
|
|
return `${parts.year}-${padded(parts.month)}-${padded(parts.day)}`;
|
|
}
|
|
|
|
export function berlinMonthKey(value: string | Date) {
|
|
return berlinDateKey(value).slice(0, 7);
|
|
}
|
|
|
|
export function normalizeMonthKey(value: string | null | undefined, fallback: string) {
|
|
if (!value || !/^\d{4}-(0[1-9]|1[0-2])$/.test(value)) return fallback;
|
|
return value;
|
|
}
|
|
|
|
export function shiftMonth(monthKey: string, delta: number) {
|
|
const [year, month] = monthKey.split('-').map(Number);
|
|
const shifted = new Date(Date.UTC(year, month - 1 + delta, 1));
|
|
return `${shifted.getUTCFullYear()}-${padded(shifted.getUTCMonth() + 1)}`;
|
|
}
|
|
|
|
export function formatMonthLabel(monthKey: string) {
|
|
const [year, month] = monthKey.split('-').map(Number);
|
|
return new Intl.DateTimeFormat('de-DE', {
|
|
timeZone: 'UTC',
|
|
month: 'long',
|
|
year: 'numeric'
|
|
}).format(new Date(Date.UTC(year, month - 1, 1)));
|
|
}
|
|
|
|
export function buildCalendarDays(monthKey: string, todayKey: string): CalendarDay[] {
|
|
const [year, month] = monthKey.split('-').map(Number);
|
|
const first = new Date(Date.UTC(year, month - 1, 1));
|
|
const mondayOffset = (first.getUTCDay() + 6) % 7;
|
|
const start = new Date(Date.UTC(year, month - 1, 1 - mondayOffset));
|
|
return Array.from({ length: 42 }, (_, index) => {
|
|
const date = new Date(start);
|
|
date.setUTCDate(start.getUTCDate() + index);
|
|
const dateKey = `${date.getUTCFullYear()}-${padded(date.getUTCMonth() + 1)}-${padded(date.getUTCDate())}`;
|
|
return {
|
|
date: dateKey,
|
|
dayNumber: date.getUTCDate(),
|
|
inSelectedMonth: dateKey.startsWith(monthKey),
|
|
isToday: dateKey === todayKey
|
|
};
|
|
});
|
|
}
|