UNPKG

55.7 kBJavaScriptView Raw
1window.formatRelative = (() => {
2
3'use strict';
4
5var MILLISECONDS_IN_HOUR = 3600000;
6var MILLISECONDS_IN_MINUTE = 60000;
7var DEFAULT_ADDITIONAL_DIGITS = 2;
8
9var patterns = {
10 dateTimeDelimeter: /[T ]/,
11 plainTime: /:/,
12
13 // year tokens
14 YY: /^(\d{2})$/,
15 YYY: [
16 /^([+-]\d{2})$/, // 0 additional digits
17 /^([+-]\d{3})$/, // 1 additional digit
18 /^([+-]\d{4})$/ // 2 additional digits
19 ],
20 YYYY: /^(\d{4})/,
21 YYYYY: [
22 /^([+-]\d{4})/, // 0 additional digits
23 /^([+-]\d{5})/, // 1 additional digit
24 /^([+-]\d{6})/ // 2 additional digits
25 ],
26
27 // date tokens
28 MM: /^-(\d{2})$/,
29 DDD: /^-?(\d{3})$/,
30 MMDD: /^-?(\d{2})-?(\d{2})$/,
31 Www: /^-?W(\d{2})$/,
32 WwwD: /^-?W(\d{2})-?(\d{1})$/,
33
34 HH: /^(\d{2}([.,]\d*)?)$/,
35 HHMM: /^(\d{2}):?(\d{2}([.,]\d*)?)$/,
36 HHMMSS: /^(\d{2}):?(\d{2}):?(\d{2}([.,]\d*)?)$/,
37
38 // timezone tokens
39 timezone: /([Z+-].*)$/,
40 timezoneZ: /^(Z)$/,
41 timezoneHH: /^([+-])(\d{2})$/,
42 timezoneHHMM: /^([+-])(\d{2}):?(\d{2})$/
43};
44
45/**
46 * @name toDate
47 * @category Common Helpers
48 * @summary Convert the given argument to an instance of Date.
49 *
50 * @description
51 * Convert the given argument to an instance of Date.
52 *
53 * If the argument is an instance of Date, the function returns its clone.
54 *
55 * If the argument is a number, it is treated as a timestamp.
56 *
57 * If an argument is a string, the function tries to parse it.
58 * Function accepts complete ISO 8601 formats as well as partial implementations.
59 * ISO 8601: http://en.wikipedia.org/wiki/ISO_8601
60 *
61 * If the argument is null, it is treated as an invalid date.
62 *
63 * If all above fails, the function passes the given argument to Date constructor.
64 *
65 * **Note**: *all* Date arguments passed to any *date-fns* function is processed by `toDate`.
66 * All *date-fns* functions will throw `RangeError` if `options.additionalDigits` is not 0, 1, 2 or undefined.
67 *
68 * @param {*} argument - the value to convert
69 * @param {Options} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
70 * @param {0|1|2} [options.additionalDigits=2] - the additional number of digits in the extended year format
71 * @returns {Date} the parsed date in the local time zone
72 * @throws {TypeError} 1 argument required
73 * @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
74 *
75 * @example
76 * // Convert string '2014-02-11T11:30:30' to date:
77 * var result = toDate('2014-02-11T11:30:30')
78 * //=> Tue Feb 11 2014 11:30:30
79 *
80 * @example
81 * // Convert string '+02014101' to date,
82 * // if the additional number of digits in the extended year format is 1:
83 * var result = toDate('+02014101', {additionalDigits: 1})
84 * //=> Fri Apr 11 2014 00:00:00
85 */
86function toDate (argument, dirtyOptions) {
87 if (arguments.length < 1) {
88 throw new TypeError('1 argument required, but only ' + arguments.length + ' present')
89 }
90
91 if (argument === null) {
92 return new Date(NaN)
93 }
94
95 var options = dirtyOptions || {};
96
97 var additionalDigits = options.additionalDigits === undefined ? DEFAULT_ADDITIONAL_DIGITS : Number(options.additionalDigits);
98 if (additionalDigits !== 2 && additionalDigits !== 1 && additionalDigits !== 0) {
99 throw new RangeError('additionalDigits must be 0, 1 or 2')
100 }
101
102 // Clone the date
103 if (argument instanceof Date) {
104 // Prevent the date to lose the milliseconds when passed to new Date() in IE10
105 return new Date(argument.getTime())
106 } else if (typeof argument !== 'string') {
107 return new Date(argument)
108 }
109
110 var dateStrings = splitDateString(argument);
111
112 var parseYearResult = parseYear(dateStrings.date, additionalDigits);
113 var year = parseYearResult.year;
114 var restDateString = parseYearResult.restDateString;
115
116 var date = parseDate(restDateString, year);
117
118 if (date) {
119 var timestamp = date.getTime();
120 var time = 0;
121 var offset;
122
123 if (dateStrings.time) {
124 time = parseTime(dateStrings.time);
125 }
126
127 if (dateStrings.timezone) {
128 offset = parseTimezone(dateStrings.timezone);
129 } else {
130 // get offset accurate to hour in timezones that change offset
131 offset = new Date(timestamp + time).getTimezoneOffset();
132 offset = new Date(timestamp + time + offset * MILLISECONDS_IN_MINUTE).getTimezoneOffset();
133 }
134
135 return new Date(timestamp + time + offset * MILLISECONDS_IN_MINUTE)
136 } else {
137 return new Date(argument)
138 }
139}
140
141function splitDateString (dateString) {
142 var dateStrings = {};
143 var array = dateString.split(patterns.dateTimeDelimeter);
144 var timeString;
145
146 if (patterns.plainTime.test(array[0])) {
147 dateStrings.date = null;
148 timeString = array[0];
149 } else {
150 dateStrings.date = array[0];
151 timeString = array[1];
152 }
153
154 if (timeString) {
155 var token = patterns.timezone.exec(timeString);
156 if (token) {
157 dateStrings.time = timeString.replace(token[1], '');
158 dateStrings.timezone = token[1];
159 } else {
160 dateStrings.time = timeString;
161 }
162 }
163
164 return dateStrings
165}
166
167function parseYear (dateString, additionalDigits) {
168 var patternYYY = patterns.YYY[additionalDigits];
169 var patternYYYYY = patterns.YYYYY[additionalDigits];
170
171 var token;
172
173 // YYYY or ±YYYYY
174 token = patterns.YYYY.exec(dateString) || patternYYYYY.exec(dateString);
175 if (token) {
176 var yearString = token[1];
177 return {
178 year: parseInt(yearString, 10),
179 restDateString: dateString.slice(yearString.length)
180 }
181 }
182
183 // YY or ±YYY
184 token = patterns.YY.exec(dateString) || patternYYY.exec(dateString);
185 if (token) {
186 var centuryString = token[1];
187 return {
188 year: parseInt(centuryString, 10) * 100,
189 restDateString: dateString.slice(centuryString.length)
190 }
191 }
192
193 // Invalid ISO-formatted year
194 return {
195 year: null
196 }
197}
198
199function parseDate (dateString, year) {
200 // Invalid ISO-formatted year
201 if (year === null) {
202 return null
203 }
204
205 var token;
206 var date;
207 var month;
208 var week;
209
210 // YYYY
211 if (dateString.length === 0) {
212 date = new Date(0);
213 date.setUTCFullYear(year);
214 return date
215 }
216
217 // YYYY-MM
218 token = patterns.MM.exec(dateString);
219 if (token) {
220 date = new Date(0);
221 month = parseInt(token[1], 10) - 1;
222 date.setUTCFullYear(year, month);
223 return date
224 }
225
226 // YYYY-DDD or YYYYDDD
227 token = patterns.DDD.exec(dateString);
228 if (token) {
229 date = new Date(0);
230 var dayOfYear = parseInt(token[1], 10);
231 date.setUTCFullYear(year, 0, dayOfYear);
232 return date
233 }
234
235 // YYYY-MM-DD or YYYYMMDD
236 token = patterns.MMDD.exec(dateString);
237 if (token) {
238 date = new Date(0);
239 month = parseInt(token[1], 10) - 1;
240 var day = parseInt(token[2], 10);
241 date.setUTCFullYear(year, month, day);
242 return date
243 }
244
245 // YYYY-Www or YYYYWww
246 token = patterns.Www.exec(dateString);
247 if (token) {
248 week = parseInt(token[1], 10) - 1;
249 return dayOfISOYear(year, week)
250 }
251
252 // YYYY-Www-D or YYYYWwwD
253 token = patterns.WwwD.exec(dateString);
254 if (token) {
255 week = parseInt(token[1], 10) - 1;
256 var dayOfWeek = parseInt(token[2], 10) - 1;
257 return dayOfISOYear(year, week, dayOfWeek)
258 }
259
260 // Invalid ISO-formatted date
261 return null
262}
263
264function parseTime (timeString) {
265 var token;
266 var hours;
267 var minutes;
268
269 // hh
270 token = patterns.HH.exec(timeString);
271 if (token) {
272 hours = parseFloat(token[1].replace(',', '.'));
273 return (hours % 24) * MILLISECONDS_IN_HOUR
274 }
275
276 // hh:mm or hhmm
277 token = patterns.HHMM.exec(timeString);
278 if (token) {
279 hours = parseInt(token[1], 10);
280 minutes = parseFloat(token[2].replace(',', '.'));
281 return (hours % 24) * MILLISECONDS_IN_HOUR +
282 minutes * MILLISECONDS_IN_MINUTE
283 }
284
285 // hh:mm:ss or hhmmss
286 token = patterns.HHMMSS.exec(timeString);
287 if (token) {
288 hours = parseInt(token[1], 10);
289 minutes = parseInt(token[2], 10);
290 var seconds = parseFloat(token[3].replace(',', '.'));
291 return (hours % 24) * MILLISECONDS_IN_HOUR +
292 minutes * MILLISECONDS_IN_MINUTE +
293 seconds * 1000
294 }
295
296 // Invalid ISO-formatted time
297 return null
298}
299
300function parseTimezone (timezoneString) {
301 var token;
302 var absoluteOffset;
303
304 // Z
305 token = patterns.timezoneZ.exec(timezoneString);
306 if (token) {
307 return 0
308 }
309
310 // ±hh
311 token = patterns.timezoneHH.exec(timezoneString);
312 if (token) {
313 absoluteOffset = parseInt(token[2], 10) * 60;
314 return (token[1] === '+') ? -absoluteOffset : absoluteOffset
315 }
316
317 // ±hh:mm or ±hhmm
318 token = patterns.timezoneHHMM.exec(timezoneString);
319 if (token) {
320 absoluteOffset = parseInt(token[2], 10) * 60 + parseInt(token[3], 10);
321 return (token[1] === '+') ? -absoluteOffset : absoluteOffset
322 }
323
324 return 0
325}
326
327function dayOfISOYear (isoYear, week, day) {
328 week = week || 0;
329 day = day || 0;
330 var date = new Date(0);
331 date.setUTCFullYear(isoYear, 0, 4);
332 var fourthOfJanuaryDay = date.getUTCDay() || 7;
333 var diff = week * 7 + day + 1 - fourthOfJanuaryDay;
334 date.setUTCDate(date.getUTCDate() + diff);
335 return date
336}
337
338/**
339 * @name isValid
340 * @category Common Helpers
341 * @summary Is the given date valid?
342 *
343 * @description
344 * Returns false if argument is Invalid Date and true otherwise.
345 * Argument is converted to Date using `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate}
346 * Invalid Date is a Date, whose time value is NaN.
347 *
348 * Time value of Date: http://es5.github.io/#x15.9.1.1
349 *
350 * @param {*} date - the date to check
351 * @param {Options} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
352 * @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate}
353 * @returns {Boolean} the date is valid
354 * @throws {TypeError} 1 argument required
355 * @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
356 *
357 * @example
358 * // For the valid date:
359 * var result = isValid(new Date(2014, 1, 31))
360 * //=> true
361 *
362 * @example
363 * // For the value, convertable into a date:
364 * var result = isValid('2014-02-31')
365 * //=> true
366 *
367 * @example
368 * // For the invalid date:
369 * var result = isValid(new Date(''))
370 * //=> false
371 */
372function isValid (dirtyDate, dirtyOptions) {
373 if (arguments.length < 1) {
374 throw new TypeError('1 argument required, but only ' + arguments.length + ' present')
375 }
376
377 var date = toDate(dirtyDate, dirtyOptions);
378 return !isNaN(date)
379}
380
381var formatDistanceLocale = {
382 lessThanXSeconds: {
383 one: 'less than a second',
384 other: 'less than {{count}} seconds'
385 },
386
387 xSeconds: {
388 one: '1 second',
389 other: '{{count}} seconds'
390 },
391
392 halfAMinute: 'half a minute',
393
394 lessThanXMinutes: {
395 one: 'less than a minute',
396 other: 'less than {{count}} minutes'
397 },
398
399 xMinutes: {
400 one: '1 minute',
401 other: '{{count}} minutes'
402 },
403
404 aboutXHours: {
405 one: 'about 1 hour',
406 other: 'about {{count}} hours'
407 },
408
409 xHours: {
410 one: '1 hour',
411 other: '{{count}} hours'
412 },
413
414 xDays: {
415 one: '1 day',
416 other: '{{count}} days'
417 },
418
419 aboutXMonths: {
420 one: 'about 1 month',
421 other: 'about {{count}} months'
422 },
423
424 xMonths: {
425 one: '1 month',
426 other: '{{count}} months'
427 },
428
429 aboutXYears: {
430 one: 'about 1 year',
431 other: 'about {{count}} years'
432 },
433
434 xYears: {
435 one: '1 year',
436 other: '{{count}} years'
437 },
438
439 overXYears: {
440 one: 'over 1 year',
441 other: 'over {{count}} years'
442 },
443
444 almostXYears: {
445 one: 'almost 1 year',
446 other: 'almost {{count}} years'
447 }
448};
449
450function formatDistance (token, count, options) {
451 options = options || {};
452
453 var result;
454 if (typeof formatDistanceLocale[token] === 'string') {
455 result = formatDistanceLocale[token];
456 } else if (count === 1) {
457 result = formatDistanceLocale[token].one;
458 } else {
459 result = formatDistanceLocale[token].other.replace('{{count}}', count);
460 }
461
462 if (options.addSuffix) {
463 if (options.comparison > 0) {
464 return 'in ' + result
465 } else {
466 return result + ' ago'
467 }
468 }
469
470 return result
471}
472
473var tokensToBeShortedPattern = /MMMM|MM|DD|dddd/g;
474
475function buildShortLongFormat (format) {
476 return format.replace(tokensToBeShortedPattern, function (token) {
477 return token.slice(1)
478 })
479}
480
481/**
482 * @name buildFormatLongFn
483 * @category Locale Helpers
484 * @summary Build `formatLong` property for locale used by `format`, `formatRelative` and `parse` functions.
485 *
486 * @description
487 * Build `formatLong` property for locale used by `format`, `formatRelative` and `parse` functions.
488 * Returns a function which takes one of the following tokens as the argument:
489 * `'LTS'`, `'LT'`, `'L'`, `'LL'`, `'LLL'`, `'l'`, `'ll'`, `'lll'`, `'llll'`
490 * and returns a long format string written as `format` token strings.
491 * See [format]{@link https://date-fns.org/docs/format}
492 *
493 * `'l'`, `'ll'`, `'lll'` and `'llll'` formats are built automatically
494 * by shortening some of the tokens from corresponding unshortened formats
495 * (e.g., if `LL` is `'MMMM DD YYYY'` then `ll` will be `MMM D YYYY`)
496 *
497 * @param {Object} obj - the object with long formats written as `format` token strings
498 * @param {String} obj.LT - time format: hours and minutes
499 * @param {String} obj.LTS - time format: hours, minutes and seconds
500 * @param {String} obj.L - short date format: numeric day, month and year
501 * @param {String} [obj.l] - short date format: numeric day, month and year (shortened)
502 * @param {String} obj.LL - long date format: day, month in words, and year
503 * @param {String} [obj.ll] - long date format: day, month in words, and year (shortened)
504 * @param {String} obj.LLL - long date and time format
505 * @param {String} [obj.lll] - long date and time format (shortened)
506 * @param {String} obj.LLLL - long date, time and weekday format
507 * @param {String} [obj.llll] - long date, time and weekday format (shortened)
508 * @returns {Function} `formatLong` property of the locale
509 *
510 * @example
511 * // For `en-US` locale:
512 * locale.formatLong = buildFormatLongFn({
513 * LT: 'h:mm aa',
514 * LTS: 'h:mm:ss aa',
515 * L: 'MM/DD/YYYY',
516 * LL: 'MMMM D YYYY',
517 * LLL: 'MMMM D YYYY h:mm aa',
518 * LLLL: 'dddd, MMMM D YYYY h:mm aa'
519 * })
520 */
521function buildFormatLongFn (obj) {
522 var formatLongLocale = {
523 LTS: obj.LTS,
524 LT: obj.LT,
525 L: obj.L,
526 LL: obj.LL,
527 LLL: obj.LLL,
528 LLLL: obj.LLLL,
529 l: obj.l || buildShortLongFormat(obj.L),
530 ll: obj.ll || buildShortLongFormat(obj.LL),
531 lll: obj.lll || buildShortLongFormat(obj.LLL),
532 llll: obj.llll || buildShortLongFormat(obj.LLLL)
533 };
534
535 return function (token) {
536 return formatLongLocale[token]
537 }
538}
539
540var formatLong = buildFormatLongFn({
541 LT: 'h:mm aa',
542 LTS: 'h:mm:ss aa',
543 L: 'MM/DD/YYYY',
544 LL: 'MMMM D YYYY',
545 LLL: 'MMMM D YYYY h:mm aa',
546 LLLL: 'dddd, MMMM D YYYY h:mm aa'
547});
548
549var formatRelativeLocale = {
550 lastWeek: '[last] dddd [at] LT',
551 yesterday: '[yesterday at] LT',
552 today: '[today at] LT',
553 tomorrow: '[tomorrow at] LT',
554 nextWeek: 'dddd [at] LT',
555 other: 'L'
556};
557
558function formatRelative$1 (token, date, baseDate, options) {
559 return formatRelativeLocale[token]
560}
561
562/**
563 * @name buildLocalizeFn
564 * @category Locale Helpers
565 * @summary Build `localize.weekday`, `localize.month` and `localize.timeOfDay` properties for the locale.
566 *
567 * @description
568 * Build `localize.weekday`, `localize.month` and `localize.timeOfDay` properties for the locale
569 * used by `format` function.
570 * If no `type` is supplied to the options of the resulting function, `defaultType` will be used (see example).
571 *
572 * `localize.weekday` function takes the weekday index as argument (0 - Sunday).
573 * `localize.month` takes the month index (0 - January).
574 * `localize.timeOfDay` takes the hours. Use `indexCallback` to convert them to an array index (see example).
575 *
576 * @param {Object} values - the object with arrays of values
577 * @param {String} defaultType - the default type for the localize function
578 * @param {Function} [indexCallback] - the callback which takes the resulting function argument
579 * and converts it into value array index
580 * @returns {Function} the resulting function
581 *
582 * @example
583 * var timeOfDayValues = {
584 * uppercase: ['AM', 'PM'],
585 * lowercase: ['am', 'pm'],
586 * long: ['a.m.', 'p.m.']
587 * }
588 * locale.localize.timeOfDay = buildLocalizeFn(timeOfDayValues, 'long', function (hours) {
589 * // 0 is a.m. array index, 1 is p.m. array index
590 * return (hours / 12) >= 1 ? 1 : 0
591 * })
592 * locale.localize.timeOfDay(16, {type: 'uppercase'}) //=> 'PM'
593 * locale.localize.timeOfDay(5) //=> 'a.m.'
594 */
595function buildLocalizeFn (values, defaultType, indexCallback) {
596 return function (dirtyIndex, dirtyOptions) {
597 var options = dirtyOptions || {};
598 var type = options.type ? String(options.type) : defaultType;
599 var valuesArray = values[type] || values[defaultType];
600 var index = indexCallback ? indexCallback(Number(dirtyIndex)) : Number(dirtyIndex);
601 return valuesArray[index]
602 }
603}
604
605/**
606 * @name buildLocalizeArrayFn
607 * @category Locale Helpers
608 * @summary Build `localize.weekdays`, `localize.months` and `localize.timesOfDay` properties for the locale.
609 *
610 * @description
611 * Build `localize.weekdays`, `localize.months` and `localize.timesOfDay` properties for the locale.
612 * If no `type` is supplied to the options of the resulting function, `defaultType` will be used (see example).
613 *
614 * @param {Object} values - the object with arrays of values
615 * @param {String} defaultType - the default type for the localize function
616 * @returns {Function} the resulting function
617 *
618 * @example
619 * var weekdayValues = {
620 * narrow: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
621 * short: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
622 * long: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
623 * }
624 * locale.localize.weekdays = buildLocalizeArrayFn(weekdayValues, 'long')
625 * locale.localize.weekdays({type: 'narrow'}) //=> ['Su', 'Mo', ...]
626 * locale.localize.weekdays() //=> ['Sunday', 'Monday', ...]
627 */
628function buildLocalizeArrayFn (values, defaultType) {
629 return function (dirtyOptions) {
630 var options = dirtyOptions || {};
631 var type = options.type ? String(options.type) : defaultType;
632 return values[type] || values[defaultType]
633 }
634}
635
636// Note: in English, the names of days of the week and months are capitalized.
637// If you are making a new locale based on this one, check if the same is true for the language you're working on.
638// Generally, formatted dates should look like they are in the middle of a sentence,
639// e.g. in Spanish language the weekdays and months should be in the lowercase.
640var weekdayValues = {
641 narrow: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
642 short: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
643 long: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
644};
645
646var monthValues = {
647 short: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
648 long: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
649};
650
651// `timeOfDay` is used to designate which part of the day it is, when used with 12-hour clock.
652// Use the system which is used the most commonly in the locale.
653// For example, if the country doesn't use a.m./p.m., you can use `night`/`morning`/`afternoon`/`evening`:
654//
655// var timeOfDayValues = {
656// any: ['in the night', 'in the morning', 'in the afternoon', 'in the evening']
657// }
658//
659// And later:
660//
661// var localize = {
662// // The callback takes the hours as the argument and returns the array index
663// timeOfDay: buildLocalizeFn(timeOfDayValues, 'any', function (hours) {
664// if (hours >= 17) {
665// return 3
666// } else if (hours >= 12) {
667// return 2
668// } else if (hours >= 4) {
669// return 1
670// } else {
671// return 0
672// }
673// }),
674// timesOfDay: buildLocalizeArrayFn(timeOfDayValues, 'any')
675// }
676var timeOfDayValues = {
677 uppercase: ['AM', 'PM'],
678 lowercase: ['am', 'pm'],
679 long: ['a.m.', 'p.m.']
680};
681
682function ordinalNumber (dirtyNumber, dirtyOptions) {
683 var number = Number(dirtyNumber);
684
685 // If ordinal numbers depend on context, for example,
686 // if they are different for different grammatical genders,
687 // use `options.unit`:
688 //
689 // var options = dirtyOptions || {}
690 // var unit = String(options.unit)
691 //
692 // where `unit` can be 'month', 'quarter', 'week', 'isoWeek', 'dayOfYear',
693 // 'dayOfMonth' or 'dayOfWeek'
694
695 var rem100 = number % 100;
696 if (rem100 > 20 || rem100 < 10) {
697 switch (rem100 % 10) {
698 case 1:
699 return number + 'st'
700 case 2:
701 return number + 'nd'
702 case 3:
703 return number + 'rd'
704 }
705 }
706 return number + 'th'
707}
708
709var localize = {
710 ordinalNumber: ordinalNumber,
711 weekday: buildLocalizeFn(weekdayValues, 'long'),
712 weekdays: buildLocalizeArrayFn(weekdayValues, 'long'),
713 month: buildLocalizeFn(monthValues, 'long'),
714 months: buildLocalizeArrayFn(monthValues, 'long'),
715 timeOfDay: buildLocalizeFn(timeOfDayValues, 'long', function (hours) {
716 return (hours / 12) >= 1 ? 1 : 0
717 }),
718 timesOfDay: buildLocalizeArrayFn(timeOfDayValues, 'long')
719};
720
721/**
722 * @name buildMatchFn
723 * @category Locale Helpers
724 * @summary Build `match.weekdays`, `match.months` and `match.timesOfDay` properties for the locale.
725 *
726 * @description
727 * Build `match.weekdays`, `match.months` and `match.timesOfDay` properties for the locale used by `parse` function.
728 * If no `type` is supplied to the options of the resulting function, `defaultType` will be used (see example).
729 * The result of the match function will be passed into corresponding parser function
730 * (`match.weekday`, `match.month` or `match.timeOfDay` respectively. See `buildParseFn`).
731 *
732 * @param {Object} values - the object with RegExps
733 * @param {String} defaultType - the default type for the match function
734 * @returns {Function} the resulting function
735 *
736 * @example
737 * var matchWeekdaysPatterns = {
738 * narrow: /^(su|mo|tu|we|th|fr|sa)/i,
739 * short: /^(sun|mon|tue|wed|thu|fri|sat)/i,
740 * long: /^(sunday|monday|tuesday|wednesday|thursday|friday|saturday)/i
741 * }
742 * locale.match.weekdays = buildMatchFn(matchWeekdaysPatterns, 'long')
743 * locale.match.weekdays('Sunday', {type: 'narrow'}) //=> ['Su', 'Su', ...]
744 * locale.match.weekdays('Sunday') //=> ['Sunday', 'Sunday', ...]
745 */
746function buildMatchFn (patterns, defaultType) {
747 return function (dirtyString, dirtyOptions) {
748 var options = dirtyOptions || {};
749 var type = options.type ? String(options.type) : defaultType;
750 var pattern = patterns[type] || patterns[defaultType];
751 var string = String(dirtyString);
752 return string.match(pattern)
753 }
754}
755
756/**
757 * @name buildParseFn
758 * @category Locale Helpers
759 * @summary Build `match.weekday`, `match.month` and `match.timeOfDay` properties for the locale.
760 *
761 * @description
762 * Build `match.weekday`, `match.month` and `match.timeOfDay` properties for the locale used by `parse` function.
763 * The argument of the resulting function is the result of the corresponding match function
764 * (`match.weekdays`, `match.months` or `match.timesOfDay` respectively. See `buildMatchFn`).
765 *
766 * @param {Object} values - the object with arrays of RegExps
767 * @param {String} defaultType - the default type for the parser function
768 * @returns {Function} the resulting function
769 *
770 * @example
771 * var parseWeekdayPatterns = {
772 * any: [/^su/i, /^m/i, /^tu/i, /^w/i, /^th/i, /^f/i, /^sa/i]
773 * }
774 * locale.match.weekday = buildParseFn(matchWeekdaysPatterns, 'long')
775 * var matchResult = locale.match.weekdays('Friday')
776 * locale.match.weekday(matchResult) //=> 5
777 */
778function buildParseFn (patterns, defaultType) {
779 return function (matchResult, dirtyOptions) {
780 var options = dirtyOptions || {};
781 var type = options.type ? String(options.type) : defaultType;
782 var patternsArray = patterns[type] || patterns[defaultType];
783 var string = matchResult[1];
784
785 return patternsArray.findIndex(function (pattern) {
786 return pattern.test(string)
787 })
788 }
789}
790
791/**
792 * @name buildMatchPatternFn
793 * @category Locale Helpers
794 * @summary Build match function from a single RegExp.
795 *
796 * @description
797 * Build match function from a single RegExp.
798 * Usually used for building `match.ordinalNumbers` property of the locale.
799 *
800 * @param {Object} pattern - the RegExp
801 * @returns {Function} the resulting function
802 *
803 * @example
804 * locale.match.ordinalNumbers = buildMatchPatternFn(/^(\d+)(th|st|nd|rd)?/i)
805 * locale.match.ordinalNumbers('3rd') //=> ['3rd', '3', 'rd', ...]
806 */
807function buildMatchPatternFn (pattern) {
808 return function (dirtyString) {
809 var string = String(dirtyString);
810 return string.match(pattern)
811 }
812}
813
814/**
815 * @name parseDecimal
816 * @category Locale Helpers
817 * @summary Parses the match result into decimal number.
818 *
819 * @description
820 * Parses the match result into decimal number.
821 * Uses the string matched with the first set of parentheses of match RegExp.
822 *
823 * @param {Array} matchResult - the object returned by matching function
824 * @returns {Number} the parsed value
825 *
826 * @example
827 * locale.match = {
828 * ordinalNumbers: (dirtyString) {
829 * return String(dirtyString).match(/^(\d+)(th|st|nd|rd)?/i)
830 * },
831 * ordinalNumber: parseDecimal
832 * }
833 */
834function parseDecimal (matchResult) {
835 return parseInt(matchResult[1], 10)
836}
837
838var matchOrdinalNumbersPattern = /^(\d+)(th|st|nd|rd)?/i;
839
840var matchWeekdaysPatterns = {
841 narrow: /^(su|mo|tu|we|th|fr|sa)/i,
842 short: /^(sun|mon|tue|wed|thu|fri|sat)/i,
843 long: /^(sunday|monday|tuesday|wednesday|thursday|friday|saturday)/i
844};
845
846var parseWeekdayPatterns = {
847 any: [/^su/i, /^m/i, /^tu/i, /^w/i, /^th/i, /^f/i, /^sa/i]
848};
849
850var matchMonthsPatterns = {
851 short: /^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i,
852 long: /^(january|february|march|april|may|june|july|august|september|october|november|december)/i
853};
854
855var parseMonthPatterns = {
856 any: [/^ja/i, /^f/i, /^mar/i, /^ap/i, /^may/i, /^jun/i, /^jul/i, /^au/i, /^s/i, /^o/i, /^n/i, /^d/i]
857};
858
859// `timeOfDay` is used to designate which part of the day it is, when used with 12-hour clock.
860// Use the system which is used the most commonly in the locale.
861// For example, if the country doesn't use a.m./p.m., you can use `night`/`morning`/`afternoon`/`evening`:
862//
863// var matchTimesOfDayPatterns = {
864// long: /^((in the)? (night|morning|afternoon|evening?))/i
865// }
866//
867// var parseTimeOfDayPatterns = {
868// any: [/(night|morning)/i, /(afternoon|evening)/i]
869// }
870var matchTimesOfDayPatterns = {
871 short: /^(am|pm)/i,
872 long: /^([ap]\.?\s?m\.?)/i
873};
874
875var parseTimeOfDayPatterns = {
876 any: [/^a/i, /^p/i]
877};
878
879var match = {
880 ordinalNumbers: buildMatchPatternFn(matchOrdinalNumbersPattern),
881 ordinalNumber: parseDecimal,
882 weekdays: buildMatchFn(matchWeekdaysPatterns, 'long'),
883 weekday: buildParseFn(parseWeekdayPatterns, 'any'),
884 months: buildMatchFn(matchMonthsPatterns, 'long'),
885 month: buildParseFn(parseMonthPatterns, 'any'),
886 timesOfDay: buildMatchFn(matchTimesOfDayPatterns, 'long'),
887 timeOfDay: buildParseFn(parseTimeOfDayPatterns, 'any')
888};
889
890/**
891 * @type {Locale}
892 * @category Locales
893 * @summary English locale (United States).
894 * @language English
895 * @iso-639-2 eng
896 */
897var locale = {
898 formatDistance: formatDistance,
899 formatLong: formatLong,
900 formatRelative: formatRelative$1,
901 localize: localize,
902 match: match,
903 options: {
904 weekStartsOn: 0 /* Sunday */,
905 firstWeekContainsDate: 1
906 }
907};
908
909var MILLISECONDS_IN_DAY = 86400000;
910
911// This function will be a part of public API when UTC function will be implemented.
912// See issue: https://github.com/date-fns/date-fns/issues/376
913function getUTCDayOfYear (dirtyDate, dirtyOptions) {
914 var date = toDate(dirtyDate, dirtyOptions);
915 var timestamp = date.getTime();
916 date.setUTCMonth(0, 1);
917 date.setUTCHours(0, 0, 0, 0);
918 var startOfYearTimestamp = date.getTime();
919 var difference = timestamp - startOfYearTimestamp;
920 return Math.floor(difference / MILLISECONDS_IN_DAY) + 1
921}
922
923// This function will be a part of public API when UTC function will be implemented.
924// See issue: https://github.com/date-fns/date-fns/issues/376
925function startOfUTCISOWeek (dirtyDate, dirtyOptions) {
926 var weekStartsOn = 1;
927
928 var date = toDate(dirtyDate, dirtyOptions);
929 var day = date.getUTCDay();
930 var diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
931
932 date.setUTCDate(date.getUTCDate() - diff);
933 date.setUTCHours(0, 0, 0, 0);
934 return date
935}
936
937// This function will be a part of public API when UTC function will be implemented.
938// See issue: https://github.com/date-fns/date-fns/issues/376
939function getUTCISOWeekYear (dirtyDate, dirtyOptions) {
940 var date = toDate(dirtyDate, dirtyOptions);
941 var year = date.getUTCFullYear();
942
943 var fourthOfJanuaryOfNextYear = new Date(0);
944 fourthOfJanuaryOfNextYear.setUTCFullYear(year + 1, 0, 4);
945 fourthOfJanuaryOfNextYear.setUTCHours(0, 0, 0, 0);
946 var startOfNextYear = startOfUTCISOWeek(fourthOfJanuaryOfNextYear, dirtyOptions);
947
948 var fourthOfJanuaryOfThisYear = new Date(0);
949 fourthOfJanuaryOfThisYear.setUTCFullYear(year, 0, 4);
950 fourthOfJanuaryOfThisYear.setUTCHours(0, 0, 0, 0);
951 var startOfThisYear = startOfUTCISOWeek(fourthOfJanuaryOfThisYear, dirtyOptions);
952
953 if (date.getTime() >= startOfNextYear.getTime()) {
954 return year + 1
955 } else if (date.getTime() >= startOfThisYear.getTime()) {
956 return year
957 } else {
958 return year - 1
959 }
960}
961
962// This function will be a part of public API when UTC function will be implemented.
963// See issue: https://github.com/date-fns/date-fns/issues/376
964function startOfUTCISOWeekYear (dirtyDate, dirtyOptions) {
965 var year = getUTCISOWeekYear(dirtyDate, dirtyOptions);
966 var fourthOfJanuary = new Date(0);
967 fourthOfJanuary.setUTCFullYear(year, 0, 4);
968 fourthOfJanuary.setUTCHours(0, 0, 0, 0);
969 var date = startOfUTCISOWeek(fourthOfJanuary, dirtyOptions);
970 return date
971}
972
973var MILLISECONDS_IN_WEEK = 604800000;
974
975// This function will be a part of public API when UTC function will be implemented.
976// See issue: https://github.com/date-fns/date-fns/issues/376
977function getUTCISOWeek (dirtyDate, dirtyOptions) {
978 var date = toDate(dirtyDate, dirtyOptions);
979 var diff = startOfUTCISOWeek(date, dirtyOptions).getTime() - startOfUTCISOWeekYear(date, dirtyOptions).getTime();
980
981 // Round the number of days to the nearest integer
982 // because the number of milliseconds in a week is not constant
983 // (e.g. it's different in the week of the daylight saving time clock shift)
984 return Math.round(diff / MILLISECONDS_IN_WEEK) + 1
985}
986
987var formatters = {
988 // Month: 1, 2, ..., 12
989 'M': function (date) {
990 return date.getUTCMonth() + 1
991 },
992
993 // Month: 1st, 2nd, ..., 12th
994 'Mo': function (date, options) {
995 var month = date.getUTCMonth() + 1;
996 return options.locale.localize.ordinalNumber(month, {unit: 'month'})
997 },
998
999 // Month: 01, 02, ..., 12
1000 'MM': function (date) {
1001 return addLeadingZeros(date.getUTCMonth() + 1, 2)
1002 },
1003
1004 // Month: Jan, Feb, ..., Dec
1005 'MMM': function (date, options) {
1006 return options.locale.localize.month(date.getUTCMonth(), {type: 'short'})
1007 },
1008
1009 // Month: January, February, ..., December
1010 'MMMM': function (date, options) {
1011 return options.locale.localize.month(date.getUTCMonth(), {type: 'long'})
1012 },
1013
1014 // Quarter: 1, 2, 3, 4
1015 'Q': function (date) {
1016 return Math.ceil((date.getUTCMonth() + 1) / 3)
1017 },
1018
1019 // Quarter: 1st, 2nd, 3rd, 4th
1020 'Qo': function (date, options) {
1021 var quarter = Math.ceil((date.getUTCMonth() + 1) / 3);
1022 return options.locale.localize.ordinalNumber(quarter, {unit: 'quarter'})
1023 },
1024
1025 // Day of month: 1, 2, ..., 31
1026 'D': function (date) {
1027 return date.getUTCDate()
1028 },
1029
1030 // Day of month: 1st, 2nd, ..., 31st
1031 'Do': function (date, options) {
1032 return options.locale.localize.ordinalNumber(date.getUTCDate(), {unit: 'dayOfMonth'})
1033 },
1034
1035 // Day of month: 01, 02, ..., 31
1036 'DD': function (date) {
1037 return addLeadingZeros(date.getUTCDate(), 2)
1038 },
1039
1040 // Day of year: 1, 2, ..., 366
1041 'DDD': function (date) {
1042 return getUTCDayOfYear(date)
1043 },
1044
1045 // Day of year: 1st, 2nd, ..., 366th
1046 'DDDo': function (date, options) {
1047 return options.locale.localize.ordinalNumber(getUTCDayOfYear(date), {unit: 'dayOfYear'})
1048 },
1049
1050 // Day of year: 001, 002, ..., 366
1051 'DDDD': function (date) {
1052 return addLeadingZeros(getUTCDayOfYear(date), 3)
1053 },
1054
1055 // Day of week: Su, Mo, ..., Sa
1056 'dd': function (date, options) {
1057 return options.locale.localize.weekday(date.getUTCDay(), {type: 'narrow'})
1058 },
1059
1060 // Day of week: Sun, Mon, ..., Sat
1061 'ddd': function (date, options) {
1062 return options.locale.localize.weekday(date.getUTCDay(), {type: 'short'})
1063 },
1064
1065 // Day of week: Sunday, Monday, ..., Saturday
1066 'dddd': function (date, options) {
1067 return options.locale.localize.weekday(date.getUTCDay(), {type: 'long'})
1068 },
1069
1070 // Day of week: 0, 1, ..., 6
1071 'd': function (date) {
1072 return date.getUTCDay()
1073 },
1074
1075 // Day of week: 0th, 1st, 2nd, ..., 6th
1076 'do': function (date, options) {
1077 return options.locale.localize.ordinalNumber(date.getUTCDay(), {unit: 'dayOfWeek'})
1078 },
1079
1080 // Day of ISO week: 1, 2, ..., 7
1081 'E': function (date) {
1082 return date.getUTCDay() || 7
1083 },
1084
1085 // ISO week: 1, 2, ..., 53
1086 'W': function (date) {
1087 return getUTCISOWeek(date)
1088 },
1089
1090 // ISO week: 1st, 2nd, ..., 53th
1091 'Wo': function (date, options) {
1092 return options.locale.localize.ordinalNumber(getUTCISOWeek(date), {unit: 'isoWeek'})
1093 },
1094
1095 // ISO week: 01, 02, ..., 53
1096 'WW': function (date) {
1097 return addLeadingZeros(getUTCISOWeek(date), 2)
1098 },
1099
1100 // Year: 00, 01, ..., 99
1101 'YY': function (date) {
1102 return addLeadingZeros(date.getUTCFullYear(), 4).substr(2)
1103 },
1104
1105 // Year: 1900, 1901, ..., 2099
1106 'YYYY': function (date) {
1107 return addLeadingZeros(date.getUTCFullYear(), 4)
1108 },
1109
1110 // ISO week-numbering year: 00, 01, ..., 99
1111 'GG': function (date) {
1112 return String(getUTCISOWeekYear(date)).substr(2)
1113 },
1114
1115 // ISO week-numbering year: 1900, 1901, ..., 2099
1116 'GGGG': function (date) {
1117 return getUTCISOWeekYear(date)
1118 },
1119
1120 // Hour: 0, 1, ... 23
1121 'H': function (date) {
1122 return date.getUTCHours()
1123 },
1124
1125 // Hour: 00, 01, ..., 23
1126 'HH': function (date) {
1127 return addLeadingZeros(date.getUTCHours(), 2)
1128 },
1129
1130 // Hour: 1, 2, ..., 12
1131 'h': function (date) {
1132 var hours = date.getUTCHours();
1133 if (hours === 0) {
1134 return 12
1135 } else if (hours > 12) {
1136 return hours % 12
1137 } else {
1138 return hours
1139 }
1140 },
1141
1142 // Hour: 01, 02, ..., 12
1143 'hh': function (date) {
1144 return addLeadingZeros(formatters['h'](date), 2)
1145 },
1146
1147 // Minute: 0, 1, ..., 59
1148 'm': function (date) {
1149 return date.getUTCMinutes()
1150 },
1151
1152 // Minute: 00, 01, ..., 59
1153 'mm': function (date) {
1154 return addLeadingZeros(date.getUTCMinutes(), 2)
1155 },
1156
1157 // Second: 0, 1, ..., 59
1158 's': function (date) {
1159 return date.getUTCSeconds()
1160 },
1161
1162 // Second: 00, 01, ..., 59
1163 'ss': function (date) {
1164 return addLeadingZeros(date.getUTCSeconds(), 2)
1165 },
1166
1167 // 1/10 of second: 0, 1, ..., 9
1168 'S': function (date) {
1169 return Math.floor(date.getUTCMilliseconds() / 100)
1170 },
1171
1172 // 1/100 of second: 00, 01, ..., 99
1173 'SS': function (date) {
1174 return addLeadingZeros(Math.floor(date.getUTCMilliseconds() / 10), 2)
1175 },
1176
1177 // Millisecond: 000, 001, ..., 999
1178 'SSS': function (date) {
1179 return addLeadingZeros(date.getUTCMilliseconds(), 3)
1180 },
1181
1182 // Timezone: -01:00, +00:00, ... +12:00
1183 'Z': function (date, options) {
1184 var originalDate = options._originalDate || date;
1185 return formatTimezone(originalDate.getTimezoneOffset(), ':')
1186 },
1187
1188 // Timezone: -0100, +0000, ... +1200
1189 'ZZ': function (date, options) {
1190 var originalDate = options._originalDate || date;
1191 return formatTimezone(originalDate.getTimezoneOffset())
1192 },
1193
1194 // Seconds timestamp: 512969520
1195 'X': function (date, options) {
1196 var originalDate = options._originalDate || date;
1197 return Math.floor(originalDate.getTime() / 1000)
1198 },
1199
1200 // Milliseconds timestamp: 512969520900
1201 'x': function (date, options) {
1202 var originalDate = options._originalDate || date;
1203 return originalDate.getTime()
1204 },
1205
1206 // AM, PM
1207 'A': function (date, options) {
1208 return options.locale.localize.timeOfDay(date.getUTCHours(), {type: 'uppercase'})
1209 },
1210
1211 // am, pm
1212 'a': function (date, options) {
1213 return options.locale.localize.timeOfDay(date.getUTCHours(), {type: 'lowercase'})
1214 },
1215
1216 // a.m., p.m.
1217 'aa': function (date, options) {
1218 return options.locale.localize.timeOfDay(date.getUTCHours(), {type: 'long'})
1219 }
1220};
1221
1222function formatTimezone (offset, delimeter) {
1223 delimeter = delimeter || '';
1224 var sign = offset > 0 ? '-' : '+';
1225 var absOffset = Math.abs(offset);
1226 var hours = Math.floor(absOffset / 60);
1227 var minutes = absOffset % 60;
1228 return sign + addLeadingZeros(hours, 2) + delimeter + addLeadingZeros(minutes, 2)
1229}
1230
1231function addLeadingZeros (number, targetLength) {
1232 var output = Math.abs(number).toString();
1233 while (output.length < targetLength) {
1234 output = '0' + output;
1235 }
1236 return output
1237}
1238
1239function cloneObject (dirtyObject) {
1240 dirtyObject = dirtyObject || {};
1241 var object = {};
1242
1243 for (var property in dirtyObject) {
1244 if (dirtyObject.hasOwnProperty(property)) {
1245 object[property] = dirtyObject[property];
1246 }
1247 }
1248
1249 return object
1250}
1251
1252// This function will be a part of public API when UTC function will be implemented.
1253// See issue: https://github.com/date-fns/date-fns/issues/376
1254function addUTCMinutes (dirtyDate, dirtyAmount, dirtyOptions) {
1255 var date = toDate(dirtyDate, dirtyOptions);
1256 var amount = Number(dirtyAmount);
1257 date.setUTCMinutes(date.getUTCMinutes() + amount);
1258 return date
1259}
1260
1261var longFormattingTokensRegExp = /(\[[^[]*])|(\\)?(LTS|LT|LLLL|LLL|LL|L|llll|lll|ll|l)/g;
1262var defaultFormattingTokensRegExp = /(\[[^[]*])|(\\)?(x|ss|s|mm|m|hh|h|do|dddd|ddd|dd|d|aa|a|ZZ|Z|YYYY|YY|X|Wo|WW|W|SSS|SS|S|Qo|Q|Mo|MMMM|MMM|MM|M|HH|H|GGGG|GG|E|Do|DDDo|DDDD|DDD|DD|D|A|.)/g;
1263
1264/**
1265 * @name format
1266 * @category Common Helpers
1267 * @summary Format the date.
1268 *
1269 * @description
1270 * Return the formatted date string in the given format.
1271 *
1272 * Accepted tokens:
1273 * | Unit | Token | Result examples |
1274 * |-------------------------|-------|----------------------------------|
1275 * | Month | M | 1, 2, ..., 12 |
1276 * | | Mo | 1st, 2nd, ..., 12th |
1277 * | | MM | 01, 02, ..., 12 |
1278 * | | MMM | Jan, Feb, ..., Dec |
1279 * | | MMMM | January, February, ..., December |
1280 * | Quarter | Q | 1, 2, 3, 4 |
1281 * | | Qo | 1st, 2nd, 3rd, 4th |
1282 * | Day of month | D | 1, 2, ..., 31 |
1283 * | | Do | 1st, 2nd, ..., 31st |
1284 * | | DD | 01, 02, ..., 31 |
1285 * | Day of year | DDD | 1, 2, ..., 366 |
1286 * | | DDDo | 1st, 2nd, ..., 366th |
1287 * | | DDDD | 001, 002, ..., 366 |
1288 * | Day of week | d | 0, 1, ..., 6 |
1289 * | | do | 0th, 1st, ..., 6th |
1290 * | | dd | Su, Mo, ..., Sa |
1291 * | | ddd | Sun, Mon, ..., Sat |
1292 * | | dddd | Sunday, Monday, ..., Saturday |
1293 * | Day of ISO week | E | 1, 2, ..., 7 |
1294 * | ISO week | W | 1, 2, ..., 53 |
1295 * | | Wo | 1st, 2nd, ..., 53rd |
1296 * | | WW | 01, 02, ..., 53 |
1297 * | Year | YY | 00, 01, ..., 99 |
1298 * | | YYYY | 1900, 1901, ..., 2099 |
1299 * | ISO week-numbering year | GG | 00, 01, ..., 99 |
1300 * | | GGGG | 1900, 1901, ..., 2099 |
1301 * | AM/PM | A | AM, PM |
1302 * | | a | am, pm |
1303 * | | aa | a.m., p.m. |
1304 * | Hour | H | 0, 1, ... 23 |
1305 * | | HH | 00, 01, ... 23 |
1306 * | | h | 1, 2, ..., 12 |
1307 * | | hh | 01, 02, ..., 12 |
1308 * | Minute | m | 0, 1, ..., 59 |
1309 * | | mm | 00, 01, ..., 59 |
1310 * | Second | s | 0, 1, ..., 59 |
1311 * | | ss | 00, 01, ..., 59 |
1312 * | 1/10 of second | S | 0, 1, ..., 9 |
1313 * | 1/100 of second | SS | 00, 01, ..., 99 |
1314 * | Millisecond | SSS | 000, 001, ..., 999 |
1315 * | Timezone | Z | -01:00, +00:00, ... +12:00 |
1316 * | | ZZ | -0100, +0000, ..., +1200 |
1317 * | Seconds timestamp | X | 512969520 |
1318 * | Milliseconds timestamp | x | 512969520900 |
1319 * | Long format | LT | 05:30 a.m. |
1320 * | | LTS | 05:30:15 a.m. |
1321 * | | L | 07/02/1995 |
1322 * | | l | 7/2/1995 |
1323 * | | LL | July 2 1995 |
1324 * | | ll | Jul 2 1995 |
1325 * | | LLL | July 2 1995 05:30 a.m. |
1326 * | | lll | Jul 2 1995 05:30 a.m. |
1327 * | | LLLL | Sunday, July 2 1995 05:30 a.m. |
1328 * | | llll | Sun, Jul 2 1995 05:30 a.m. |
1329 *
1330 * The characters wrapped in square brackets are escaped.
1331 *
1332 * The result may vary by locale.
1333 *
1334 * @param {Date|String|Number} date - the original date
1335 * @param {String} format - the string of tokens
1336 * @param {Options} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
1337 * @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate}
1338 * @param {Locale} [options.locale=defaultLocale] - the locale object. See [Locale]{@link https://date-fns.org/docs/Locale}
1339 * @returns {String} the formatted date string
1340 * @throws {TypeError} 2 arguments required
1341 * @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
1342 * @throws {RangeError} `options.locale` must contain `localize` property
1343 * @throws {RangeError} `options.locale` must contain `formatLong` property
1344 *
1345 * @example
1346 * // Represent 11 February 2014 in middle-endian format:
1347 * var result = format(
1348 * new Date(2014, 1, 11),
1349 * 'MM/DD/YYYY'
1350 * )
1351 * //=> '02/11/2014'
1352 *
1353 * @example
1354 * // Represent 2 July 2014 in Esperanto:
1355 * import { eoLocale } from 'date-fns/locale/eo'
1356 * var result = format(
1357 * new Date(2014, 6, 2),
1358 * 'Do [de] MMMM YYYY',
1359 * {locale: eoLocale}
1360 * )
1361 * //=> '2-a de julio 2014'
1362 */
1363function format (dirtyDate, dirtyFormatStr, dirtyOptions) {
1364 if (arguments.length < 2) {
1365 throw new TypeError('2 arguments required, but only ' + arguments.length + ' present')
1366 }
1367
1368 var formatStr = String(dirtyFormatStr);
1369 var options = dirtyOptions || {};
1370
1371 var locale$$1 = options.locale || locale;
1372
1373 if (!locale$$1.localize) {
1374 throw new RangeError('locale must contain localize property')
1375 }
1376
1377 if (!locale$$1.formatLong) {
1378 throw new RangeError('locale must contain formatLong property')
1379 }
1380
1381 var localeFormatters = locale$$1.formatters || {};
1382 var formattingTokensRegExp = locale$$1.formattingTokensRegExp || defaultFormattingTokensRegExp;
1383 var formatLong = locale$$1.formatLong;
1384
1385 var originalDate = toDate(dirtyDate, options);
1386
1387 if (!isValid(originalDate, options)) {
1388 return 'Invalid Date'
1389 }
1390
1391 // Convert the date in system timezone to the same date in UTC+00:00 timezone.
1392 // This ensures that when UTC functions will be implemented, locales will be compatible with them.
1393 // See an issue about UTC functions: https://github.com/date-fns/date-fns/issues/376
1394 var timezoneOffset = originalDate.getTimezoneOffset();
1395 var utcDate = addUTCMinutes(originalDate, -timezoneOffset, options);
1396
1397 var formatterOptions = cloneObject(options);
1398 formatterOptions.locale = locale$$1;
1399 formatterOptions.formatters = formatters;
1400
1401 // When UTC functions will be implemented, options._originalDate will likely be a part of public API.
1402 // Right now, please don't use it in locales. If you have to use an original date,
1403 // please restore it from `date`, adding a timezone offset to it.
1404 formatterOptions._originalDate = originalDate;
1405
1406 var result = formatStr
1407 .replace(longFormattingTokensRegExp, function (substring) {
1408 if (substring[0] === '[') {
1409 return substring
1410 }
1411
1412 if (substring[0] === '\\') {
1413 return cleanEscapedString(substring)
1414 }
1415
1416 return formatLong(substring)
1417 })
1418 .replace(formattingTokensRegExp, function (substring) {
1419 var formatter = localeFormatters[substring] || formatters[substring];
1420
1421 if (formatter) {
1422 return formatter(utcDate, formatterOptions)
1423 } else {
1424 return cleanEscapedString(substring)
1425 }
1426 });
1427
1428 return result
1429}
1430
1431function cleanEscapedString (input) {
1432 if (input.match(/\[[\s\S]/)) {
1433 return input.replace(/^\[|]$/g, '')
1434 }
1435 return input.replace(/\\/g, '')
1436}
1437
1438/**
1439 * @name startOfDay
1440 * @category Day Helpers
1441 * @summary Return the start of a day for the given date.
1442 *
1443 * @description
1444 * Return the start of a day for the given date.
1445 * The result will be in the local timezone.
1446 *
1447 * @param {Date|String|Number} date - the original date
1448 * @param {Options} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
1449 * @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate}
1450 * @returns {Date} the start of a day
1451 * @throws {TypeError} 1 argument required
1452 * @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
1453 *
1454 * @example
1455 * // The start of a day for 2 September 2014 11:55:00:
1456 * var result = startOfDay(new Date(2014, 8, 2, 11, 55, 0))
1457 * //=> Tue Sep 02 2014 00:00:00
1458 */
1459function startOfDay (dirtyDate, dirtyOptions) {
1460 if (arguments.length < 1) {
1461 throw new TypeError('1 argument required, but only ' + arguments.length + ' present')
1462 }
1463
1464 var date = toDate(dirtyDate, dirtyOptions);
1465 date.setHours(0, 0, 0, 0);
1466 return date
1467}
1468
1469var MILLISECONDS_IN_MINUTE$1 = 60000;
1470var MILLISECONDS_IN_DAY$1 = 86400000;
1471
1472/**
1473 * @name differenceInCalendarDays
1474 * @category Day Helpers
1475 * @summary Get the number of calendar days between the given dates.
1476 *
1477 * @description
1478 * Get the number of calendar days between the given dates. This means that the times are removed
1479 * from the dates and then the difference in days is calculated.
1480 *
1481 * @param {Date|String|Number} dateLeft - the later date
1482 * @param {Date|String|Number} dateRight - the earlier date
1483 * @param {Options} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
1484 * @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate}
1485 * @returns {Number} the number of calendar days
1486 * @throws {TypeError} 2 arguments required
1487 * @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
1488 *
1489 * @example
1490 * // How many calendar days are between
1491 * // 2 July 2011 23:00:00 and 2 July 2012 00:00:00?
1492 * var result = differenceInCalendarDays(
1493 * new Date(2012, 6, 2, 0, 0),
1494 * new Date(2011, 6, 2, 23, 0)
1495 * )
1496 * //=> 366
1497 * // How many calendar days are between
1498 * // 2 July 2011 23:59:00 and 3 July 2011 00:01:00?
1499 * var result = differenceInCalendarDays(
1500 * new Date(2011, 6, 2, 0, 1),
1501 * new Date(2011, 6, 2, 23, 59)
1502 * )
1503 * //=> 1
1504 */
1505function differenceInCalendarDays (dirtyDateLeft, dirtyDateRight, dirtyOptions) {
1506 if (arguments.length < 2) {
1507 throw new TypeError('2 arguments required, but only ' + arguments.length + ' present')
1508 }
1509
1510 var startOfDayLeft = startOfDay(dirtyDateLeft, dirtyOptions);
1511 var startOfDayRight = startOfDay(dirtyDateRight, dirtyOptions);
1512
1513 var timestampLeft = startOfDayLeft.getTime() -
1514 startOfDayLeft.getTimezoneOffset() * MILLISECONDS_IN_MINUTE$1;
1515 var timestampRight = startOfDayRight.getTime() -
1516 startOfDayRight.getTimezoneOffset() * MILLISECONDS_IN_MINUTE$1;
1517
1518 // Round the number of days to the nearest integer
1519 // because the number of milliseconds in a day is not constant
1520 // (e.g. it's different in the day of the daylight saving time clock shift)
1521 return Math.round((timestampLeft - timestampRight) / MILLISECONDS_IN_DAY$1)
1522}
1523
1524/**
1525 * @name addMilliseconds
1526 * @category Millisecond Helpers
1527 * @summary Add the specified number of milliseconds to the given date.
1528 *
1529 * @description
1530 * Add the specified number of milliseconds to the given date.
1531 *
1532 * @param {Date|String|Number} date - the date to be changed
1533 * @param {Number} amount - the amount of milliseconds to be added
1534 * @param {Options} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
1535 * @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate}
1536 * @returns {Date} the new date with the milliseconds added
1537 * @throws {TypeError} 2 arguments required
1538 * @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
1539 *
1540 * @example
1541 * // Add 750 milliseconds to 10 July 2014 12:45:30.000:
1542 * var result = addMilliseconds(new Date(2014, 6, 10, 12, 45, 30, 0), 750)
1543 * //=> Thu Jul 10 2014 12:45:30.750
1544 */
1545function addMilliseconds (dirtyDate, dirtyAmount, dirtyOptions) {
1546 if (arguments.length < 2) {
1547 throw new TypeError('2 arguments required, but only ' + arguments.length + ' present')
1548 }
1549
1550 var timestamp = toDate(dirtyDate, dirtyOptions).getTime();
1551 var amount = Number(dirtyAmount);
1552 return new Date(timestamp + amount)
1553}
1554
1555var MILLISECONDS_IN_MINUTE$2 = 60000;
1556
1557/**
1558 * @name addMinutes
1559 * @category Minute Helpers
1560 * @summary Add the specified number of minutes to the given date.
1561 *
1562 * @description
1563 * Add the specified number of minutes to the given date.
1564 *
1565 * @param {Date|String|Number} date - the date to be changed
1566 * @param {Number} amount - the amount of minutes to be added
1567 * @param {Options} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
1568 * @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate}
1569 * @returns {Date} the new date with the minutes added
1570 * @throws {TypeError} 2 arguments required
1571 * @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
1572 *
1573 * @example
1574 * // Add 30 minutes to 10 July 2014 12:00:00:
1575 * var result = addMinutes(new Date(2014, 6, 10, 12, 0), 30)
1576 * //=> Thu Jul 10 2014 12:30:00
1577 */
1578function addMinutes (dirtyDate, dirtyAmount, dirtyOptions) {
1579 if (arguments.length < 2) {
1580 throw new TypeError('2 arguments required, but only ' + arguments.length + ' present')
1581 }
1582
1583 var amount = Number(dirtyAmount);
1584 return addMilliseconds(dirtyDate, amount * MILLISECONDS_IN_MINUTE$2, dirtyOptions)
1585}
1586
1587/**
1588 * @name subMinutes
1589 * @category Minute Helpers
1590 * @summary Subtract the specified number of minutes from the given date.
1591 *
1592 * @description
1593 * Subtract the specified number of minutes from the given date.
1594 *
1595 * @param {Date|String|Number} date - the date to be changed
1596 * @param {Number} amount - the amount of minutes to be subtracted
1597 * @param {Options} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
1598 * @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate}
1599 * @returns {Date} the new date with the mintues subtracted
1600 * @throws {TypeError} 2 arguments required
1601 * @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
1602 *
1603 * @example
1604 * // Subtract 30 minutes from 10 July 2014 12:00:00:
1605 * var result = subMinutes(new Date(2014, 6, 10, 12, 0), 30)
1606 * //=> Thu Jul 10 2014 11:30:00
1607 */
1608function subMinutes (dirtyDate, dirtyAmount, dirtyOptions) {
1609 if (arguments.length < 2) {
1610 throw new TypeError('2 arguments required, but only ' + arguments.length + ' present')
1611 }
1612
1613 var amount = Number(dirtyAmount);
1614 return addMinutes(dirtyDate, -amount, dirtyOptions)
1615}
1616
1617/**
1618 * @name formatRelative
1619 * @category Common Helpers
1620 * @summary Represent the date in words relative to the given base date.
1621 *
1622 * @description
1623 * Represent the date in words relative to the given base date.
1624 *
1625 * | Distance to the base date | Result |
1626 * |---------------------------|---------------------------|
1627 * | Previous 6 days | last Sunday at 04:30 a.m. |
1628 * | Last day | yesterday at 04:30 a.m. |
1629 * | Same day | today at 04:30 a.m. |
1630 * | Next day | tomorrow at 04:30 a.m. |
1631 * | Next 6 days | Sunday at 04:30 a.m. |
1632 * | Other | 12/31/2017 |
1633 *
1634 * @param {Date|String|Number} date - the date to format
1635 * @param {Date|String|Number} baseDate - the date to compare with
1636 * @param {Options} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
1637 * @param {Locale} [options.locale=defaultLocale] - the locale object. See [Locale]{@link https://date-fns.org/docs/Locale}
1638 * @returns {String} the date in words
1639 * @throws {TypeError} 2 arguments required
1640 * @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
1641 * @throws {RangeError} `options.locale` must contain `localize` property
1642 * @throws {RangeError} `options.locale` must contain `formatLong` property
1643 * @throws {RangeError} `options.locale` must contain `formatRelative` property
1644 */
1645function formatRelative (dirtyDate, dirtyBaseDate, dirtyOptions) {
1646 if (arguments.length < 2) {
1647 throw new TypeError('2 arguments required, but only ' + arguments.length + ' present')
1648 }
1649
1650 var date = toDate(dirtyDate, dirtyOptions);
1651 var baseDate = toDate(dirtyBaseDate, dirtyOptions);
1652
1653 var options = dirtyOptions || {};
1654 var locale$$1 = options.locale || locale;
1655
1656 if (!locale$$1.localize) {
1657 throw new RangeError('locale must contain localize property')
1658 }
1659
1660 if (!locale$$1.formatLong) {
1661 throw new RangeError('locale must contain formatLong property')
1662 }
1663
1664 if (!locale$$1.formatRelative) {
1665 throw new RangeError('locale must contain formatRelative property')
1666 }
1667
1668 var diff = differenceInCalendarDays(date, baseDate, options);
1669
1670 if (isNaN(diff)) {
1671 return 'Invalid Date'
1672 }
1673
1674 var token;
1675 if (diff < -6) {
1676 token = 'other';
1677 } else if (diff < -1) {
1678 token = 'lastWeek';
1679 } else if (diff < 0) {
1680 token = 'yesterday';
1681 } else if (diff < 1) {
1682 token = 'today';
1683 } else if (diff < 2) {
1684 token = 'tomorrow';
1685 } else if (diff < 7) {
1686 token = 'nextWeek';
1687 } else {
1688 token = 'other';
1689 }
1690
1691 var utcDate = subMinutes(date, date.getTimezoneOffset(), options);
1692 var utcBaseDate = subMinutes(baseDate, date.getTimezoneOffset(), options);
1693 var formatStr = locale$$1.formatRelative(token, utcDate, utcBaseDate, options);
1694 return format(date, formatStr, options)
1695}
1696
1697return formatRelative;
1698
1699})();