defmodule Timex.Parse.DateTime.Helpers do @moduledoc false import Combine.Parsers.Base import Combine.Parsers.Text, except: [integer: 0, integer: 1] alias Combine.Parsers.Text use Timex.Constants def months do @month_names ++ Map.values(Timex.Translator.get_months(Timex.Translator.current_locale())) end def months_abbr do @month_abbrs ++ Map.values(Timex.Translator.get_months_abbreviated(Timex.Translator.current_locale())) end def to_month(month) when is_integer(month), do: [month: month] def to_month_num(m) when m in ["January", "Jan"], do: to_month(1) def to_month_num(m) when m in ["February", "Feb"], do: to_month(2) def to_month_num(m) when m in ["March", "Mar"], do: to_month(3) def to_month_num(m) when m in ["April", "Apr"], do: to_month(4) def to_month_num(m) when m in ["May", "May"], do: to_month(5) def to_month_num(m) when m in ["June", "Jun"], do: to_month(6) def to_month_num(m) when m in ["July", "Jul"], do: to_month(7) def to_month_num(m) when m in ["August", "Aug"], do: to_month(8) def to_month_num(m) when m in ["September", "Sep"], do: to_month(9) def to_month_num(m) when m in ["October", "Oct"], do: to_month(10) def to_month_num(m) when m in ["November", "Nov"], do: to_month(11) def to_month_num(m) when m in ["December", "Dec"], do: to_month(12) def to_month_num(m) when is_binary(m) do Map.fetch!(Timex.Translator.get_months_lookup(Timex.Translator.current_locale()), m) end def is_weekday(name) do n = String.downcase(name) cond do n in @weekday_abbrs_lower -> true n in @weekday_names_lower -> true Map.has_key?(Timex.Translator.get_weekdays_lookup(Timex.Translator.current_locale()), name) -> true :else -> false end end def to_weekday(name) do n = String.downcase(name) case n do n when n in ["mon", "monday"] -> 1 n when n in ["tue", "tuesday"] -> 2 n when n in ["wed", "wednesday"] -> 3 n when n in ["thu", "thursday"] -> 4 n when n in ["fri", "friday"] -> 5 n when n in ["sat", "saturday"] -> 6 n when n in ["sun", "sunday"] -> 7 _ -> Map.fetch!(Timex.Translator.get_weekdays_lookup(Timex.Translator.current_locale()), name) end end def to_sec_ms(fraction) do precision = byte_size(fraction) n = String.to_integer(fraction) n = n * div(1_000_000, trunc(:math.pow(10, precision))) case n do 0 -> [sec_fractional: {0, 0}] _ -> [sec_fractional: {n, precision}] end end def parse_milliseconds(ms) do n = ms |> String.trim_leading("0") n = if n == "", do: 0, else: String.to_integer(n) n = n * 1_000 [sec_fractional: Timex.DateTime.Helpers.construct_microseconds(n, -1)] end def parse_microseconds(us) do n_width = byte_size(us) trailing = n_width - byte_size(String.trim_trailing(us, "0")) cond do n_width == trailing -> [sec_fractional: {0, n_width}] :else -> p = n_width - trailing p = if p > 6, do: 6, else: p n = us |> String.trim("0") |> String.to_integer() [sec_fractional: {n * trunc(:math.pow(10, 6 - p)), p}] end end def ampm_lower do ["am", "pm"] ++ Timex.Translator.get_day_periods_lower(Timex.Translator.current_locale()) end def ampm_upper do ["AM", "PM"] ++ Timex.Translator.get_day_periods_upper(Timex.Translator.current_locale()) end def ampm_any do ampm_lower() ++ ampm_upper() end def to_ampm("am"), do: [am: "am"] def to_ampm("AM"), do: [AM: "AM"] def to_ampm("pm"), do: [am: "pm"] def to_ampm("PM"), do: [AM: "PM"] def to_ampm(value) when is_binary(value) do type = Map.fetch!( Timex.Translator.get_day_periods_lookup(Timex.Translator.current_locale()), value ) [{type, value}] end def integer(opts \\ []) do min_width = case Keyword.get(opts, :padding) do :none -> 1 _ -> get_in(opts, [:min]) || 1 end max_width = get_in(opts, [:max]) padding = get_in(opts, [:padding]) case {padding, min_width, max_width} do {:zeroes, _, nil} -> Text.integer() {:zeroes, min, max} -> choice(Enum.map(max..min//-1, &fixed_integer(&1))) {:spaces, -1, nil} -> skip(spaces()) |> Text.integer() {:spaces, min, nil} -> skip(spaces()) |> fixed_integer(min) {:spaces, _, max} -> skip(spaces()) |> choice(Enum.map(max..1//-1, &fixed_integer(&1))) {_, -1, nil} -> Text.integer() {_, min, nil} -> fixed_integer(min) {_, min, max} -> choice(Enum.map(max..min//-1, &fixed_integer(&1))) end end end