import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.format.ResolverStyle;
import java.util.Locale;
import java.util.Optional;

/**
 * Drop-in date formats for an application. Every formatter is a static final constant, because
 * DateTimeFormatter is immutable and thread-safe, so one instance can be shared by every thread.
 * Locale is pinned on each one, so the output does not change with the server's default locale.
 *
 * Run the self-check with: java DateFormats.java
 */
public final class DateFormats {

    private DateFormats() {}

    /** 14-11-2026 : display, and strict input. uuuu (not yyyy) so STRICT parsing can resolve it. */
    public static final DateTimeFormatter DMY = strict("dd-MM-uuuu");

    /** 14-11-2026 13:05 : 24-hour, no AM/PM, so no locale-dependent marker text to go wrong. */
    public static final DateTimeFormatter DMY_HM = strict("dd-MM-uuuu HH:mm");

    /** 14 Nov 2026 : month text pinned to English so the abbreviation is the same everywhere. */
    public static final DateTimeFormatter DAY_MONTH_YEAR = DateTimeFormatter.ofPattern("d MMM uuuu", Locale.ENGLISH);

    /** 01:05 PM : the 12-hour form, with the English marker pinned (en_IN would print lowercase "pm"). */
    public static final DateTimeFormatter TIME_12H = DateTimeFormatter.ofPattern("hh:mm a", Locale.ENGLISH);

    /** Machine-to-machine: use the built-in ISO constant, never a hand-written pattern. */
    public static final DateTimeFormatter WIRE = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

    private static DateTimeFormatter strict(String pattern) {
        return DateTimeFormatter.ofPattern(pattern, Locale.ENGLISH).withResolverStyle(ResolverStyle.STRICT);
    }

    /** Parses a dd-MM-uuuu date, returning empty instead of throwing for bad input such as 31-02-2026. */
    public static Optional<LocalDate> parseDmy(String text) {
        try {
            return Optional.of(LocalDate.parse(text, DMY));
        } catch (DateTimeParseException e) {
            return Optional.empty();
        }
    }

    public static void main(String[] args) {
        LocalDateTime when = LocalDateTime.of(2026, 11, 14, 13, 5);
        System.out.println("DMY            " + DMY.format(when));
        System.out.println("DMY_HM         " + DMY_HM.format(when));
        System.out.println("DAY_MONTH_YEAR " + DAY_MONTH_YEAR.format(when));
        System.out.println("TIME_12H       " + TIME_12H.format(when));
        System.out.println("WIRE           " + WIRE.format(when));
        System.out.println("parseDmy(14-11-2026) = " + parseDmy("14-11-2026"));
        System.out.println("parseDmy(31-02-2026) = " + parseDmy("31-02-2026"));
        System.out.println("parseDmy(14-11-26)   = " + parseDmy("14-11-26"));
        System.out.println("with default locale set to en_IN:");
        Locale.setDefault(Locale.of("en", "IN"));
        System.out.println("TIME_12H       " + TIME_12H.format(when));
        System.out.println("localized SHORT would have printed: "
                + DateTimeFormatter.ofLocalizedTime(java.time.format.FormatStyle.SHORT).format(when));
    }
}
