UNPKG

7.95 kBJavaScriptView Raw
1(function (main) {
2 'use strict';
3
4 /**
5 * Parse or format dates
6 * @class fecha
7 */
8 var fecha = {},
9 token = /d{1,4}|M{1,4}|YY(?:YY)?|S{1,3}|Do|ZZ|([HhMsDm])\1?|[aA]|"[^"]*"|'[^']*'/g,
10 dayNames = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
11 monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
12 amPm = ['am', 'pm'],
13 twoDigits = /\d\d?/, threeDigits = /\d{3}/, fourDigits = /\d{4}/,
14 word = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i,
15 noop = function () {},
16 dayNamesShort, monthNamesShort,
17 parseFlags = {
18 D: [twoDigits, function (d, v) {
19 d.day = v;
20 }],
21 M: [twoDigits, function (d, v) {
22 d.month = v - 1;
23 }],
24 YY: [twoDigits, function (d, v) {
25 var da = new Date(), cent = +('' + da.getFullYear()).substr(0, 2);
26 d.year = '' + (v > 68 ? cent - 1 : cent) + v;
27 }],
28 h: [twoDigits, function (d, v) {
29 d.hour = v;
30 }],
31 m: [twoDigits, function (d, v) {
32 d.minute = v;
33 }],
34 s: [twoDigits, function (d, v) {
35 d.second = v;
36 }],
37 YYYY: [fourDigits, function (d, v) {
38 d.year = v;
39 }],
40 S: [/\d/, function (d, v) {
41 d.millisecond = v * 100;
42 }],
43 SS: [/\d{2}/, function (d, v) {
44 d.millisecond = v * 10;
45 }],
46 SSS: [threeDigits, function (d, v) {
47 d.millisecond = v;
48 }],
49 d: [twoDigits, noop],
50 ddd: [word, noop],
51 MMM: [word, monthUpdate('monthNamesShort')],
52 MMMM: [word, monthUpdate('monthNames')],
53 a: [word, function (d, v) {
54 var val = v.toLowerCase();
55 if (val === amPm[0]) {
56 d.isPm = false;
57 } else if (val === amPm[1]) {
58 d.isPm = true;
59 }
60 }],
61 ZZ: [/[\+\-]\d\d:?\d\d/, function (d, v) {
62 var parts = (v + '').match(/([\+\-]|\d\d)/gi), minutes;
63
64 if (parts) {
65 minutes = +(parts[1] * 60) + parseInt(parts[2], 10);
66 d.timezoneOffset = parts[0] === '+' ? minutes : -minutes;
67 }
68
69 }]
70 };
71 parseFlags.dd = parseFlags.d;
72 parseFlags.dddd = parseFlags.ddd;
73 parseFlags.Do = parseFlags.DD = parseFlags.D;
74 parseFlags.mm = parseFlags.m;
75 parseFlags.hh = parseFlags.H = parseFlags.HH = parseFlags.h;
76 parseFlags.MM = parseFlags.M;
77 parseFlags.ss = parseFlags.s;
78 parseFlags.A = parseFlags.a;
79
80 monthNamesShort = shorten(monthNames, 3);
81 dayNamesShort = shorten(dayNames, 3);
82
83 function monthUpdate(arrName) {
84 return function (d, v) {
85 var index = fecha.i18n[arrName].indexOf(v.charAt(0).toUpperCase() + v.substr(1).toLowerCase());
86 if (~index) {
87 d.month = index;
88 }
89 }
90 }
91
92 function pad(val, len) {
93 val = String(val);
94 len = len || 2;
95 while (val.length < len) {
96 val = '0' + val;
97 }
98 return val;
99 }
100
101 function shorten(arr, sLen) {
102 var newArr = [];
103 for (var i = 0, len = arr.length; i < len; i++) {
104 newArr.push(arr[i].substr(0, sLen));
105 }
106 return newArr;
107 }
108
109 function DoFn(D) {
110 return D + ['th', 'st', 'nd', 'rd'][D % 10 > 3 ? 0 : (D - D % 10 !== 10) * D % 10];
111 }
112
113 fecha.i18n = {
114 dayNamesShort: dayNamesShort,
115 dayNames: dayNames,
116 monthNamesShort: monthNamesShort,
117 monthNames: monthNames,
118 amPm: amPm,
119 DoFn: DoFn
120 };
121
122 // Some common format strings
123 fecha.masks = {
124 'default': 'ddd MMM DD YYYY HH:mm:ss',
125 shortDate: 'M/D/YY',
126 mediumDate: 'MMM D, YYYY',
127 longDate: 'MMMM D, YYYY',
128 fullDate: 'dddd, MMMM D, YYYY',
129 shortTime: 'HH:mm',
130 mediumTime: 'HH:mm:ss',
131 longTime: 'HH:mm:ss.SSS'
132 };
133
134 /***
135 * Format a date
136 * @method format
137 * @param {Date|number} dateObj
138 * @param {string} mask Format of the date, i.e. 'mm-dd-yy' or 'shortDate'
139 */
140 fecha.format = function (dateObj, mask) {
141 if (typeof dateObj === 'number') {
142 dateObj = new Date(dateObj);
143 }
144
145 if (Object.prototype.toString.call(dateObj) !== '[object Date]' || isNaN(dateObj.getTime())) {
146 throw new Error('Invalid Date in fecha.format');
147 }
148
149 mask = fecha.masks[mask] || mask || fecha.masks['default'];
150
151 var D = dateObj.getDate(),
152 d = dateObj.getDay(),
153 M = dateObj.getMonth(),
154 y = dateObj.getFullYear(),
155 H = dateObj.getHours(),
156 m = dateObj.getMinutes(),
157 s = dateObj.getSeconds(),
158 S = dateObj.getMilliseconds(),
159 o = dateObj.getTimezoneOffset(),
160 flags = {
161 D: D,
162 DD: pad(D),
163 Do: fecha.i18n.DoFn(D),
164 d: d,
165 dd: pad(d),
166 ddd: fecha.i18n.dayNamesShort[d],
167 dddd: fecha.i18n.dayNames[d],
168 M: M + 1,
169 MM: pad(M + 1),
170 MMM: fecha.i18n.monthNamesShort[M],
171 MMMM: fecha.i18n.monthNames[M],
172 YY: String(y).slice(2),
173 YYYY: y,
174 h: H % 12 || 12,
175 hh: pad(H % 12 || 12),
176 H: H,
177 HH: pad(H),
178 m: m,
179 mm: pad(m),
180 s: s,
181 ss: pad(s),
182 S: Math.round(S / 100),
183 SS: pad(Math.round(S / 10), 2),
184 SSS: pad(S, 3),
185 a: H < 12 ? fecha.i18n.amPm[0] : fecha.i18n.amPm[1],
186 A: H < 12 ? fecha.i18n.amPm[0].toUpperCase() : fecha.i18n.amPm[1].toUpperCase(),
187 ZZ: (o > 0 ? '-' : '+') + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4)
188 };
189
190 return mask.replace(token, function ($0) {
191 return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);
192 });
193 };
194
195 /**
196 * Parse a date string into an object, changes - into /
197 * @method parse
198 * @param {string} dateStr Date string
199 * @param {string} format Date parse format
200 * @returns {Date|boolean}
201 */
202 fecha.parse = function (dateStr, format) {
203 var isValid, dateInfo, today, date, info, index;
204
205 if (typeof format !== 'string') {
206 throw new Error('Invalid format in fecha.parse');
207 }
208
209 format = fecha.masks[format] || format;
210
211 // Avoid regular expression denial of service, fail early for really long strings
212 // https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS
213 if (dateStr.length > 1000) {
214 return false;
215 }
216
217 isValid = true;
218 dateInfo = {};
219 format.replace(token, function ($0) {
220 if (parseFlags[$0]) {
221 info = parseFlags[$0];
222 index = dateStr.search(info[0]);
223 if (!~index) {
224 isValid = false;
225 } else {
226 dateStr.replace(info[0], function (result) {
227 info[1](dateInfo, result);
228 dateStr = dateStr.substr(index + result.length);
229 return result;
230 });
231 }
232 }
233
234 return parseFlags[$0] ? '' : $0.slice(1, $0.length - 1);
235 });
236
237 if (!isValid) {
238 return false;
239 }
240
241 today = new Date();
242 if (dateInfo.isPm === true && dateInfo.hour != null && +dateInfo.hour !== 12) {
243 dateInfo.hour = +dateInfo.hour + 12;
244 } else if (dateInfo.isPm === false && +dateInfo.hour === 12) {
245 dateInfo.hour = 0;
246 }
247
248 if (dateInfo.timezoneOffset != null) {
249 dateInfo.minute = +(dateInfo.minute || 0) - +dateInfo.timezoneOffset;
250 date = new Date(Date.UTC(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1,
251 dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0));
252 } else {
253 date = new Date(dateInfo.year || today.getFullYear(), dateInfo.month || 0, dateInfo.day || 1,
254 dateInfo.hour || 0, dateInfo.minute || 0, dateInfo.second || 0, dateInfo.millisecond || 0);
255 }
256 return date;
257 };
258
259 /* istanbul ignore next */
260 if (typeof module !== 'undefined' && module.exports) {
261 module.exports = fecha;
262 } else if (typeof define === 'function' && define.amd) {
263 define(function () {
264 return fecha;
265 });
266 } else {
267 main.fecha = fecha;
268 }
269})(this);