parser.go 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // Copyright 2017 Frédéric Guillot. All rights reserved.
  2. // Use of this source code is governed by the Apache 2.0
  3. // license that can be found in the LICENSE file.
  4. package date // import "miniflux.app/reader/date"
  5. import (
  6. "errors"
  7. "fmt"
  8. "strconv"
  9. "strings"
  10. "time"
  11. )
  12. // DateFormats taken from github.com/mjibson/goread
  13. var dateFormats = []string{
  14. time.RFC822, // RSS
  15. time.RFC822Z, // RSS
  16. time.RFC3339, // Atom
  17. time.UnixDate,
  18. time.RubyDate,
  19. time.RFC850,
  20. time.RFC1123Z,
  21. time.RFC1123,
  22. time.ANSIC,
  23. "Mon, 02 Jan 2006 15:04:05 MST -07:00",
  24. "Mon, January 2, 2006, 3:04 PM MST",
  25. "Mon, January 2 2006 15:04:05 -0700",
  26. "Mon, January 02, 2006, 15:04:05 MST",
  27. "Mon, January 02, 2006 15:04:05 MST",
  28. "Mon, Jan 2, 2006 15:04 MST",
  29. "Mon, Jan 2 2006 15:04 MST",
  30. "Mon, Jan 2 2006 15:04:05 MST",
  31. "Mon, Jan 2, 2006 15:04:05 MST",
  32. "Mon, Jan 2 2006 15:04:05 -700",
  33. "Mon, Jan 2 2006 15:04:05 -0700",
  34. "Mon Jan 2 15:04 2006",
  35. "Mon Jan 2 15:04:05 2006 MST",
  36. "Mon Jan 02, 2006 3:04 pm",
  37. "Mon, Jan 02,2006 15:04:05 MST",
  38. "Mon Jan 02 2006 15:04:05 -0700",
  39. "Mon, 02/01/2006",
  40. "Monday, 2. January 2006 - 15:04",
  41. "Monday 02 January 2006",
  42. "Monday, January 2, 2006 15:04:05 MST",
  43. "Monday, January 2, 2006 03:04 PM",
  44. "Monday, January 2, 2006",
  45. "Monday, January 02, 2006",
  46. "Monday, 2 January 2006 15:04:05 MST",
  47. "Monday, 2 January 2006 15:04:05 -0700",
  48. "Monday, 2 Jan 2006 15:04:05 MST",
  49. "Monday, 2 Jan 2006 15:04:05 -0700",
  50. "Monday, 02 January 2006 15:04:05 MST",
  51. "Monday, 02 January 2006 15:04:05 -0700",
  52. "Monday, 02 January 2006 15:04:05",
  53. "Monday, January 02, 2006 - 3:04pm",
  54. "Monday, January 2, 2006 - 3:04pm",
  55. "Mon, 01/02/2006 - 15:04",
  56. "Mon, 2 January 2006 15:04 MST",
  57. "Mon, 2 January 2006, 15:04 -0700",
  58. "Mon, 2 January 2006, 15:04:05 MST",
  59. "Mon, 2 January 2006 15:04:05 MST",
  60. "Mon, 2 January 2006 15:04:05 -0700",
  61. "Mon, 2 January 2006",
  62. "Mon, 2 Jan 2006 3:04:05 PM -0700",
  63. "Mon, 2 Jan 2006 15:4:5 MST",
  64. "Mon, 2 Jan 2006 15:4:5 -0700 GMT",
  65. "Mon, 2, Jan 2006 15:4",
  66. "Mon, 2 Jan 2006 15:04 MST",
  67. "Mon, 2 Jan 2006, 15:04 -0700",
  68. "Mon, 2 Jan 2006 15:04 -0700",
  69. "Mon, 2 Jan 2006 15:04:05 UT",
  70. "Mon, 2 Jan 2006 15:04:05MST",
  71. "Mon, 2 Jan 2006 15:04:05 MST",
  72. "Mon 2 Jan 2006 15:04:05 MST",
  73. "mon,2 Jan 2006 15:04:05 MST",
  74. "Mon, 2 Jan 2006 15:04:05 -0700 MST",
  75. "Mon, 2 Jan 2006 15:04:05-0700",
  76. "Mon, 2 Jan 2006 15:04:05 -0700",
  77. "Mon, 2 Jan 2006 15:04:05",
  78. "Mon, 2 Jan 2006 15:04",
  79. "Mon, 02 Jan 2006, 15:04",
  80. "Mon, 2 Jan 2006, 15:04",
  81. "Mon,2 Jan 2006",
  82. "Mon, 2 Jan 2006",
  83. "Mon, 2 Jan 15:04:05 MST",
  84. "Mon, 2 Jan 06 15:04:05 MST",
  85. "Mon, 2 Jan 06 15:04:05 -0700",
  86. "Mon, 2006-01-02 15:04",
  87. "Mon,02 January 2006 14:04:05 MST",
  88. "Mon, 02 January 2006",
  89. "Mon, 02 Jan 2006 3:04:05 PM MST",
  90. "Mon, 02 Jan 2006 15 -0700",
  91. "Mon,02 Jan 2006 15:04 MST",
  92. "Mon, 02 Jan 2006 15:04 MST",
  93. "Mon, 02 Jan 2006 15:04 -0700",
  94. "Mon, 02 Jan 2006 15:04:05 Z",
  95. "Mon, 02 Jan 2006 15:04:05 UT",
  96. "Mon, 02 Jan 2006 15:04:05 MST-07:00",
  97. "Mon, 02 Jan 2006 15:04:05 MST -0700",
  98. "Mon, 02 Jan 2006, 15:04:05 MST",
  99. "Mon, 02 Jan 2006 15:04:05MST",
  100. "Mon, 02 Jan 2006 15:04:05 MST",
  101. "Mon , 02 Jan 2006 15:04:05 MST",
  102. "Mon, 02 Jan 2006 15:04:05 GMT-0700",
  103. "Mon,02 Jan 2006 15:04:05 -0700",
  104. "Mon, 02 Jan 2006 15:04:05 -0700",
  105. "Mon, 02 Jan 2006 15:04:05 -07:00",
  106. "Mon, 02 Jan 2006 15:04:05 --0700",
  107. "Mon 02 Jan 2006 15:04:05 -0700",
  108. "Mon 02 Jan 2006, 15:04:05 MST",
  109. "Mon, 02 Jan 2006 15:04:05 MST",
  110. "Mon, 02 Jan 2006 15:04:05 -07",
  111. "Mon, 02 Jan 2006 15:04:05 00",
  112. "Mon, 02 Jan 2006 15:04:05",
  113. "Mon, 02 Jan 2006",
  114. "Mon, 02 Jan 06 15:04:05 MST",
  115. "Mon, 02 Jan 2006 3:04 PM MST",
  116. "Mon Jan 02 2006 15:04:05 MST",
  117. "Mon, 01 02 2006 15:04:05 -0700",
  118. "Mon, 2th Jan 2006 15:05:05 MST",
  119. "Jan. 2, 2006, 3:04 a.m.",
  120. "fri, 02 jan 2006 15:04:05 -0700",
  121. "January 02 2006 03:04:05 PM",
  122. "January 2, 2006 3:04 PM",
  123. "January 2, 2006, 3:04 p.m.",
  124. "January 2, 2006 15:04:05 MST",
  125. "January 2, 2006 15:04:05",
  126. "January 2, 2006 03:04 PM",
  127. "January 2, 2006",
  128. "January 02, 2006 15:04:05 MST",
  129. "January 02, 2006 15:04",
  130. "January 02, 2006 03:04 PM",
  131. "January 02, 2006",
  132. "Jan 2, 2006 3:04:05 PM MST",
  133. "Jan 2, 2006 3:04:05 PM",
  134. "Jan 2, 2006 15:04:05 MST",
  135. "Jan 2, 2006",
  136. "Jan 02 2006 03:04:05PM",
  137. "Jan 02, 2006",
  138. "6/1/2 15:04",
  139. "6-1-2 15:04",
  140. "2 January 2006 15:04:05 MST",
  141. "2 January 2006 15:04:05 -0700",
  142. "2 January 2006",
  143. "2 Jan 2006 15:04:05 Z",
  144. "2 Jan 2006 15:04:05 MST",
  145. "2 Jan 2006 15:04:05 -0700",
  146. "2 Jan 2006",
  147. "2 Jan 2006 15:04 MST",
  148. "2.1.2006 15:04:05",
  149. "2/1/2006",
  150. "2-1-2006",
  151. "2006 January 02",
  152. "2006-1-2T15:04:05Z",
  153. "2006-1-2 15:04:05",
  154. "2006-1-2",
  155. "2006-01-02T15:04:05-07:00Z",
  156. "2006-1-02T15:04:05Z",
  157. "2006-01-02T15:04Z",
  158. "2006-01-02T15:04-07:00",
  159. "2006-01-02T15:04:05Z",
  160. "2006-01-02T15:04:05-07:00:00",
  161. "2006-01-02T15:04:05:-0700",
  162. "2006-01-02T15:04:05-0700",
  163. "2006-01-02T15:04:05-07:00",
  164. "2006-01-02T15:04:05 -0700",
  165. "2006-01-02T15:04:05:00",
  166. "2006-01-02T15:04:05",
  167. "2006-01-02T15:04",
  168. "2006-01-02 at 15:04:05",
  169. "2006-01-02 15:04:05Z",
  170. "2006-01-02 15:04:05 MST",
  171. "2006-01-02 15:04:05-0700",
  172. "2006-01-02 15:04:05-07:00",
  173. "2006-01-02 15:04:05 -0700",
  174. "2006-01-02 15:04",
  175. "2006-01-02 00:00:00.0 15:04:05.0 -0700",
  176. "2006/01/02",
  177. "2006-01-02",
  178. "15:04 02.01.2006 -0700",
  179. "1/2/2006 3:04 PM MST",
  180. "1/2/2006 3:04:05 PM MST",
  181. "1/2/2006 3:04:05 PM",
  182. "1/2/2006 15:04:05 MST",
  183. "1/2/2006",
  184. "06/1/2 15:04",
  185. "06-1-2 15:04",
  186. "02 Monday, Jan 2006 15:04",
  187. "02 Jan 2006 15:04 MST",
  188. "02 Jan 2006 15:04:05 UT",
  189. "02 Jan 2006 15:04:05 MST",
  190. "02 Jan 2006 15:04:05 -0700",
  191. "02 Jan 2006 15:04:05",
  192. "02 Jan 2006",
  193. "02/01/2006 15:04 MST",
  194. "02-01-2006 15:04:05 MST",
  195. "02.01.2006 15:04:05",
  196. "02/01/2006 15:04:05",
  197. "02.01.2006 15:04",
  198. "02/01/2006 - 15:04",
  199. "02.01.2006 -0700",
  200. "02/01/2006",
  201. "02-01-2006",
  202. "01/02/2006 3:04 PM",
  203. "01/02/2006 15:04:05 MST",
  204. "01/02/2006 - 15:04",
  205. "01/02/2006",
  206. "01-02-2006",
  207. "Jan. 2006",
  208. "Jan. 2, 2006, 03:04 p.m.",
  209. "2006-01-02 15:04:05 -07:00",
  210. "2 January, 2006",
  211. }
  212. var invalidTimezoneReplacer = strings.NewReplacer(
  213. "Europe/Brussels", "CET",
  214. "GMT+0000 (Coordinated Universal Time)", "GMT",
  215. "GMT-", "GMT -",
  216. )
  217. var invalidLocalizedDateReplacer = strings.NewReplacer(
  218. "Mo,", "Mon,",
  219. "Di,", "Tue,",
  220. "Mi,", "Wed,",
  221. "Do,", "Thu,",
  222. "Fr,", "Fri,",
  223. "Sa,", "Sat,",
  224. "So,", "Sun,",
  225. "Mär ", "Mar ",
  226. "Mai ", "May ",
  227. "Okt ", "Oct ",
  228. "Dez ", "Dec ",
  229. "lun,", "Mon,",
  230. "mar,", "Tue,",
  231. "mer,", "Wed,",
  232. "jeu,", "Thu,",
  233. "ven,", "Fri,",
  234. "sam,", "Sat,",
  235. "dim,", "Sun,",
  236. "lun.", "Mon",
  237. "mar.", "Tue",
  238. "mer.", "Wed",
  239. "jeu.", "Thu",
  240. "ven.", "Fri",
  241. "sam.", "Sat",
  242. "dim.", "Sun",
  243. "Lundi,", "Monday,",
  244. "Mardi,", "Tuesday,",
  245. "Mercredi,", "Wednesday,",
  246. "Jeudi,", "Thursday,",
  247. "Vendredi,", "Friday,",
  248. "Samedi,", "Saturday,",
  249. "Dimanche,", "Sunday,",
  250. "jan.", "January ",
  251. "feb.", "February ",
  252. "mars.", "March ",
  253. "avril.", "April ",
  254. "mai.", "May ",
  255. "juin.", "June ",
  256. "juil.", "July",
  257. "août.", "August",
  258. "sept.", "September",
  259. "oct.", "October",
  260. "nov.", "November",
  261. "dec.", "December",
  262. "déc.", "December",
  263. "janvier ", "January ",
  264. "février ", "February ",
  265. "mars ", "March ",
  266. "avril ", "April ",
  267. "mai ", "May ",
  268. "juin ", "June ",
  269. "juillet ", "July",
  270. "août ", "August",
  271. "septembre ", "September",
  272. "octobre ", "October",
  273. "november ", "November",
  274. "décembre ", "December",
  275. "Janvier", "January",
  276. "Février", "February",
  277. "Mars", "March",
  278. "Avril", "April",
  279. "Mai", "May",
  280. "Juin", "June",
  281. "Juillet", "July",
  282. "Août", "August",
  283. "Septembre", "September",
  284. "Octobre", "October",
  285. "Novembre", "November",
  286. "Décembre", "December",
  287. "avr ", "Apr ",
  288. "mai ", "May ",
  289. "jui ", "Jun ",
  290. "juin ", "June ",
  291. "Thurs,", "Thu,",
  292. "Thur,", "Thu,",
  293. )
  294. // Parse parses a given date string using a large
  295. // list of commonly found feed date formats.
  296. func Parse(rawInput string) (t time.Time, err error) {
  297. timestamp, err := strconv.ParseInt(rawInput, 10, 64)
  298. if err == nil {
  299. return time.Unix(timestamp, 0), nil
  300. }
  301. processedInput := invalidLocalizedDateReplacer.Replace(rawInput)
  302. processedInput = invalidTimezoneReplacer.Replace(processedInput)
  303. processedInput = strings.TrimSpace(processedInput)
  304. if processedInput == "" {
  305. return t, errors.New(`date parser: empty value`)
  306. }
  307. for _, layout := range dateFormats {
  308. switch layout {
  309. case time.RFC822, time.RFC850, time.RFC1123:
  310. if t, err = parseLocalTimeDates(layout, processedInput); err == nil {
  311. return
  312. }
  313. }
  314. if t, err = time.Parse(layout, processedInput); err == nil {
  315. return
  316. }
  317. }
  318. err = fmt.Errorf(`date parser: failed to parse date "%s"`, rawInput)
  319. return
  320. }
  321. // According to Golang documentation:
  322. //
  323. // RFC822, RFC850, and RFC1123 formats should be applied only to local times.
  324. // Applying them to UTC times will use "UTC" as the time zone abbreviation,
  325. // while strictly speaking those RFCs require the use of "GMT" in that case.
  326. func parseLocalTimeDates(layout, ds string) (t time.Time, err error) {
  327. loc := time.UTC
  328. // Workaround for dates that don't use GMT.
  329. if strings.HasSuffix(ds, "PST") || strings.HasSuffix(ds, "PDT") {
  330. loc, _ = time.LoadLocation("America/Los_Angeles")
  331. }
  332. if strings.HasSuffix(ds, "EST") || strings.HasSuffix(ds, "EDT") {
  333. loc, _ = time.LoadLocation("America/New_York")
  334. }
  335. return time.ParseInLocation(layout, ds, loc)
  336. }