mirror of
https://github.com/philomena-dev/philomena.git
synced 2024-11-30 14:57:59 +01:00
more comprehensive datetime parsing fix
This commit is contained in:
parent
975531c42c
commit
e3e143e2c6
1 changed files with 45 additions and 52 deletions
|
@ -1,8 +1,6 @@
|
||||||
defmodule Search.DateParser do
|
defmodule Search.DateParser do
|
||||||
import NimbleParsec
|
import NimbleParsec
|
||||||
|
|
||||||
defp to_int(input), do: Search.Helpers.to_int(input)
|
|
||||||
|
|
||||||
defp build_datetime(naive, tz_off, tz_hour, tz_minute) do
|
defp build_datetime(naive, tz_off, tz_hour, tz_minute) do
|
||||||
tz_hour =
|
tz_hour =
|
||||||
tz_hour
|
tz_hour
|
||||||
|
@ -18,78 +16,78 @@ defmodule Search.DateParser do
|
||||||
|
|
||||||
# Unbelievable that there is no way to build this with integer arguments.
|
# Unbelievable that there is no way to build this with integer arguments.
|
||||||
# WTF, Elixir?
|
# WTF, Elixir?
|
||||||
{:ok, datetime, _offset} = DateTime.from_iso8601(iso8601_string)
|
case DateTime.from_iso8601(iso8601_string) do
|
||||||
|
{:ok, datetime, _offset} ->
|
||||||
|
{:ok, datetime}
|
||||||
|
|
||||||
datetime
|
_ ->
|
||||||
|
:error
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp timezone_bounds([]), do: ["+", 0, 0]
|
defp timezone_bounds([]), do: ["+", 0, 0]
|
||||||
defp timezone_bounds([tz_off, tz_hour]), do: [tz_off, tz_hour, 0]
|
defp timezone_bounds([tz_off, tz_hour]), do: [tz_off, tz_hour, 0]
|
||||||
defp timezone_bounds([tz_off, tz_hour, tz_minute]), do: [tz_off, tz_hour, tz_minute]
|
defp timezone_bounds([tz_off, tz_hour, tz_minute]), do: [tz_off, tz_hour, tz_minute]
|
||||||
|
|
||||||
|
defp days_in_month(year, month) when month in 1..12 do
|
||||||
|
Calendar.ISO.days_in_month(year, month)
|
||||||
|
end
|
||||||
|
defp days_in_month(_year, _month) do
|
||||||
|
0
|
||||||
|
end
|
||||||
|
|
||||||
|
defp lower_upper(tuple, offset_amount) do
|
||||||
|
case NaiveDateTime.from_erl(tuple) do
|
||||||
|
{:ok, lower} ->
|
||||||
|
upper = NaiveDateTime.add(lower, offset_amount, :second)
|
||||||
|
{:ok, [lower, upper]}
|
||||||
|
|
||||||
|
_ ->
|
||||||
|
:error
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defp date_bounds([year]) do
|
defp date_bounds([year]) do
|
||||||
lower = %NaiveDateTime{year: year, month: 1, day: 1, hour: 0, minute: 0, second: 0}
|
lower_upper({{year, 1, 1}, {0, 0, 0}}, 31_536_000)
|
||||||
upper = NaiveDateTime.add(lower, 31_536_000, :second)
|
|
||||||
[lower, upper]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp date_bounds([year, month]) do
|
defp date_bounds([year, month]) do
|
||||||
lower = %NaiveDateTime{year: year, month: month, day: 1, hour: 0, minute: 0, second: 0}
|
days = days_in_month(year, month)
|
||||||
upper = NaiveDateTime.add(lower, 2_592_000, :second)
|
lower_upper({{year, month, 1}, {0, 0, 0}}, 86_400 * days)
|
||||||
[lower, upper]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp date_bounds([year, month, day]) do
|
defp date_bounds([year, month, day]) do
|
||||||
lower = %NaiveDateTime{year: year, month: month, day: day, hour: 0, minute: 0, second: 0}
|
lower_upper({{year, month, day}, {0, 0, 0}}, 86_400)
|
||||||
upper = NaiveDateTime.add(lower, 86400, :second)
|
|
||||||
[lower, upper]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp date_bounds([year, month, day, hour]) do
|
defp date_bounds([year, month, day, hour]) do
|
||||||
lower = %NaiveDateTime{year: year, month: month, day: day, hour: hour, minute: 0, second: 0}
|
lower_upper({{year, month, day}, {hour, 0, 0}}, 3_600)
|
||||||
upper = NaiveDateTime.add(lower, 3600, :second)
|
|
||||||
[lower, upper]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp date_bounds([year, month, day, hour, minute]) do
|
defp date_bounds([year, month, day, hour, minute]) do
|
||||||
lower = %NaiveDateTime{
|
lower_upper({{year, month, day}, {hour, minute, 0}}, 60)
|
||||||
year: year,
|
|
||||||
month: month,
|
|
||||||
day: day,
|
|
||||||
hour: hour,
|
|
||||||
minute: minute,
|
|
||||||
second: 0
|
|
||||||
}
|
|
||||||
|
|
||||||
upper = NaiveDateTime.add(lower, 60, :second)
|
|
||||||
[lower, upper]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp date_bounds([year, month, day, hour, minute, second]) do
|
defp date_bounds([year, month, day, hour, minute, second]) do
|
||||||
lower = %NaiveDateTime{
|
lower_upper({{year, month, day}, {hour, minute, second}}, 1)
|
||||||
year: year,
|
|
||||||
month: month,
|
|
||||||
day: day,
|
|
||||||
hour: hour,
|
|
||||||
minute: minute,
|
|
||||||
second: second
|
|
||||||
}
|
|
||||||
|
|
||||||
upper = NaiveDateTime.add(lower, 1, :second)
|
|
||||||
[lower, upper]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp absolute_datetime(opts) do
|
defp absolute_datetime(_rest, opts, context, _line, _offset) do
|
||||||
date = Keyword.fetch!(opts, :date)
|
date = Keyword.fetch!(opts, :date)
|
||||||
timezone = Keyword.get(opts, :timezone, [])
|
timezone = Keyword.get(opts, :timezone, [])
|
||||||
|
|
||||||
[lower, upper] = date_bounds(date)
|
|
||||||
[tz_off, tz_hour, tz_minute] = timezone_bounds(timezone)
|
[tz_off, tz_hour, tz_minute] = timezone_bounds(timezone)
|
||||||
|
|
||||||
lower = build_datetime(lower, tz_off, tz_hour, tz_minute)
|
with {:ok, [lower, upper]} <- date_bounds(date),
|
||||||
upper = build_datetime(upper, tz_off, tz_hour, tz_minute)
|
{:ok, lower} <- build_datetime(lower, tz_off, tz_hour, tz_minute),
|
||||||
|
{:ok, upper} <- build_datetime(upper, tz_off, tz_hour, tz_minute)
|
||||||
[lower, upper]
|
do
|
||||||
|
{[[lower, upper]], context}
|
||||||
|
else
|
||||||
|
_ ->
|
||||||
|
date = Enum.join(date ++ timezone, ", ")
|
||||||
|
{:error, "invalid date format in input, parsed as #{date}"}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp relative_datetime([count, scale]) do
|
defp relative_datetime([count, scale]) do
|
||||||
|
@ -105,14 +103,9 @@ defmodule Search.DateParser do
|
||||||
choice([string(" "), string("\t"), string("\n"), string("\r"), string("\v"), string("\f")])
|
choice([string(" "), string("\t"), string("\n"), string("\r"), string("\v"), string("\f")])
|
||||||
|> ignore()
|
|> ignore()
|
||||||
|
|
||||||
pos_2dig_int =
|
|
||||||
ascii_char('0123456789')
|
|
||||||
|> ascii_char('123456789')
|
|
||||||
|> reduce(:to_int)
|
|
||||||
|
|
||||||
year = integer(4)
|
year = integer(4)
|
||||||
month = pos_2dig_int
|
month = integer(2)
|
||||||
day = pos_2dig_int
|
day = integer(2)
|
||||||
|
|
||||||
hour = integer(2)
|
hour = integer(2)
|
||||||
minute = integer(2)
|
minute = integer(2)
|
||||||
|
@ -164,7 +157,7 @@ defmodule Search.DateParser do
|
||||||
absolute_date =
|
absolute_date =
|
||||||
date_part
|
date_part
|
||||||
|> optional(timezone_part)
|
|> optional(timezone_part)
|
||||||
|> reduce(:absolute_datetime)
|
|> post_traverse(:absolute_datetime)
|
||||||
|> unwrap_and_tag(:date)
|
|> unwrap_and_tag(:date)
|
||||||
|
|
||||||
relative_date =
|
relative_date =
|
||||||
|
|
Loading…
Reference in a new issue