fecha.umd.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (factory((global.fecha = {})));
  5. }(this, (function (exports) { 'use strict';
  6. var token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|Z|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g;
  7. var twoDigitsOptional = "\\d\\d?";
  8. var twoDigits = "\\d\\d";
  9. var threeDigits = "\\d{3}";
  10. var fourDigits = "\\d{4}";
  11. var word = "[^\\s]+";
  12. var literal = /\[([^]*?)\]/gm;
  13. function shorten(arr, sLen) {
  14. var newArr = [];
  15. for (var i = 0, len = arr.length; i < len; i++) {
  16. newArr.push(arr[i].substr(0, sLen));
  17. }
  18. return newArr;
  19. }
  20. var monthUpdate = function (arrName) { return function (v, i18n) {
  21. var lowerCaseArr = i18n[arrName].map(function (v) { return v.toLowerCase(); });
  22. var index = lowerCaseArr.indexOf(v.toLowerCase());
  23. if (index > -1) {
  24. return index;
  25. }
  26. return null;
  27. }; };
  28. function assign(origObj) {
  29. var args = [];
  30. for (var _i = 1; _i < arguments.length; _i++) {
  31. args[_i - 1] = arguments[_i];
  32. }
  33. for (var _a = 0, args_1 = args; _a < args_1.length; _a++) {
  34. var obj = args_1[_a];
  35. for (var key in obj) {
  36. // @ts-ignore ex
  37. origObj[key] = obj[key];
  38. }
  39. }
  40. return origObj;
  41. }
  42. var dayNames = [
  43. "Sunday",
  44. "Monday",
  45. "Tuesday",
  46. "Wednesday",
  47. "Thursday",
  48. "Friday",
  49. "Saturday"
  50. ];
  51. var monthNames = [
  52. "January",
  53. "February",
  54. "March",
  55. "April",
  56. "May",
  57. "June",
  58. "July",
  59. "August",
  60. "September",
  61. "October",
  62. "November",
  63. "December"
  64. ];
  65. var monthNamesShort = shorten(monthNames, 3);
  66. var dayNamesShort = shorten(dayNames, 3);
  67. var defaultI18n = {
  68. dayNamesShort: dayNamesShort,
  69. dayNames: dayNames,
  70. monthNamesShort: monthNamesShort,
  71. monthNames: monthNames,
  72. amPm: ["am", "pm"],
  73. DoFn: function (dayOfMonth) {
  74. return (dayOfMonth +
  75. ["th", "st", "nd", "rd"][dayOfMonth % 10 > 3
  76. ? 0
  77. : ((dayOfMonth - (dayOfMonth % 10) !== 10 ? 1 : 0) * dayOfMonth) % 10]);
  78. }
  79. };
  80. var globalI18n = assign({}, defaultI18n);
  81. var setGlobalDateI18n = function (i18n) {
  82. return (globalI18n = assign(globalI18n, i18n));
  83. };
  84. var regexEscape = function (str) {
  85. return str.replace(/[|\\{()[^$+*?.-]/g, "\\$&");
  86. };
  87. var pad = function (val, len) {
  88. if (len === void 0) { len = 2; }
  89. val = String(val);
  90. while (val.length < len) {
  91. val = "0" + val;
  92. }
  93. return val;
  94. };
  95. var formatFlags = {
  96. D: function (dateObj) { return String(dateObj.getDate()); },
  97. DD: function (dateObj) { return pad(dateObj.getDate()); },
  98. Do: function (dateObj, i18n) {
  99. return i18n.DoFn(dateObj.getDate());
  100. },
  101. d: function (dateObj) { return String(dateObj.getDay()); },
  102. dd: function (dateObj) { return pad(dateObj.getDay()); },
  103. ddd: function (dateObj, i18n) {
  104. return i18n.dayNamesShort[dateObj.getDay()];
  105. },
  106. dddd: function (dateObj, i18n) {
  107. return i18n.dayNames[dateObj.getDay()];
  108. },
  109. M: function (dateObj) { return String(dateObj.getMonth() + 1); },
  110. MM: function (dateObj) { return pad(dateObj.getMonth() + 1); },
  111. MMM: function (dateObj, i18n) {
  112. return i18n.monthNamesShort[dateObj.getMonth()];
  113. },
  114. MMMM: function (dateObj, i18n) {
  115. return i18n.monthNames[dateObj.getMonth()];
  116. },
  117. YY: function (dateObj) {
  118. return pad(String(dateObj.getFullYear()), 4).substr(2);
  119. },
  120. YYYY: function (dateObj) { return pad(dateObj.getFullYear(), 4); },
  121. h: function (dateObj) { return String(dateObj.getHours() % 12 || 12); },
  122. hh: function (dateObj) { return pad(dateObj.getHours() % 12 || 12); },
  123. H: function (dateObj) { return String(dateObj.getHours()); },
  124. HH: function (dateObj) { return pad(dateObj.getHours()); },
  125. m: function (dateObj) { return String(dateObj.getMinutes()); },
  126. mm: function (dateObj) { return pad(dateObj.getMinutes()); },
  127. s: function (dateObj) { return String(dateObj.getSeconds()); },
  128. ss: function (dateObj) { return pad(dateObj.getSeconds()); },
  129. S: function (dateObj) {
  130. return String(Math.round(dateObj.getMilliseconds() / 100));
  131. },
  132. SS: function (dateObj) {
  133. return pad(Math.round(dateObj.getMilliseconds() / 10), 2);
  134. },
  135. SSS: function (dateObj) { return pad(dateObj.getMilliseconds(), 3); },
  136. a: function (dateObj, i18n) {
  137. return dateObj.getHours() < 12 ? i18n.amPm[0] : i18n.amPm[1];
  138. },
  139. A: function (dateObj, i18n) {
  140. return dateObj.getHours() < 12
  141. ? i18n.amPm[0].toUpperCase()
  142. : i18n.amPm[1].toUpperCase();
  143. },
  144. ZZ: function (dateObj) {
  145. var offset = dateObj.getTimezoneOffset();
  146. return ((offset > 0 ? "-" : "+") +
  147. pad(Math.floor(Math.abs(offset) / 60) * 100 + (Math.abs(offset) % 60), 4));
  148. },
  149. Z: function (dateObj) {
  150. var offset = dateObj.getTimezoneOffset();
  151. return ((offset > 0 ? "-" : "+") +
  152. pad(Math.floor(Math.abs(offset) / 60), 2) +
  153. ":" +
  154. pad(Math.abs(offset) % 60, 2));
  155. }
  156. };
  157. var monthParse = function (v) { return +v - 1; };
  158. var emptyDigits = [null, twoDigitsOptional];
  159. var emptyWord = [null, word];
  160. var amPm = [
  161. "isPm",
  162. word,
  163. function (v, i18n) {
  164. var val = v.toLowerCase();
  165. if (val === i18n.amPm[0]) {
  166. return 0;
  167. }
  168. else if (val === i18n.amPm[1]) {
  169. return 1;
  170. }
  171. return null;
  172. }
  173. ];
  174. var timezoneOffset = [
  175. "timezoneOffset",
  176. "[^\\s]*?[\\+\\-]\\d\\d:?\\d\\d|[^\\s]*?Z?",
  177. function (v) {
  178. var parts = (v + "").match(/([+-]|\d\d)/gi);
  179. if (parts) {
  180. var minutes = +parts[1] * 60 + parseInt(parts[2], 10);
  181. return parts[0] === "+" ? minutes : -minutes;
  182. }
  183. return 0;
  184. }
  185. ];
  186. var parseFlags = {
  187. D: ["day", twoDigitsOptional],
  188. DD: ["day", twoDigits],
  189. Do: ["day", twoDigitsOptional + word, function (v) { return parseInt(v, 10); }],
  190. M: ["month", twoDigitsOptional, monthParse],
  191. MM: ["month", twoDigits, monthParse],
  192. YY: [
  193. "year",
  194. twoDigits,
  195. function (v) {
  196. var now = new Date();
  197. var cent = +("" + now.getFullYear()).substr(0, 2);
  198. return +("" + (+v > 68 ? cent - 1 : cent) + v);
  199. }
  200. ],
  201. h: ["hour", twoDigitsOptional, undefined, "isPm"],
  202. hh: ["hour", twoDigits, undefined, "isPm"],
  203. H: ["hour", twoDigitsOptional],
  204. HH: ["hour", twoDigits],
  205. m: ["minute", twoDigitsOptional],
  206. mm: ["minute", twoDigits],
  207. s: ["second", twoDigitsOptional],
  208. ss: ["second", twoDigits],
  209. YYYY: ["year", fourDigits],
  210. S: ["millisecond", "\\d", function (v) { return +v * 100; }],
  211. SS: ["millisecond", twoDigits, function (v) { return +v * 10; }],
  212. SSS: ["millisecond", threeDigits],
  213. d: emptyDigits,
  214. dd: emptyDigits,
  215. ddd: emptyWord,
  216. dddd: emptyWord,
  217. MMM: ["month", word, monthUpdate("monthNamesShort")],
  218. MMMM: ["month", word, monthUpdate("monthNames")],
  219. a: amPm,
  220. A: amPm,
  221. ZZ: timezoneOffset,
  222. Z: timezoneOffset
  223. };
  224. // Some common format strings
  225. var globalMasks = {
  226. default: "ddd MMM DD YYYY HH:mm:ss",
  227. shortDate: "M/D/YY",
  228. mediumDate: "MMM D, YYYY",
  229. longDate: "MMMM D, YYYY",
  230. fullDate: "dddd, MMMM D, YYYY",
  231. isoDate: "YYYY-MM-DD",
  232. isoDateTime: "YYYY-MM-DDTHH:mm:ssZ",
  233. shortTime: "HH:mm",
  234. mediumTime: "HH:mm:ss",
  235. longTime: "HH:mm:ss.SSS"
  236. };
  237. var setGlobalDateMasks = function (masks) { return assign(globalMasks, masks); };
  238. /***
  239. * Format a date
  240. * @method format
  241. * @param {Date|number} dateObj
  242. * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate'
  243. * @returns {string} Formatted date string
  244. */
  245. var format = function (dateObj, mask, i18n) {
  246. if (mask === void 0) { mask = globalMasks["default"]; }
  247. if (i18n === void 0) { i18n = {}; }
  248. if (typeof dateObj === "number") {
  249. dateObj = new Date(dateObj);
  250. }
  251. if (Object.prototype.toString.call(dateObj) !== "[object Date]" ||
  252. isNaN(dateObj.getTime())) {
  253. throw new Error("Invalid Date pass to format");
  254. }
  255. mask = globalMasks[mask] || mask;
  256. var literals = [];
  257. // Make literals inactive by replacing them with @@@
  258. mask = mask.replace(literal, function ($0, $1) {
  259. literals.push($1);
  260. return "@@@";
  261. });
  262. var combinedI18nSettings = assign(assign({}, globalI18n), i18n);
  263. // Apply formatting rules
  264. mask = mask.replace(token, function ($0) {
  265. return formatFlags[$0](dateObj, combinedI18nSettings);
  266. });
  267. // Inline literal values back into the formatted value
  268. return mask.replace(/@@@/g, function () { return literals.shift(); });
  269. };
  270. /**
  271. * Parse a date string into a Javascript Date object /
  272. * @method parse
  273. * @param {string} dateStr Date string
  274. * @param {string} format Date parse format
  275. * @param {i18n} I18nSettingsOptional Full or subset of I18N settings
  276. * @returns {Date|null} Returns Date object. Returns null what date string is invalid or doesn't match format
  277. */
  278. function parse(dateStr, format, i18n) {
  279. if (i18n === void 0) { i18n = {}; }
  280. if (typeof format !== "string") {
  281. throw new Error("Invalid format in fecha parse");
  282. }
  283. // Check to see if the format is actually a mask
  284. format = globalMasks[format] || format;
  285. // Avoid regular expression denial of service, fail early for really long strings
  286. // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS
  287. if (dateStr.length > 1000) {
  288. return null;
  289. }
  290. // Default to the beginning of the year.
  291. var today = new Date();
  292. var dateInfo = {
  293. year: today.getFullYear(),
  294. month: 0,
  295. day: 1,
  296. hour: 0,
  297. minute: 0,
  298. second: 0,
  299. millisecond: 0,
  300. isPm: null,
  301. timezoneOffset: null
  302. };
  303. var parseInfo = [];
  304. var literals = [];
  305. // Replace all the literals with @@@. Hopefully a string that won't exist in the format
  306. var newFormat = format.replace(literal, function ($0, $1) {
  307. literals.push(regexEscape($1));
  308. return "@@@";
  309. });
  310. var specifiedFields = {};
  311. var requiredFields = {};
  312. // Change every token that we find into the correct regex
  313. newFormat = regexEscape(newFormat).replace(token, function ($0) {
  314. var info = parseFlags[$0];
  315. var field = info[0], regex = info[1], requiredField = info[3];
  316. // Check if the person has specified the same field twice. This will lead to confusing results.
  317. if (specifiedFields[field]) {
  318. throw new Error("Invalid format. " + field + " specified twice in format");
  319. }
  320. specifiedFields[field] = true;
  321. // Check if there are any required fields. For instance, 12 hour time requires AM/PM specified
  322. if (requiredField) {
  323. requiredFields[requiredField] = true;
  324. }
  325. parseInfo.push(info);
  326. return "(" + regex + ")";
  327. });
  328. // Check all the required fields are present
  329. Object.keys(requiredFields).forEach(function (field) {
  330. if (!specifiedFields[field]) {
  331. throw new Error("Invalid format. " + field + " is required in specified format");
  332. }
  333. });
  334. // Add back all the literals after
  335. newFormat = newFormat.replace(/@@@/g, function () { return literals.shift(); });
  336. // Check if the date string matches the format. If it doesn't return null
  337. var matches = dateStr.match(new RegExp(newFormat, "i"));
  338. if (!matches) {
  339. return null;
  340. }
  341. var combinedI18nSettings = assign(assign({}, globalI18n), i18n);
  342. // For each match, call the parser function for that date part
  343. for (var i = 1; i < matches.length; i++) {
  344. var _a = parseInfo[i - 1], field = _a[0], parser = _a[2];
  345. var value = parser
  346. ? parser(matches[i], combinedI18nSettings)
  347. : +matches[i];
  348. // If the parser can't make sense of the value, return null
  349. if (value == null) {
  350. return null;
  351. }
  352. dateInfo[field] = value;
  353. }
  354. if (dateInfo.isPm === 1 && dateInfo.hour != null && +dateInfo.hour !== 12) {
  355. dateInfo.hour = +dateInfo.hour + 12;
  356. }
  357. else if (dateInfo.isPm === 0 && +dateInfo.hour === 12) {
  358. dateInfo.hour = 0;
  359. }
  360. var dateTZ;
  361. if (dateInfo.timezoneOffset == null) {
  362. dateTZ = new Date(dateInfo.year, dateInfo.month, dateInfo.day, dateInfo.hour, dateInfo.minute, dateInfo.second, dateInfo.millisecond);
  363. var validateFields = [
  364. ["month", "getMonth"],
  365. ["day", "getDate"],
  366. ["hour", "getHours"],
  367. ["minute", "getMinutes"],
  368. ["second", "getSeconds"]
  369. ];
  370. for (var i = 0, len = validateFields.length; i < len; i++) {
  371. // Check to make sure the date field is within the allowed range. Javascript dates allows values
  372. // outside the allowed range. If the values don't match the value was invalid
  373. if (specifiedFields[validateFields[i][0]] &&
  374. dateInfo[validateFields[i][0]] !== dateTZ[validateFields[i][1]]()) {
  375. return null;
  376. }
  377. }
  378. }
  379. else {
  380. dateTZ = new Date(Date.UTC(dateInfo.year, dateInfo.month, dateInfo.day, dateInfo.hour, dateInfo.minute - dateInfo.timezoneOffset, dateInfo.second, dateInfo.millisecond));
  381. // We can't validate dates in another timezone unfortunately. Do a basic check instead
  382. if (dateInfo.month > 11 ||
  383. dateInfo.month < 0 ||
  384. dateInfo.day > 31 ||
  385. dateInfo.day < 1 ||
  386. dateInfo.hour > 23 ||
  387. dateInfo.hour < 0 ||
  388. dateInfo.minute > 59 ||
  389. dateInfo.minute < 0 ||
  390. dateInfo.second > 59 ||
  391. dateInfo.second < 0) {
  392. return null;
  393. }
  394. }
  395. // Don't allow invalid dates
  396. return dateTZ;
  397. }
  398. var fecha = {
  399. format: format,
  400. parse: parse,
  401. defaultI18n: defaultI18n,
  402. setGlobalDateI18n: setGlobalDateI18n,
  403. setGlobalDateMasks: setGlobalDateMasks
  404. };
  405. exports.assign = assign;
  406. exports.default = fecha;
  407. exports.format = format;
  408. exports.parse = parse;
  409. exports.defaultI18n = defaultI18n;
  410. exports.setGlobalDateI18n = setGlobalDateI18n;
  411. exports.setGlobalDateMasks = setGlobalDateMasks;
  412. Object.defineProperty(exports, '__esModule', { value: true });
  413. })));
  414. //# sourceMappingURL=fecha.umd.js.map