WebMvcConfig.java

package de.mirkosertic.powerstaff.shared;

import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(final FormatterRegistry registry) {
        // HTML <input type="date"> sends yyyy-MM-dd; also accept dd.MM.yyyy (German format)
        registry.addConverter(String.class, LocalDate.class, source -> {
            if (source == null || source.isBlank()) return null;
            // Try ISO format (yyyy-MM-dd) — standard HTML date input
            try {
                return LocalDate.parse(source.trim(), DateTimeFormatter.ISO_LOCAL_DATE);
            } catch (final DateTimeParseException e1) {
                // Try German format (dd.MM.yyyy)
                try {
                    return LocalDate.parse(source.trim(), DateTimeFormatter.ofPattern("dd.MM.yyyy"));
                } catch (final DateTimeParseException e2) {
                    throw new IllegalArgumentException("Ungültiges Datum: " + source + ". Erwartet: TT.MM.JJJJ");
                }
            }
        });

        // LocalDateTime: HTML date input sends yyyy-MM-dd (no time) → treat as midnight
        registry.addConverter(String.class, LocalDateTime.class, source -> {
            if (source == null || source.isBlank()) return null;
            // Try ISO format (yyyy-MM-dd) → midnight
            try {
                return LocalDate.parse(source.trim(), DateTimeFormatter.ISO_LOCAL_DATE).atStartOfDay();
            } catch (final DateTimeParseException e1) {
                // Try German format (dd.MM.yyyy) → midnight
                try {
                    return LocalDate.parse(source.trim(), DateTimeFormatter.ofPattern("dd.MM.yyyy")).atStartOfDay();
                } catch (final DateTimeParseException e2) {
                    // Try full ISO datetime (yyyy-MM-ddTHH:mm:ss)
                    try {
                        return LocalDateTime.parse(source.trim(), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
                    } catch (final DateTimeParseException e3) {
                        throw new IllegalArgumentException("Ungültiges Datum: " + source + ". Erwartet: TT.MM.JJJJ");
                    }
                }
            }
        });
    }
}