1
1
import { u } from '../localizedFormat/utils'
2
+ import { daysInMonth } from './utils'
2
3
3
4
const formattingTokens = / ( \[ [ ^ [ ] * \] ) | ( [ - _ : / . , ( ) \s ] + ) | ( A | a | Y Y Y Y | Y Y ? | M M ? M ? M ? | D o | D D ? | h h ? | H H ? | m m ? | s s ? | S { 1 , 3 } | z | Z Z ? ) / g
4
5
@@ -138,6 +139,30 @@ function correctHours(time) {
138
139
}
139
140
}
140
141
142
+ function checkOverflow ( year , month , day , hours , minutes , seconds , milliseconds ) {
143
+ let overflow = false
144
+ if ( month ) {
145
+ overflow = overflow || ( month < 0 || month > 12 )
146
+ }
147
+ if ( ( day !== undefined ) && ( day !== null ) ) {
148
+ overflow = overflow || ( day < 1 || day > daysInMonth ( year , month ) )
149
+ }
150
+ if ( hours ) {
151
+ overflow = overflow || ( hours < 0 || hours > 24 ||
152
+ ( hours === 24 && ( minutes !== 0 || seconds !== 0 || milliseconds !== 0 ) ) )
153
+ }
154
+ if ( minutes ) {
155
+ overflow = overflow || ( minutes < 0 || minutes > 59 )
156
+ }
157
+ if ( seconds ) {
158
+ overflow = overflow || ( seconds < 0 || seconds > 59 )
159
+ }
160
+ if ( milliseconds ) {
161
+ overflow = overflow || ( milliseconds < 0 || milliseconds > 999 )
162
+ }
163
+ return overflow
164
+ }
165
+
141
166
function makeParser ( format ) {
142
167
format = u ( format , locale && locale . formats )
143
168
const array = format . match ( formattingTokens )
@@ -154,32 +179,48 @@ function makeParser(format) {
154
179
}
155
180
}
156
181
return function ( input ) {
157
- const time = { }
158
- for ( let i = 0 , start = 0 ; i < length ; i += 1 ) {
182
+ const time = { strictMatch : true }
183
+ let start = 0
184
+ for ( let i = 0 ; i < length ; i += 1 ) {
159
185
const token = array [ i ]
160
186
if ( typeof token === 'string' ) {
187
+ const separator = input . slice ( start , start + token . length )
188
+ time . strictMatch = time . strictMatch && ( separator === token )
161
189
start += token . length
162
190
} else {
163
191
const { regex, parser } = token
164
192
const part = input . slice ( start )
165
193
const match = regex . exec ( part )
166
- const value = match [ 0 ]
167
- parser . call ( time , value )
168
- input = input . replace ( value , '' )
194
+ if ( match !== null ) {
195
+ const value = match [ 0 ] // eslint-disable-line prefer-destructuring
196
+ parser . call ( time , value )
197
+ input = input . replace ( value , '' )
198
+ if ( match . index !== 0 ) {
199
+ time . strictMatch = false
200
+ start += match . index
201
+ }
202
+ } else {
203
+ time . strictMatch = false
204
+ break
205
+ }
169
206
}
170
207
}
208
+ if ( start < input . length ) {
209
+ time . strictMatch = false
210
+ }
171
211
correctHours ( time )
172
212
return time
173
213
}
174
214
}
175
215
176
- const parseFormattedInput = ( input , format , utc ) => {
216
+ const parseFormattedInput = ( input , format , utc , strict ) => {
177
217
try {
178
218
if ( [ 'x' , 'X' ] . indexOf ( format ) > - 1 ) return new Date ( ( format === 'X' ? 1000 : 1 ) * input )
179
219
const parser = makeParser ( format )
180
220
const {
181
- year, month, day, hours, minutes, seconds, milliseconds, zone
221
+ year, month, day, hours, minutes, seconds, milliseconds, zone, strictMatch
182
222
} = parser ( input )
223
+ const isOverflow = checkOverflow ( year , month , day , hours , minutes , seconds , milliseconds )
183
224
const now = new Date ( )
184
225
const d = day || ( ( ! year && ! month ) ? now . getDate ( ) : 1 )
185
226
const y = year || now . getFullYear ( )
@@ -191,19 +232,22 @@ const parseFormattedInput = (input, format, utc) => {
191
232
const m = minutes || 0
192
233
const s = seconds || 0
193
234
const ms = milliseconds || 0
194
- if ( zone ) {
195
- return new Date ( Date . UTC ( y , M , d , h , m , s , ms + ( zone . offset * 60 * 1000 ) ) )
196
- }
197
- if ( utc ) {
198
- return new Date ( Date . UTC ( y , M , d , h , m , s , ms ) )
235
+ let parsedDate = new Date ( '' ) // Invalid Date
236
+ if ( ! strict || ( strict && strictMatch && ! isOverflow ) ) {
237
+ if ( zone ) {
238
+ parsedDate = new Date ( Date . UTC ( y , M , d , h , m , s , ms + ( zone . offset * 60 * 1000 ) ) )
239
+ } else if ( utc ) {
240
+ parsedDate = new Date ( Date . UTC ( y , M , d , h , m , s , ms ) )
241
+ } else {
242
+ parsedDate = new Date ( y , M , d , h , m , s , ms )
243
+ }
199
244
}
200
- return new Date ( y , M , d , h , m , s , ms )
245
+ return parsedDate
201
246
} catch ( e ) {
202
247
return new Date ( '' ) // Invalid Date
203
248
}
204
249
}
205
250
206
-
207
251
export default ( o , C , d ) => {
208
252
d . p . customParseFormat = true
209
253
if ( o && o . parseTwoDigitYear ) {
@@ -229,22 +273,16 @@ export default (o, C, d) => {
229
273
if ( ! isStrictWithoutLocale && pl ) {
230
274
locale = d . Ls [ pl ]
231
275
}
232
- this . $d = parseFormattedInput ( date , format , utc )
276
+ this . $d = parseFormattedInput ( date , format , utc , isStrict )
233
277
this . init ( )
234
278
if ( pl && pl !== true ) this . $L = this . locale ( pl ) . $L
235
- // use != to treat
236
- // input number 1410715640579 and format string '1410715640579' equal
237
- // eslint-disable-next-line eqeqeq
238
- if ( isStrict && date != this . format ( format ) ) {
239
- this . $d = new Date ( '' )
240
- }
241
279
// reset global locale to make parallel unit test
242
280
locale = { }
243
281
} else if ( format instanceof Array ) {
244
282
const len = format . length
245
283
for ( let i = 1 ; i <= len ; i += 1 ) {
246
284
args [ 1 ] = format [ i - 1 ]
247
- const result = d . apply ( this , args )
285
+ const result = d . apply ( this , [ date , cfg ] )
248
286
if ( result . isValid ( ) ) {
249
287
this . $d = result . $d
250
288
this . $L = result . $L
0 commit comments