When working with dates, you’ll often run into the challenge of handling different formats. Some users might input "12 January 2024," while others might prefer "January 12, 2024" or "2024-01-12." Instead of forcing a single strict format, we can use Elixir's Timex library to attempt multiple formats and return the first valid one.

Let’s say we receive date strings from various sources, but we don’t know in advance which format they will follow. Using Timex.parse/2, we can attempt to parse the date string with a predefined format. However, if we try just one format and it fails, we need a way to fall back to other formats automatically.

We can define a list of possible formats and iterate through them, trying each one until we find a match:

defmodule DateParser do
  def parse_date(date) do
    # Define the supported formats
    formats = [
      "{D} {Mfull} {YYYY}",
      "{Mfull} {D}, {YYYY}",
      "{YYYY}-{0M}-{0D}"
    ]

    date
    |> String.replace([",", "\\", "*"], "") # Sanitize the input if needed
    |> try_formats(formats) # Attempt each format, returning the first match
  end

  # No formats left to try
  defp try_formats(_date, []), do: {:error, "No valid format found"}
  
  # Try the next format, it it fails, try again with the list of remaining formats
  defp try_formats(date, [format | rest]) do
    case Timex.parse(date, format) do
      {:ok, parsed_date} -> {:ok, parsed_date}
      {:error, _} -> try_formats(date, rest)
    end
  end
end

You can use it like this:

DateParser.parse_date("12 January 2024")
# => {:ok, ~N[2024-01-12 00:00:00]}

DateParser.parse_date("January 12, 2024")
# => {:ok, ~N[2024-01-12 00:00:00]}

DateParser.parse_date("2024-01-12")
# => {:ok, ~N[2024-01-12 00:00:00]}

DateParser.parse_date("Invalid Date")
# => {:error, "No valid format found"}