Оптимизация форматирования строки ISO в Elixir - PullRequest
1 голос
/ 30 апреля 2019

У меня есть две функции для форматирования строки даты ISO и времени ISO в обычные строки, например, "1999-10-12" -> "10.10.1999" & "18:00:00" -> "18:00", и они включают в себя множество функций преобразования ...

Интересно, есть ли более эффективный способ форматирования строковых входов ISO:

  # ISO Date String to DD/MM/YYYY
  def date_to_dd_mm_yyyy(iso_date) do
    {_, date} = Date.from_iso8601(iso_date)
    {year, month, day} = Date.to_erl(date)

    Integer.to_string(day) <> "/" <> Integer.to_string(month) <> "/" <> Integer.to_string(year)
  end

  # ISO Time String to 12 hour time
  def time_to_12hour(iso_time) do
    {:ok, new_time} = Time.from_iso8601(iso_time)
    {hour, minute, _second} = Time.to_erl(new_time)

    minute_string =
      cond do
        minute < 10 ->
          "0" <> Integer.to_string(minute)
        true ->
          Integer.to_string(minute)
      end

    hour_string =
      cond do
        hour === 0 ->
          "12"
        hour > 12 ->
          Integer.to_string(hour - 12)
        hour <= 12 ->
          Integer.to_string(hour)
      end

    meridiem =
      cond do
        hour >= 12 ->
          "pm"
        hour < 12 ->
          "am"
      end

    hour_string <> ":" <> minute_string <> meridiem
  end

Ответы [ 2 ]

2 голосов
/ 30 апреля 2019

Использовать совпадение скороговорки:

defmodule IsoToMine do
  # "1999-01-01"
  def convert(<<y::binary-size(4), "-",
                m::binary-size(2), "-",
                d::binary-size(2)>> = iso_date),
  # add {:ok, date} = Date.from_iso8601(iso_date)
  # here to blow up on wrong input
    do: Enum.join([y, d, m], "/")

  # "18:00:00"
  def convert(<<h::binary-size(2), ":",
                m::binary-size(2), ":",
                _::binary-size(2)>>) do
    {h, apm} =
      case String.to_integer(h) do
        0 -> {12, "am"}
        12 -> {12, "pm"}
        am when am < 12 -> {am, "am"}
        pm when pm > 12 -> {rem(pm, 12), "pm"}
      end

    to_string(h) <> ":" <> m <> apm
  end
end

Теперь IsoToMine.convert/1 всеяден:

iex|1 ▶ IsoToMine.convert "1999-01-01"
#⇒ "1999/01/01"
iex|2 ▶ IsoToMine.convert "12:03:01"  
#⇒ "12:03pm"
iex|3 ▶ IsoToMine.convert "11:03:01"
#⇒ "11:03am"
iex|4 ▶ IsoToMine.convert "18:03:01"
#⇒ "6:03pm"

Обратите внимание, что вышеприведенные функции не проверяют ввод и могут взорвать исключение MatchError / NoFunctionClause при неправильном вводе, но я просто повторил начальное поведение как в вашем коде (сохранить потому что вы взрываетесь в хорошо отформатированных, но невозможных датах, и моя радостно бежит.)

Добавление проверок и / или изящного отката на неправильный ввод - очень легкая задача, которую я оставляю вам в качестве упражнения.

1 голос
/ 30 апреля 2019

Не уверен, что он более производительный, но есть готовая библиотека с именем Timex , которая может сделать это за вас:

iex> "1999-10-12" |> Timex.parse!("{ISOdate}") |> Timex.format!("{D}/{M}/{YYYY}")
"12/10/1999"
iex> "18:00:00" |> Timex.parse!("{ISOtime}") |> Timex.format!("{kitchen}")
"6:00PM"

Как говорится, преждевременная оптимизация - корень всего зла , поэтому я бы предложил измерить скорость и попытаться создать более оптимизированную версию этого кода только в том случае, если парсинг и форматирование даты не удастся быть узким местом.

...