1
+ var expDTComponents = / (?: [ E e c ] { 1 , 6 } | G { 1 , 5 } | (?: [ y Y u ] + | U { 1 , 5 } ) | [ M L ] { 1 , 5 } | d { 1 , 2 } | a | [ h k H K ] { 1 , 2 } | m { 1 , 2 } | s { 1 , 2 } | z { 1 , 4 } ) (? = ( [ ^ ' ] * ' [ ^ ' ] * ' ) * [ ^ ' ] * $ ) / g;
2
+
3
+ // Skip over patterns with these datetime components
4
+ var unwantedDTCs = / [ Q x X V O v Z A S j g F D w W I Q q H ] / ;
5
+
6
+ // Maps the number of characters in a CLDR pattern to the specification
7
+ var dtcLengthMap = {
8
+ month : [ 'numeric' , '2-digit' , 'short' , 'long' , 'narrow' ] ,
9
+ weekday : [ 'short' , 'short' , 'short' , 'long' , 'narrow' ] ,
10
+ era : [ 'short' , 'short' , 'short' , 'long' , 'narrow' ]
11
+ } ;
12
+
13
+ var dtKeys = [ "weekday" , "era" , "year" , "month" , "day" ] ;
14
+ var tmKeys = [ "hour" , "minite" , "second" , "timeZoneName" ] ;
15
+
16
+ function isDateFormatOnly ( obj ) {
17
+ for ( var i = 0 ; i < tmKeys . length ; i += 1 ) {
18
+ if ( obj . hasOwnProperty ( tmKeys [ i ] ) ) {
19
+ return false ;
20
+ }
21
+ }
22
+ return true ;
23
+ }
24
+
25
+ function isTimeFormatOnly ( obj ) {
26
+ for ( var i = 0 ; i < dtKeys . length ; i += 1 ) {
27
+ if ( obj . hasOwnProperty ( dtKeys [ i ] ) ) {
28
+ return false ;
29
+ }
30
+ }
31
+ return true ;
32
+ }
33
+
34
+ function createDateTimeFormat ( format ) {
35
+ if ( unwantedDTCs . test ( format ) )
36
+ return undefined ;
37
+
38
+ var formatObj = { } ;
39
+
40
+ // Replace the pattern string with the one required by the specification, whilst
41
+ // at the same time evaluating it for the subsets and formats
42
+ formatObj . pattern = format . replace ( expDTComponents , function ( $0 ) {
43
+ // See which symbol we're dealing with
44
+ switch ( $0 . charAt ( 0 ) ) {
45
+ case 'E' :
46
+ case 'e' :
47
+ case 'c' :
48
+ formatObj . weekday = dtcLengthMap . weekday [ $0 . length - 1 ] ;
49
+ return '{weekday}' ;
50
+
51
+ // Not supported yet
52
+ case 'G' :
53
+ formatObj . era = dtcLengthMap . era [ $0 . length - 1 ] ;
54
+ return '{era}' ;
55
+
56
+ case 'y' :
57
+ case 'Y' :
58
+ case 'u' :
59
+ case 'U' :
60
+ formatObj . year = $0 . length === 2 ? '2-digit' : 'numeric' ;
61
+ return '{year}' ;
62
+
63
+ case 'M' :
64
+ case 'L' :
65
+ formatObj . month = dtcLengthMap . month [ $0 . length - 1 ] ;
66
+ return '{month}' ;
67
+
68
+ case 'd' :
69
+ formatObj . day = $0 . length === 2 ? '2-digit' : 'numeric' ;
70
+ return '{day}' ;
71
+
72
+ case 'a' :
73
+ return '{ampm}' ;
74
+
75
+ case 'h' :
76
+ case 'H' :
77
+ case 'k' :
78
+ case 'K' :
79
+ formatObj . hour = $0 . length === 2 ? '2-digit' : 'numeric' ;
80
+ return '{hour}' ;
81
+
82
+ case 'm' :
83
+ formatObj . minute = $0 . length === 2 ? '2-digit' : 'numeric' ;
84
+ return '{minute}' ;
85
+
86
+ case 's' :
87
+ formatObj . second = $0 . length === 2 ? '2-digit' : 'numeric' ;
88
+ return '{second}' ;
89
+
90
+ case 'z' :
91
+ formatObj . timeZoneName = $0 . length < 4 ? 'short' : 'long' ;
92
+ return '{timeZoneName}' ;
93
+ }
94
+ } ) ;
95
+
96
+ // From http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns:
97
+ // 'In patterns, two single quotes represents a literal single quote, either
98
+ // inside or outside single quotes. Text within single quotes is not
99
+ // interpreted in any way (except for two adjacent single quotes).'
100
+ formatObj . pattern = formatObj . pattern . replace ( / ' ( [ ^ ' ] * ) ' / g, function ( $0 , literal ) {
101
+ return literal ? literal : "'" ;
102
+ } ) ;
103
+
104
+ if ( formatObj . pattern . indexOf ( '{ampm}' ) > - 1 ) {
105
+ formatObj . pattern12 = formatObj . pattern ;
106
+ formatObj . pattern = formatObj . pattern . replace ( '{ampm}' , '' ) . trim ( ) ;
107
+ }
108
+
109
+ return formatObj ;
110
+ }
111
+
112
+ export function createDateTimeFormats ( formats ) {
113
+
114
+ var avail = formats . availableFormats ;
115
+ var order = formats . medium ;
116
+ var result = [ ] ;
117
+ var M , E , frmt , dFrmt , computed , i , j ;
118
+ var timeFrmts = [ ] ;
119
+ var dateFrmts = [ ] ;
120
+
121
+ // Map the formats into a pattern for createDateTimeFormats
122
+ for ( frmt in avail ) {
123
+ if ( avail . hasOwnProperty ( frmt ) ) {
124
+ dFrmt = avail [ frmt ] ;
125
+
126
+ // Expand component lengths if necessary, as allowed in the LDML spec
127
+ // Get the lengths of 'M' and 'E' substrings in the date pattern
128
+ // as arrays that can be joined to create a new substring
129
+ M = new Array ( ( frmt . match ( / M / g) || [ ] ) . length + 1 ) ;
130
+ E = new Array ( ( frmt . match ( / E / g) || [ ] ) . length + 1 ) ;
131
+
132
+ if ( M . length > 2 )
133
+ dFrmt = dFrmt . replace ( / ( M | L ) + / , M . join ( '$1' ) ) ;
134
+
135
+ if ( E . length > 2 )
136
+ dFrmt = dFrmt . replace ( / ( [ E e c ] ) + / , E . join ( '$1' ) ) ;
137
+
138
+ computed = createDateTimeFormat ( dFrmt ) ;
139
+
140
+ if ( computed ) {
141
+ result . push ( computed ) ;
142
+ // in some cases, the format is only displaying date specific props
143
+ // or time specific props, in which case we need to also produce the
144
+ // combined formats.
145
+ if ( isDateFormatOnly ( computed ) ) {
146
+ dateFrmts . push ( dFrmt ) ;
147
+ } else if ( isTimeFormatOnly ( computed ) ) {
148
+ timeFrmts . push ( dFrmt ) ;
149
+ }
150
+ }
151
+ }
152
+ }
153
+
154
+ // combine time and date formats when they are orthogonals to complete the
155
+ // formats supported by browsers by relying on the value of "formats.medium"
156
+ for ( i = 0 ; i < timeFrmts . length ; i += 1 ) {
157
+ for ( j = 0 ; j < dateFrmts . length ; j += 1 ) {
158
+ computed = createDateTimeFormat (
159
+ order
160
+ . replace ( '{0}' , timeFrmts [ i ] )
161
+ . replace ( '{1}' , dateFrmts [ j ] )
162
+ . replace ( / ^ [ , \s ] + | [ , \s ] + $ / gi, '' )
163
+ ) ;
164
+ if ( computed ) {
165
+ result . push ( computed ) ;
166
+ }
167
+ }
168
+ }
169
+ return result ;
170
+ }
0 commit comments