date.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653
  1. 'use strict'
  2. /**
  3. * @see https://www.rfc-editor.org/rfc/rfc9110.html#name-date-time-formats
  4. *
  5. * @param {string} date
  6. * @returns {Date | undefined}
  7. */
  8. function parseHttpDate (date) {
  9. // Sun, 06 Nov 1994 08:49:37 GMT ; IMF-fixdate
  10. // Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
  11. // Sunday, 06-Nov-94 08:49:37 GMT ; obsolete RFC 850 format
  12. switch (date[3]) {
  13. case ',': return parseImfDate(date)
  14. case ' ': return parseAscTimeDate(date)
  15. default: return parseRfc850Date(date)
  16. }
  17. }
  18. /**
  19. * @see https://httpwg.org/specs/rfc9110.html#preferred.date.format
  20. *
  21. * @param {string} date
  22. * @returns {Date | undefined}
  23. */
  24. function parseImfDate (date) {
  25. if (
  26. date.length !== 29 ||
  27. date[4] !== ' ' ||
  28. date[7] !== ' ' ||
  29. date[11] !== ' ' ||
  30. date[16] !== ' ' ||
  31. date[19] !== ':' ||
  32. date[22] !== ':' ||
  33. date[25] !== ' ' ||
  34. date[26] !== 'G' ||
  35. date[27] !== 'M' ||
  36. date[28] !== 'T'
  37. ) {
  38. return undefined
  39. }
  40. let weekday = -1
  41. if (date[0] === 'S' && date[1] === 'u' && date[2] === 'n') { // Sunday
  42. weekday = 0
  43. } else if (date[0] === 'M' && date[1] === 'o' && date[2] === 'n') { // Monday
  44. weekday = 1
  45. } else if (date[0] === 'T' && date[1] === 'u' && date[2] === 'e') { // Tuesday
  46. weekday = 2
  47. } else if (date[0] === 'W' && date[1] === 'e' && date[2] === 'd') { // Wednesday
  48. weekday = 3
  49. } else if (date[0] === 'T' && date[1] === 'h' && date[2] === 'u') { // Thursday
  50. weekday = 4
  51. } else if (date[0] === 'F' && date[1] === 'r' && date[2] === 'i') { // Friday
  52. weekday = 5
  53. } else if (date[0] === 'S' && date[1] === 'a' && date[2] === 't') { // Saturday
  54. weekday = 6
  55. } else {
  56. return undefined // Not a valid day of the week
  57. }
  58. let day = 0
  59. if (date[5] === '0') {
  60. // Single digit day, e.g. "Sun Nov 6 08:49:37 1994"
  61. const code = date.charCodeAt(6)
  62. if (code < 49 || code > 57) {
  63. return undefined // Not a digit
  64. }
  65. day = code - 48 // Convert ASCII code to number
  66. } else {
  67. const code1 = date.charCodeAt(5)
  68. if (code1 < 49 || code1 > 51) {
  69. return undefined // Not a digit between 1 and 3
  70. }
  71. const code2 = date.charCodeAt(6)
  72. if (code2 < 48 || code2 > 57) {
  73. return undefined // Not a digit
  74. }
  75. day = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  76. }
  77. let monthIdx = -1
  78. if (
  79. (date[8] === 'J' && date[9] === 'a' && date[10] === 'n')
  80. ) {
  81. monthIdx = 0 // Jan
  82. } else if (
  83. (date[8] === 'F' && date[9] === 'e' && date[10] === 'b')
  84. ) {
  85. monthIdx = 1 // Feb
  86. } else if (
  87. (date[8] === 'M' && date[9] === 'a')
  88. ) {
  89. if (date[10] === 'r') {
  90. monthIdx = 2 // Mar
  91. } else if (date[10] === 'y') {
  92. monthIdx = 4 // May
  93. } else {
  94. return undefined // Invalid month
  95. }
  96. } else if (
  97. (date[8] === 'J')
  98. ) {
  99. if (date[9] === 'a' && date[10] === 'n') {
  100. monthIdx = 0 // Jan
  101. } else if (date[9] === 'u') {
  102. if (date[10] === 'n') {
  103. monthIdx = 5 // Jun
  104. } else if (date[10] === 'l') {
  105. monthIdx = 6 // Jul
  106. } else {
  107. return undefined // Invalid month
  108. }
  109. } else {
  110. return undefined // Invalid month
  111. }
  112. } else if (
  113. (date[8] === 'A')
  114. ) {
  115. if (date[9] === 'p' && date[10] === 'r') {
  116. monthIdx = 3 // Apr
  117. } else if (date[9] === 'u' && date[10] === 'g') {
  118. monthIdx = 7 // Aug
  119. } else {
  120. return undefined // Invalid month
  121. }
  122. } else if (
  123. (date[8] === 'S' && date[9] === 'e' && date[10] === 'p')
  124. ) {
  125. monthIdx = 8 // Sep
  126. } else if (
  127. (date[8] === 'O' && date[9] === 'c' && date[10] === 't')
  128. ) {
  129. monthIdx = 9 // Oct
  130. } else if (
  131. (date[8] === 'N' && date[9] === 'o' && date[10] === 'v')
  132. ) {
  133. monthIdx = 10 // Nov
  134. } else if (
  135. (date[8] === 'D' && date[9] === 'e' && date[10] === 'c')
  136. ) {
  137. monthIdx = 11 // Dec
  138. } else {
  139. // Not a valid month
  140. return undefined
  141. }
  142. const yearDigit1 = date.charCodeAt(12)
  143. if (yearDigit1 < 48 || yearDigit1 > 57) {
  144. return undefined // Not a digit
  145. }
  146. const yearDigit2 = date.charCodeAt(13)
  147. if (yearDigit2 < 48 || yearDigit2 > 57) {
  148. return undefined // Not a digit
  149. }
  150. const yearDigit3 = date.charCodeAt(14)
  151. if (yearDigit3 < 48 || yearDigit3 > 57) {
  152. return undefined // Not a digit
  153. }
  154. const yearDigit4 = date.charCodeAt(15)
  155. if (yearDigit4 < 48 || yearDigit4 > 57) {
  156. return undefined // Not a digit
  157. }
  158. const year = (yearDigit1 - 48) * 1000 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48)
  159. let hour = 0
  160. if (date[17] === '0') {
  161. const code = date.charCodeAt(18)
  162. if (code < 48 || code > 57) {
  163. return undefined // Not a digit
  164. }
  165. hour = code - 48 // Convert ASCII code to number
  166. } else {
  167. const code1 = date.charCodeAt(17)
  168. if (code1 < 48 || code1 > 50) {
  169. return undefined // Not a digit between 0 and 2
  170. }
  171. const code2 = date.charCodeAt(18)
  172. if (code2 < 48 || code2 > 57) {
  173. return undefined // Not a digit
  174. }
  175. if (code1 === 50 && code2 > 51) {
  176. return undefined // Hour cannot be greater than 23
  177. }
  178. hour = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  179. }
  180. let minute = 0
  181. if (date[20] === '0') {
  182. const code = date.charCodeAt(21)
  183. if (code < 48 || code > 57) {
  184. return undefined // Not a digit
  185. }
  186. minute = code - 48 // Convert ASCII code to number
  187. } else {
  188. const code1 = date.charCodeAt(20)
  189. if (code1 < 48 || code1 > 53) {
  190. return undefined // Not a digit between 0 and 5
  191. }
  192. const code2 = date.charCodeAt(21)
  193. if (code2 < 48 || code2 > 57) {
  194. return undefined // Not a digit
  195. }
  196. minute = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  197. }
  198. let second = 0
  199. if (date[23] === '0') {
  200. const code = date.charCodeAt(24)
  201. if (code < 48 || code > 57) {
  202. return undefined // Not a digit
  203. }
  204. second = code - 48 // Convert ASCII code to number
  205. } else {
  206. const code1 = date.charCodeAt(23)
  207. if (code1 < 48 || code1 > 53) {
  208. return undefined // Not a digit between 0 and 5
  209. }
  210. const code2 = date.charCodeAt(24)
  211. if (code2 < 48 || code2 > 57) {
  212. return undefined // Not a digit
  213. }
  214. second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  215. }
  216. const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
  217. return result.getUTCDay() === weekday ? result : undefined
  218. }
  219. /**
  220. * @see https://httpwg.org/specs/rfc9110.html#obsolete.date.formats
  221. *
  222. * @param {string} date
  223. * @returns {Date | undefined}
  224. */
  225. function parseAscTimeDate (date) {
  226. // This is assumed to be in UTC
  227. if (
  228. date.length !== 24 ||
  229. date[7] !== ' ' ||
  230. date[10] !== ' ' ||
  231. date[19] !== ' '
  232. ) {
  233. return undefined
  234. }
  235. let weekday = -1
  236. if (date[0] === 'S' && date[1] === 'u' && date[2] === 'n') { // Sunday
  237. weekday = 0
  238. } else if (date[0] === 'M' && date[1] === 'o' && date[2] === 'n') { // Monday
  239. weekday = 1
  240. } else if (date[0] === 'T' && date[1] === 'u' && date[2] === 'e') { // Tuesday
  241. weekday = 2
  242. } else if (date[0] === 'W' && date[1] === 'e' && date[2] === 'd') { // Wednesday
  243. weekday = 3
  244. } else if (date[0] === 'T' && date[1] === 'h' && date[2] === 'u') { // Thursday
  245. weekday = 4
  246. } else if (date[0] === 'F' && date[1] === 'r' && date[2] === 'i') { // Friday
  247. weekday = 5
  248. } else if (date[0] === 'S' && date[1] === 'a' && date[2] === 't') { // Saturday
  249. weekday = 6
  250. } else {
  251. return undefined // Not a valid day of the week
  252. }
  253. let monthIdx = -1
  254. if (
  255. (date[4] === 'J' && date[5] === 'a' && date[6] === 'n')
  256. ) {
  257. monthIdx = 0 // Jan
  258. } else if (
  259. (date[4] === 'F' && date[5] === 'e' && date[6] === 'b')
  260. ) {
  261. monthIdx = 1 // Feb
  262. } else if (
  263. (date[4] === 'M' && date[5] === 'a')
  264. ) {
  265. if (date[6] === 'r') {
  266. monthIdx = 2 // Mar
  267. } else if (date[6] === 'y') {
  268. monthIdx = 4 // May
  269. } else {
  270. return undefined // Invalid month
  271. }
  272. } else if (
  273. (date[4] === 'J')
  274. ) {
  275. if (date[5] === 'a' && date[6] === 'n') {
  276. monthIdx = 0 // Jan
  277. } else if (date[5] === 'u') {
  278. if (date[6] === 'n') {
  279. monthIdx = 5 // Jun
  280. } else if (date[6] === 'l') {
  281. monthIdx = 6 // Jul
  282. } else {
  283. return undefined // Invalid month
  284. }
  285. } else {
  286. return undefined // Invalid month
  287. }
  288. } else if (
  289. (date[4] === 'A')
  290. ) {
  291. if (date[5] === 'p' && date[6] === 'r') {
  292. monthIdx = 3 // Apr
  293. } else if (date[5] === 'u' && date[6] === 'g') {
  294. monthIdx = 7 // Aug
  295. } else {
  296. return undefined // Invalid month
  297. }
  298. } else if (
  299. (date[4] === 'S' && date[5] === 'e' && date[6] === 'p')
  300. ) {
  301. monthIdx = 8 // Sep
  302. } else if (
  303. (date[4] === 'O' && date[5] === 'c' && date[6] === 't')
  304. ) {
  305. monthIdx = 9 // Oct
  306. } else if (
  307. (date[4] === 'N' && date[5] === 'o' && date[6] === 'v')
  308. ) {
  309. monthIdx = 10 // Nov
  310. } else if (
  311. (date[4] === 'D' && date[5] === 'e' && date[6] === 'c')
  312. ) {
  313. monthIdx = 11 // Dec
  314. } else {
  315. // Not a valid month
  316. return undefined
  317. }
  318. let day = 0
  319. if (date[8] === ' ') {
  320. // Single digit day, e.g. "Sun Nov 6 08:49:37 1994"
  321. const code = date.charCodeAt(9)
  322. if (code < 49 || code > 57) {
  323. return undefined // Not a digit
  324. }
  325. day = code - 48 // Convert ASCII code to number
  326. } else {
  327. const code1 = date.charCodeAt(8)
  328. if (code1 < 49 || code1 > 51) {
  329. return undefined // Not a digit between 1 and 3
  330. }
  331. const code2 = date.charCodeAt(9)
  332. if (code2 < 48 || code2 > 57) {
  333. return undefined // Not a digit
  334. }
  335. day = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  336. }
  337. let hour = 0
  338. if (date[11] === '0') {
  339. const code = date.charCodeAt(12)
  340. if (code < 48 || code > 57) {
  341. return undefined // Not a digit
  342. }
  343. hour = code - 48 // Convert ASCII code to number
  344. } else {
  345. const code1 = date.charCodeAt(11)
  346. if (code1 < 48 || code1 > 50) {
  347. return undefined // Not a digit between 0 and 2
  348. }
  349. const code2 = date.charCodeAt(12)
  350. if (code2 < 48 || code2 > 57) {
  351. return undefined // Not a digit
  352. }
  353. if (code1 === 50 && code2 > 51) {
  354. return undefined // Hour cannot be greater than 23
  355. }
  356. hour = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  357. }
  358. let minute = 0
  359. if (date[14] === '0') {
  360. const code = date.charCodeAt(15)
  361. if (code < 48 || code > 57) {
  362. return undefined // Not a digit
  363. }
  364. minute = code - 48 // Convert ASCII code to number
  365. } else {
  366. const code1 = date.charCodeAt(14)
  367. if (code1 < 48 || code1 > 53) {
  368. return undefined // Not a digit between 0 and 5
  369. }
  370. const code2 = date.charCodeAt(15)
  371. if (code2 < 48 || code2 > 57) {
  372. return undefined // Not a digit
  373. }
  374. minute = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  375. }
  376. let second = 0
  377. if (date[17] === '0') {
  378. const code = date.charCodeAt(18)
  379. if (code < 48 || code > 57) {
  380. return undefined // Not a digit
  381. }
  382. second = code - 48 // Convert ASCII code to number
  383. } else {
  384. const code1 = date.charCodeAt(17)
  385. if (code1 < 48 || code1 > 53) {
  386. return undefined // Not a digit between 0 and 5
  387. }
  388. const code2 = date.charCodeAt(18)
  389. if (code2 < 48 || code2 > 57) {
  390. return undefined // Not a digit
  391. }
  392. second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  393. }
  394. const yearDigit1 = date.charCodeAt(20)
  395. if (yearDigit1 < 48 || yearDigit1 > 57) {
  396. return undefined // Not a digit
  397. }
  398. const yearDigit2 = date.charCodeAt(21)
  399. if (yearDigit2 < 48 || yearDigit2 > 57) {
  400. return undefined // Not a digit
  401. }
  402. const yearDigit3 = date.charCodeAt(22)
  403. if (yearDigit3 < 48 || yearDigit3 > 57) {
  404. return undefined // Not a digit
  405. }
  406. const yearDigit4 = date.charCodeAt(23)
  407. if (yearDigit4 < 48 || yearDigit4 > 57) {
  408. return undefined // Not a digit
  409. }
  410. const year = (yearDigit1 - 48) * 1000 + (yearDigit2 - 48) * 100 + (yearDigit3 - 48) * 10 + (yearDigit4 - 48)
  411. const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
  412. return result.getUTCDay() === weekday ? result : undefined
  413. }
  414. /**
  415. * @see https://httpwg.org/specs/rfc9110.html#obsolete.date.formats
  416. *
  417. * @param {string} date
  418. * @returns {Date | undefined}
  419. */
  420. function parseRfc850Date (date) {
  421. let commaIndex = -1
  422. let weekday = -1
  423. if (date[0] === 'S') {
  424. if (date[1] === 'u' && date[2] === 'n' && date[3] === 'd' && date[4] === 'a' && date[5] === 'y') {
  425. weekday = 0 // Sunday
  426. commaIndex = 6
  427. } else if (date[1] === 'a' && date[2] === 't' && date[3] === 'u' && date[4] === 'r' && date[5] === 'd' && date[6] === 'a' && date[7] === 'y') {
  428. weekday = 6 // Saturday
  429. commaIndex = 8
  430. }
  431. } else if (date[0] === 'M' && date[1] === 'o' && date[2] === 'n' && date[3] === 'd' && date[4] === 'a' && date[5] === 'y') {
  432. weekday = 1 // Monday
  433. commaIndex = 6
  434. } else if (date[0] === 'T') {
  435. if (date[1] === 'u' && date[2] === 'e' && date[3] === 's' && date[4] === 'd' && date[5] === 'a' && date[6] === 'y') {
  436. weekday = 2 // Tuesday
  437. commaIndex = 7
  438. } else if (date[1] === 'h' && date[2] === 'u' && date[3] === 'r' && date[4] === 's' && date[5] === 'd' && date[6] === 'a' && date[7] === 'y') {
  439. weekday = 4 // Thursday
  440. commaIndex = 8
  441. }
  442. } else if (date[0] === 'W' && date[1] === 'e' && date[2] === 'd' && date[3] === 'n' && date[4] === 'e' && date[5] === 's' && date[6] === 'd' && date[7] === 'a' && date[8] === 'y') {
  443. weekday = 3 // Wednesday
  444. commaIndex = 9
  445. } else if (date[0] === 'F' && date[1] === 'r' && date[2] === 'i' && date[3] === 'd' && date[4] === 'a' && date[5] === 'y') {
  446. weekday = 5 // Friday
  447. commaIndex = 6
  448. } else {
  449. // Not a valid day name
  450. return undefined
  451. }
  452. if (
  453. date[commaIndex] !== ',' ||
  454. (date.length - commaIndex - 1) !== 23 ||
  455. date[commaIndex + 1] !== ' ' ||
  456. date[commaIndex + 4] !== '-' ||
  457. date[commaIndex + 8] !== '-' ||
  458. date[commaIndex + 11] !== ' ' ||
  459. date[commaIndex + 14] !== ':' ||
  460. date[commaIndex + 17] !== ':' ||
  461. date[commaIndex + 20] !== ' ' ||
  462. date[commaIndex + 21] !== 'G' ||
  463. date[commaIndex + 22] !== 'M' ||
  464. date[commaIndex + 23] !== 'T'
  465. ) {
  466. return undefined
  467. }
  468. let day = 0
  469. if (date[commaIndex + 2] === '0') {
  470. // Single digit day, e.g. "Sun Nov 6 08:49:37 1994"
  471. const code = date.charCodeAt(commaIndex + 3)
  472. if (code < 49 || code > 57) {
  473. return undefined // Not a digit
  474. }
  475. day = code - 48 // Convert ASCII code to number
  476. } else {
  477. const code1 = date.charCodeAt(commaIndex + 2)
  478. if (code1 < 49 || code1 > 51) {
  479. return undefined // Not a digit between 1 and 3
  480. }
  481. const code2 = date.charCodeAt(commaIndex + 3)
  482. if (code2 < 48 || code2 > 57) {
  483. return undefined // Not a digit
  484. }
  485. day = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  486. }
  487. let monthIdx = -1
  488. if (
  489. (date[commaIndex + 5] === 'J' && date[commaIndex + 6] === 'a' && date[commaIndex + 7] === 'n')
  490. ) {
  491. monthIdx = 0 // Jan
  492. } else if (
  493. (date[commaIndex + 5] === 'F' && date[commaIndex + 6] === 'e' && date[commaIndex + 7] === 'b')
  494. ) {
  495. monthIdx = 1 // Feb
  496. } else if (
  497. (date[commaIndex + 5] === 'M' && date[commaIndex + 6] === 'a' && date[commaIndex + 7] === 'r')
  498. ) {
  499. monthIdx = 2 // Mar
  500. } else if (
  501. (date[commaIndex + 5] === 'A' && date[commaIndex + 6] === 'p' && date[commaIndex + 7] === 'r')
  502. ) {
  503. monthIdx = 3 // Apr
  504. } else if (
  505. (date[commaIndex + 5] === 'M' && date[commaIndex + 6] === 'a' && date[commaIndex + 7] === 'y')
  506. ) {
  507. monthIdx = 4 // May
  508. } else if (
  509. (date[commaIndex + 5] === 'J' && date[commaIndex + 6] === 'u' && date[commaIndex + 7] === 'n')
  510. ) {
  511. monthIdx = 5 // Jun
  512. } else if (
  513. (date[commaIndex + 5] === 'J' && date[commaIndex + 6] === 'u' && date[commaIndex + 7] === 'l')
  514. ) {
  515. monthIdx = 6 // Jul
  516. } else if (
  517. (date[commaIndex + 5] === 'A' && date[commaIndex + 6] === 'u' && date[commaIndex + 7] === 'g')
  518. ) {
  519. monthIdx = 7 // Aug
  520. } else if (
  521. (date[commaIndex + 5] === 'S' && date[commaIndex + 6] === 'e' && date[commaIndex + 7] === 'p')
  522. ) {
  523. monthIdx = 8 // Sep
  524. } else if (
  525. (date[commaIndex + 5] === 'O' && date[commaIndex + 6] === 'c' && date[commaIndex + 7] === 't')
  526. ) {
  527. monthIdx = 9 // Oct
  528. } else if (
  529. (date[commaIndex + 5] === 'N' && date[commaIndex + 6] === 'o' && date[commaIndex + 7] === 'v')
  530. ) {
  531. monthIdx = 10 // Nov
  532. } else if (
  533. (date[commaIndex + 5] === 'D' && date[commaIndex + 6] === 'e' && date[commaIndex + 7] === 'c')
  534. ) {
  535. monthIdx = 11 // Dec
  536. } else {
  537. // Not a valid month
  538. return undefined
  539. }
  540. const yearDigit1 = date.charCodeAt(commaIndex + 9)
  541. if (yearDigit1 < 48 || yearDigit1 > 57) {
  542. return undefined // Not a digit
  543. }
  544. const yearDigit2 = date.charCodeAt(commaIndex + 10)
  545. if (yearDigit2 < 48 || yearDigit2 > 57) {
  546. return undefined // Not a digit
  547. }
  548. let year = (yearDigit1 - 48) * 10 + (yearDigit2 - 48) // Convert ASCII codes to number
  549. // RFC 6265 states that the year is in the range 1970-2069.
  550. // @see https://datatracker.ietf.org/doc/html/rfc6265#section-5.1.1
  551. //
  552. // 3. If the year-value is greater than or equal to 70 and less than or
  553. // equal to 99, increment the year-value by 1900.
  554. // 4. If the year-value is greater than or equal to 0 and less than or
  555. // equal to 69, increment the year-value by 2000.
  556. year += year < 70 ? 2000 : 1900
  557. let hour = 0
  558. if (date[commaIndex + 12] === '0') {
  559. const code = date.charCodeAt(commaIndex + 13)
  560. if (code < 48 || code > 57) {
  561. return undefined // Not a digit
  562. }
  563. hour = code - 48 // Convert ASCII code to number
  564. } else {
  565. const code1 = date.charCodeAt(commaIndex + 12)
  566. if (code1 < 48 || code1 > 50) {
  567. return undefined // Not a digit between 0 and 2
  568. }
  569. const code2 = date.charCodeAt(commaIndex + 13)
  570. if (code2 < 48 || code2 > 57) {
  571. return undefined // Not a digit
  572. }
  573. if (code1 === 50 && code2 > 51) {
  574. return undefined // Hour cannot be greater than 23
  575. }
  576. hour = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  577. }
  578. let minute = 0
  579. if (date[commaIndex + 15] === '0') {
  580. const code = date.charCodeAt(commaIndex + 16)
  581. if (code < 48 || code > 57) {
  582. return undefined // Not a digit
  583. }
  584. minute = code - 48 // Convert ASCII code to number
  585. } else {
  586. const code1 = date.charCodeAt(commaIndex + 15)
  587. if (code1 < 48 || code1 > 53) {
  588. return undefined // Not a digit between 0 and 5
  589. }
  590. const code2 = date.charCodeAt(commaIndex + 16)
  591. if (code2 < 48 || code2 > 57) {
  592. return undefined // Not a digit
  593. }
  594. minute = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  595. }
  596. let second = 0
  597. if (date[commaIndex + 18] === '0') {
  598. const code = date.charCodeAt(commaIndex + 19)
  599. if (code < 48 || code > 57) {
  600. return undefined // Not a digit
  601. }
  602. second = code - 48 // Convert ASCII code to number
  603. } else {
  604. const code1 = date.charCodeAt(commaIndex + 18)
  605. if (code1 < 48 || code1 > 53) {
  606. return undefined // Not a digit between 0 and 5
  607. }
  608. const code2 = date.charCodeAt(commaIndex + 19)
  609. if (code2 < 48 || code2 > 57) {
  610. return undefined // Not a digit
  611. }
  612. second = (code1 - 48) * 10 + (code2 - 48) // Convert ASCII codes to number
  613. }
  614. const result = new Date(Date.UTC(year, monthIdx, day, hour, minute, second))
  615. return result.getUTCDay() === weekday ? result : undefined
  616. }
  617. module.exports = {
  618. parseHttpDate
  619. }