0fd148730eb248409afe25bb5c9b4f356e62fa2d310607e7055eccadc403665031affca6bbb5208f3f8e78c93efc34634e85ae80d617a5f8004b8f2b71d792 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. import { configFromStringAndFormat } from './from-string-and-format';
  2. import { createUTCDate } from './date-from-array';
  3. import { hooks } from '../utils/hooks';
  4. import { deprecate } from '../utils/deprecate';
  5. import getParsingFlags from './parsing-flags';
  6. import { defaultLocaleMonthsShort } from '../units/month';
  7. import { defaultLocaleWeekdaysShort } from '../units/day-of-week';
  8. // iso 8601 regex
  9. // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00)
  10. var extendedIsoRegex =
  11. /^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
  12. basicIsoRegex =
  13. /^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,
  14. tzRegex = /Z|[+-]\d\d(?::?\d\d)?/,
  15. isoDates = [
  16. ['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],
  17. ['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],
  18. ['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],
  19. ['GGGG-[W]WW', /\d{4}-W\d\d/, false],
  20. ['YYYY-DDD', /\d{4}-\d{3}/],
  21. ['YYYY-MM', /\d{4}-\d\d/, false],
  22. ['YYYYYYMMDD', /[+-]\d{10}/],
  23. ['YYYYMMDD', /\d{8}/],
  24. ['GGGG[W]WWE', /\d{4}W\d{3}/],
  25. ['GGGG[W]WW', /\d{4}W\d{2}/, false],
  26. ['YYYYDDD', /\d{7}/],
  27. ['YYYYMM', /\d{6}/, false],
  28. ['YYYY', /\d{4}/, false],
  29. ],
  30. // iso time formats and regexes
  31. isoTimes = [
  32. ['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],
  33. ['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],
  34. ['HH:mm:ss', /\d\d:\d\d:\d\d/],
  35. ['HH:mm', /\d\d:\d\d/],
  36. ['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],
  37. ['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],
  38. ['HHmmss', /\d\d\d\d\d\d/],
  39. ['HHmm', /\d\d\d\d/],
  40. ['HH', /\d\d/],
  41. ],
  42. aspNetJsonRegex = /^\/?Date\((-?\d+)/i,
  43. // RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.3
  44. rfc2822 =
  45. /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,
  46. obsOffsets = {
  47. UT: 0,
  48. GMT: 0,
  49. EDT: -4 * 60,
  50. EST: -5 * 60,
  51. CDT: -5 * 60,
  52. CST: -6 * 60,
  53. MDT: -6 * 60,
  54. MST: -7 * 60,
  55. PDT: -7 * 60,
  56. PST: -8 * 60,
  57. };
  58. // date from iso format
  59. export function configFromISO(config) {
  60. var i,
  61. l,
  62. string = config._i,
  63. match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),
  64. allowTime,
  65. dateFormat,
  66. timeFormat,
  67. tzFormat,
  68. isoDatesLen = isoDates.length,
  69. isoTimesLen = isoTimes.length;
  70. if (match) {
  71. getParsingFlags(config).iso = true;
  72. for (i = 0, l = isoDatesLen; i < l; i++) {
  73. if (isoDates[i][1].exec(match[1])) {
  74. dateFormat = isoDates[i][0];
  75. allowTime = isoDates[i][2] !== false;
  76. break;
  77. }
  78. }
  79. if (dateFormat == null) {
  80. config._isValid = false;
  81. return;
  82. }
  83. if (match[3]) {
  84. for (i = 0, l = isoTimesLen; i < l; i++) {
  85. if (isoTimes[i][1].exec(match[3])) {
  86. // match[2] should be 'T' or space
  87. timeFormat = (match[2] || ' ') + isoTimes[i][0];
  88. break;
  89. }
  90. }
  91. if (timeFormat == null) {
  92. config._isValid = false;
  93. return;
  94. }
  95. }
  96. if (!allowTime && timeFormat != null) {
  97. config._isValid = false;
  98. return;
  99. }
  100. if (match[4]) {
  101. if (tzRegex.exec(match[4])) {
  102. tzFormat = 'Z';
  103. } else {
  104. config._isValid = false;
  105. return;
  106. }
  107. }
  108. config._f = dateFormat + (timeFormat || '') + (tzFormat || '');
  109. configFromStringAndFormat(config);
  110. } else {
  111. config._isValid = false;
  112. }
  113. }
  114. function extractFromRFC2822Strings(
  115. yearStr,
  116. monthStr,
  117. dayStr,
  118. hourStr,
  119. minuteStr,
  120. secondStr
  121. ) {
  122. var result = [
  123. untruncateYear(yearStr),
  124. defaultLocaleMonthsShort.indexOf(monthStr),
  125. parseInt(dayStr, 10),
  126. parseInt(hourStr, 10),
  127. parseInt(minuteStr, 10),
  128. ];
  129. if (secondStr) {
  130. result.push(parseInt(secondStr, 10));
  131. }
  132. return result;
  133. }
  134. function untruncateYear(yearStr) {
  135. var year = parseInt(yearStr, 10);
  136. if (year <= 49) {
  137. return 2000 + year;
  138. } else if (year <= 999) {
  139. return 1900 + year;
  140. }
  141. return year;
  142. }
  143. function preprocessRFC2822(s) {
  144. // Remove comments and folding whitespace and replace multiple-spaces with a single space
  145. return s
  146. .replace(/\([^()]*\)|[\n\t]/g, ' ')
  147. .replace(/(\s\s+)/g, ' ')
  148. .replace(/^\s\s*/, '')
  149. .replace(/\s\s*$/, '');
  150. }
  151. function checkWeekday(weekdayStr, parsedInput, config) {
  152. if (weekdayStr) {
  153. // TODO: Replace the vanilla JS Date object with an independent day-of-week check.
  154. var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),
  155. weekdayActual = new Date(
  156. parsedInput[0],
  157. parsedInput[1],
  158. parsedInput[2]
  159. ).getDay();
  160. if (weekdayProvided !== weekdayActual) {
  161. getParsingFlags(config).weekdayMismatch = true;
  162. config._isValid = false;
  163. return false;
  164. }
  165. }
  166. return true;
  167. }
  168. function calculateOffset(obsOffset, militaryOffset, numOffset) {
  169. if (obsOffset) {
  170. return obsOffsets[obsOffset];
  171. } else if (militaryOffset) {
  172. // the only allowed military tz is Z
  173. return 0;
  174. } else {
  175. var hm = parseInt(numOffset, 10),
  176. m = hm % 100,
  177. h = (hm - m) / 100;
  178. return h * 60 + m;
  179. }
  180. }
  181. // date and time from ref 2822 format
  182. export function configFromRFC2822(config) {
  183. var match = rfc2822.exec(preprocessRFC2822(config._i)),
  184. parsedArray;
  185. if (match) {
  186. parsedArray = extractFromRFC2822Strings(
  187. match[4],
  188. match[3],
  189. match[2],
  190. match[5],
  191. match[6],
  192. match[7]
  193. );
  194. if (!checkWeekday(match[1], parsedArray, config)) {
  195. return;
  196. }
  197. config._a = parsedArray;
  198. config._tzm = calculateOffset(match[8], match[9], match[10]);
  199. config._d = createUTCDate.apply(null, config._a);
  200. config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);
  201. getParsingFlags(config).rfc2822 = true;
  202. } else {
  203. config._isValid = false;
  204. }
  205. }
  206. // date from 1) ASP.NET, 2) ISO, 3) RFC 2822 formats, or 4) optional fallback if parsing isn't strict
  207. export function configFromString(config) {
  208. var matched = aspNetJsonRegex.exec(config._i);
  209. if (matched !== null) {
  210. config._d = new Date(+matched[1]);
  211. return;
  212. }
  213. configFromISO(config);
  214. if (config._isValid === false) {
  215. delete config._isValid;
  216. } else {
  217. return;
  218. }
  219. configFromRFC2822(config);
  220. if (config._isValid === false) {
  221. delete config._isValid;
  222. } else {
  223. return;
  224. }
  225. if (config._strict) {
  226. config._isValid = false;
  227. } else {
  228. // Final attempt, use Input Fallback
  229. hooks.createFromInputFallback(config);
  230. }
  231. }
  232. hooks.createFromInputFallback = deprecate(
  233. 'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +
  234. 'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +
  235. 'discouraged. Please refer to http://momentjs.com/guides/#/warnings/js-date/ for more info.',
  236. function (config) {
  237. config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
  238. }
  239. );