/
index.js
134 lines (121 loc) · 6.35 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import toDate from '../toDate/index.js'
import formatters from '../_lib/format/lightFormatters/index.js'
import getTimezoneOffsetInMilliseconds from '../_lib/getTimezoneOffsetInMilliseconds/index.js'
import isValid from '../isValid/index.js'
import subMilliseconds from '../subMilliseconds/index.js'
// This RegExp consists of three parts separated by `|`:
// - (\w)\1* matches any sequences of the same letter
// - '' matches two quote characters in a row
// - '(''|[^'])+('|$) matches anything surrounded by two quote characters ('),
// except a single quote symbol, which ends the sequence.
// Two quote characters do not end the sequence.
// If there is no matching single quote
// then the sequence will continue until the end of the string.
// - . matches any single character unmatched by previous parts of the RegExps
var formattingTokensRegExp = /(\w)\1*|''|'(''|[^'])+('|$)|./g
var escapedStringRegExp = /^'(.*?)'?$/
var doubleQuoteRegExp = /''/g
/**
* @name lightFormat
* @category Common Helpers
* @summary Format the date.
*
* @description
* Return the formatted date string in the given format. Unlike `format`,
* `lightFormat` doesn't use locales and outputs date using the most popular tokens.
*
* > ⚠️ Please note that the `lightFormat` tokens differ from Moment.js and other libraries.
* > See: https://git.io/fxCyr
*
* The characters wrapped between two single quotes characters (') are escaped.
* Two single quotes in a row, whether inside or outside a quoted sequence, represent a 'real' single quote.
* (see the last example)
*
* Format of the string is based on Unicode Technical Standard #35:
* https://www.unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table
* with a few additions (see note 7 below the table).
*
* Accepted patterns:
* | Unit | Pattern | Result examples |
* |---------------------------------|---------|-----------------------------------|
* | AM, PM | a..aaa | AM, PM |
* | | aaaa | a.m., p.m. |
* | | aaaaa | a, p |
* | Calendar year | y | 44, 1, 1900, 2017 |
* | | yy | 44, 01, 00, 17 |
* | | yyy | 044, 001, 000, 017 |
* | | yyyy | 0044, 0001, 1900, 2017 |
* | Month (formatting) | M | 1, 2, ..., 12 |
* | | MM | 01, 02, ..., 12 |
* | Day of month | d | 1, 2, ..., 31 |
* | | dd | 01, 02, ..., 31 |
* | Hour [1-12] | h | 1, 2, ..., 11, 12 |
* | | hh | 01, 02, ..., 11, 12 |
* | Hour [0-23] | H | 0, 1, 2, ..., 23 |
* | | HH | 00, 01, 02, ..., 23 |
* | Minute | m | 0, 1, ..., 59 |
* | | mm | 00, 01, ..., 59 |
* | Second | s | 0, 1, ..., 59 |
* | | ss | 00, 01, ..., 59 |
* | Timezone (ISO-8601 w/ Z) | X | -08, +0530, Z |
* | | XX | -0800, +0530, Z |
* | | XXX | -08:00, +05:30, Z |
* | | XXXX | -0800, +0530, Z, +123456 |
* | | XXXXX | -08:00, +05:30, Z, +12:34:56 |
* | Timezone (ISO-8601 w/o Z) | x | -08, +0530, +00 |
* | | xx | -0800, +0530, +0000 |
* | | xxx | -08:00, +05:30, +00:00 |
* | | xxxx | -0800, +0530, +0000, +123456 |
* | | xxxxx | -08:00, +05:30, +00:00, +12:34:56 |
*
* @param {Date|String|Number} date - the original date
* @param {String} format - the string of tokens
* @param {Options} [options] - the object with options. See [Options]{@link https://date-fns.org/docs/Options}
* @param {0|1|2} [options.additionalDigits=2] - passed to `toDate`. See [toDate]{@link https://date-fns.org/docs/toDate}
* @returns {String} the formatted date string
* @throws {TypeError} 2 arguments required
* @throws {RangeError} `options.additionalDigits` must be 0, 1 or 2
*
* @example
* var result = format(new Date(2014, 1, 11), 'yyyy-MM-dd')
* //=> '1987-02-11'
*/
export default function lightFormat(dirtyDate, dirtyFormatStr, options) {
if (arguments.length < 2) {
throw new TypeError(
'2 arguments required, but only ' + arguments.length + ' present'
)
}
var formatStr = String(dirtyFormatStr)
var originalDate = toDate(dirtyDate, options)
if (!isValid(originalDate, options)) {
return 'Invalid Date'
}
// Convert the date in system timezone to the same date in UTC+00:00 timezone.
// This ensures that when UTC functions will be implemented, locales will be compatible with them.
// See an issue about UTC functions: https://github.com/date-fns/date-fns/issues/376
var timezoneOffset = getTimezoneOffsetInMilliseconds(originalDate)
var utcDate = subMilliseconds(originalDate, timezoneOffset, options)
var result = formatStr
.match(formattingTokensRegExp)
.map(function(substring) {
// Replace two single quote characters with one single quote character
if (substring === "''") {
return "'"
}
var firstCharacter = substring[0]
if (firstCharacter === "'") {
return cleanEscapedString(substring)
}
var formatter = formatters[firstCharacter]
if (formatter) {
return formatter(utcDate, substring, null, {})
}
return substring
})
.join('')
return result
}
function cleanEscapedString(input) {
return input.match(escapedStringRegExp)[1].replace(doubleQuoteRegExp, "'")
}