Unify date display to DD.MM.YYYY across the UI

Previously two formats showed up next to each other: raw ISO
(YYYY-MM-DD) where DB values were interpolated directly, and
toLocaleDateString('de-DE') output (D.M.YYYY without leading
zeros) where formatDate was used.

- formatDate / formatDateTime now build the string explicitly with
  zero-padded day and month, so dates render as DD.MM.YYYY (and
  DD.MM.YYYY HH:MM for timestamps) regardless of locale.
- Replaced the remaining raw uses (Anbieter-Admin createdAt,
  Mitarbeiter-Prozentsätze gueltig_ab, the new Benutzer tab's
  createdAt, PDF export date filters and footer).
- Native <input type=\"date\"> fields are unchanged — they require
  the ISO value internally and render localized in the picker.
This commit is contained in:
kerimatilgan committed 2026-05-15 16:10:50 +02:00
1 parent e308c1a7b7
commit ea3a3fc12c
1 file changed
+25 -11
+25 -11
View File
@@ -601,9 +601,16 @@ async function loadSchaltungen() {
} }
} }
// Format any ISO-like date string (YYYY-MM-DD or full timestamp) as DD.MM.YYYY
// with leading zeros. Returns the original string unchanged if it cannot be parsed.
function formatDate(dateString) { function formatDate(dateString) {
if (!dateString) return '';
const date = new Date(dateString); const date = new Date(dateString);
return date.toLocaleDateString('de-DE'); if (isNaN(date.getTime())) return String(dateString);
const dd = String(date.getDate()).padStart(2, '0');
const mm = String(date.getMonth() + 1).padStart(2, '0');
const yyyy = date.getFullYear();
return `${dd}.${mm}.${yyyy}`;
} }
async function showDocuments(schaltungId) { async function showDocuments(schaltungId) {
@@ -848,7 +855,7 @@ async function loadAnbieterAdmin() {
} }
anbieter.forEach(a => { anbieter.forEach(a => {
const createdAt = new Date(a.created_at).toLocaleDateString('de-DE'); const createdAt = formatDate(a.created_at);
const tr = document.createElement('tr'); const tr = document.createElement('tr');
tr.innerHTML = ` tr.innerHTML = `
<td>${a.id}</td> <td>${a.id}</td>
@@ -1844,8 +1851,15 @@ async function loadGeloeschteSchaltungen() {
} }
function formatDateTime(dateTimeString) { function formatDateTime(dateTimeString) {
const date = new Date(dateTimeString); if (!dateTimeString) return '';
return date.toLocaleDateString('de-DE') + ' ' + date.toLocaleTimeString('de-DE', {hour: '2-digit', minute: '2-digit'}); const d = new Date(dateTimeString);
if (isNaN(d.getTime())) return String(dateTimeString);
const dd = String(d.getDate()).padStart(2, '0');
const mm = String(d.getMonth() + 1).padStart(2, '0');
const yyyy = d.getFullYear();
const HH = String(d.getHours()).padStart(2, '0');
const MM = String(d.getMinutes()).padStart(2, '0');
return `${dd}.${mm}.${yyyy} ${HH}:${MM}`;
} }
// Filter functionality // Filter functionality
@@ -3096,7 +3110,7 @@ async function loadMitarbeiterProzentsaetzeAdmin() {
<div> <div>
<strong>${escapeHtml(String(p.prozentsatz))}%</strong> <strong>${escapeHtml(String(p.prozentsatz))}%</strong>
${p.beschreibung ? `- ${escapeHtml(p.beschreibung)}` : ''} ${p.beschreibung ? `- ${escapeHtml(p.beschreibung)}` : ''}
<br><small class="text-muted">Gültig ab: ${escapeHtml(p.gueltig_ab)}</small> <br><small class="text-muted">Gültig ab: ${escapeHtml(formatDate(p.gueltig_ab))}</small>
</div> </div>
<div> <div>
<button data-mp-action="delete" data-id="${p.id}" class="btn-danger"> <button data-mp-action="delete" data-id="${p.id}" class="btn-danger">
@@ -3577,18 +3591,18 @@ function exportProvisionenToPdf() {
yPos += 5; yPos += 5;
} }
if (datumVon) { if (datumVon) {
doc.text(`• Von: ${new Date(datumVon).toLocaleDateString('de-DE')}`, 25, yPos); doc.text(`• Von: ${formatDate(datumVon)}`, 25, yPos);
yPos += 5; yPos += 5;
} }
if (datumBis) { if (datumBis) {
doc.text(`• Bis: ${new Date(datumBis).toLocaleDateString('de-DE')}`, 25, yPos); doc.text(`• Bis: ${formatDate(datumBis)}`, 25, yPos);
yPos += 5; yPos += 5;
} }
yPos += 5; yPos += 5;
} }
// Add generation date // Add generation date
doc.text(`Erstellt am: ${new Date().toLocaleDateString('de-DE')} um ${new Date().toLocaleTimeString('de-DE')}`, 20, yPos); doc.text(`Erstellt am: ${formatDateTime(new Date())}`, 20, yPos);
yPos += 15; yPos += 15;
// Table headers // Table headers
@@ -3678,8 +3692,8 @@ function exportProvisionenToPdf() {
// Prepare row data // Prepare row data
const rawData = [ const rawData = [
schaltung.schaltungs_id || '', schaltung.schaltungs_id || '',
schaltung.eingabe_datum ? new Date(schaltung.eingabe_datum).toLocaleDateString('de-DE') : '', schaltung.eingabe_datum ? formatDate(schaltung.eingabe_datum) : '',
schaltung.schaltungs_datum ? new Date(schaltung.schaltungs_datum).toLocaleDateString('de-DE') : '', schaltung.schaltungs_datum ? formatDate(schaltung.schaltungs_datum) : '',
`${schaltung.vorname || ''} ${schaltung.nachname || ''}`.trim() + (schaltung.firma ? ` (${schaltung.firma})` : ''), `${schaltung.vorname || ''} ${schaltung.nachname || ''}`.trim() + (schaltung.firma ? ` (${schaltung.firma})` : ''),
schaltung.anbieter_name || '', schaltung.anbieter_name || '',
schaltung.tarif_name || '', schaltung.tarif_name || '',
@@ -3780,7 +3794,7 @@ async function loadUsers() {
<td>${escapeHtml(u.username)}${isSelf ? ' <small style="color:#3498db;">(Sie)</small>' : ''}</td> <td>${escapeHtml(u.username)}${isSelf ? ' <small style="color:#3498db;">(Sie)</small>' : ''}</td>
<td>${escapeHtml(u.displayName || '')}</td> <td>${escapeHtml(u.displayName || '')}</td>
<td>${u.isAdmin ? '<span style="color:#27ae60;">✓</span>' : ''}</td> <td>${u.isAdmin ? '<span style="color:#27ae60;">✓</span>' : ''}</td>
<td>${escapeHtml(u.createdAt || '')}</td> <td>${escapeHtml(formatDateTime(u.createdAt))}</td>
<td> <td>
<button data-user-action="edit" data-uuid="${escapeHtml(u.uuid)}" class="btn-success" style="margin-right:5px;">Bearbeiten</button> <button data-user-action="edit" data-uuid="${escapeHtml(u.uuid)}" class="btn-success" style="margin-right:5px;">Bearbeiten</button>
<button data-user-action="delete" data-uuid="${escapeHtml(u.uuid)}" data-username="${escapeHtml(u.username)}" class="btn-danger" ${isSelf ? 'disabled title="Eigener Account kann nicht gelöscht werden"' : ''}>Löschen</button> <button data-user-action="delete" data-uuid="${escapeHtml(u.uuid)}" data-username="${escapeHtml(u.username)}" class="btn-danger" ${isSelf ? 'disabled title="Eigener Account kann nicht gelöscht werden"' : ''}>Löschen</button>