Guest User

Untitled

a guest
Jul 19th, 2018
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 2.77 KB | None | 0 0
  1. defmodule RFC822 do
  2. import NimbleParsec
  3.  
  4. day =
  5. choice([
  6. string("Mon"),
  7. string("Tue"),
  8. string("Wed"),
  9. string("Thu"),
  10. string("Fri"),
  11. string("Sat"),
  12. string("Sun")
  13. ])
  14. |> string(",")
  15. |> string(" ")
  16.  
  17. date =
  18. integer(min: 1, max: 2)
  19. |> ignore(string(" "))
  20. |> choice([
  21. string("Jan"),
  22. string("Feb"),
  23. string("Mar"),
  24. string("Apr"),
  25. string("May"),
  26. string("Jun"),
  27. string("Jul"),
  28. string("Aug"),
  29. string("Sep"),
  30. string("Oct"),
  31. string("Nov"),
  32. string("Dec")
  33. ])
  34. |> ignore(string(" "))
  35. |> integer(2)
  36.  
  37. time =
  38. integer(2)
  39. |> ignore(string(":"))
  40. |> integer(2)
  41. |> ignore(string(":"))
  42. |> optional(integer(2))
  43.  
  44. timezone =
  45. choice([
  46. string("EST"),
  47. string("EDT"),
  48. ])
  49.  
  50. defparsec :rfc822,
  51. optional(ignore(day))
  52. |> concat(date)
  53. |> ignore(string(" "))
  54. |> concat(time)
  55. |> ignore(string(" "))
  56. |> concat(timezone)
  57.  
  58. def parse(binary) do
  59. case rfc822(binary) do
  60. {:ok, result, _, _, _, _} ->
  61. # FIXME: irreponsible pattern matching.
  62. [day, month, year, hour, minute, second, zone] = result
  63.  
  64. {:ok, naive_datetime} =
  65. NaiveDateTime.new(year(year), month(month), day, hour, minute, second)
  66.  
  67. {
  68. :ok,
  69. naive_datetime
  70. |> NaiveDateTime.add(zone_to_offset(zone), :second)
  71. |> DateTime.from_naive!("Etc/UTC")
  72. }
  73.  
  74. {:error, _, rest, _, _, _} ->
  75. {:error, :invalid}
  76. end
  77. end
  78.  
  79. defp year(year), do: 2000 + year
  80.  
  81. defp month("Jan"), do: 1
  82. defp month("Feb"), do: 2
  83. defp month("Mar"), do: 3
  84. defp month("Apr"), do: 4
  85. defp month("May"), do: 5
  86. defp month("Jun"), do: 6
  87. defp month("Jul"), do: 7
  88. defp month("Aug"), do: 8
  89. defp month("Sep"), do: 9
  90. defp month("Oct"), do: 10
  91. defp month("Nov"), do: 11
  92. defp month("Dec"), do: 12
  93.  
  94. defp zone_to_offset("EDT"), do: -4 * 60 * 60
  95. defp zone_to_offset("EST"), do: -5 * 60 * 60
  96. defp zone_to_offset("CST"), do: -6 * 60 * 60
  97. # More zones to come
  98. end
  99.  
  100. defmodule RFC822Test do
  101. use ExUnit.Case
  102.  
  103. test "parses the string" do
  104. string = "Wed, 02 Oct 02 08:00:00 EST"
  105. assert {:ok, datetime} = RFC822.parse(string)
  106. assert datetime.year == 2002
  107. assert datetime.month == 10
  108. assert datetime.day == 2
  109. assert datetime.hour == 3
  110. assert datetime.minute == 0
  111. assert datetime.second == 0
  112.  
  113. string = "02 Oct 19 08:00:00 EST"
  114. assert {:ok, datetime} = RFC822.parse(string)
  115. assert datetime.year == 2019
  116. assert datetime.month == 10
  117. assert datetime.day == 2
  118. assert datetime.hour == 3
  119. assert datetime.minute == 0
  120. assert datetime.second == 0
  121.  
  122. string = "Wednesday, 02 Oct 19 08:00:00 EST"
  123. assert {:error, invalid} = RFC822.parse(string)
  124. end
  125. end
Add Comment
Please, Sign In to add comment