在Elixir中优化ISO字符串格式

时间:2019-04-30 04:34:54

标签: performance date time elixir

我有两个函数可以将ISO日期和ISO时间字符串格式化为常规字符串,例如“ 1999-10-12”->“ 12/10/1999”&“ 18:00:00”->“ 6:00 pm”,它们涉及许多转换功能...

我想知道是否有更高效的格式化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 个答案:

答案 0 :(得分:2)

使用模式匹配:

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 :(得分:1)

不确定性能是否更好,但是有一个现成的名为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"

正如他们所说的premature optimization is the root of all evil,所以我建议测量速度,并仅在日期解析和格式化成为瓶颈的情况下,才尝试创建此代码的更优化版本。