globalize-rpk 1.7.1 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/CONTRIBUTING.md +5 -0
  2. package/README.md +818 -0
  3. package/{globalize → dist/globalize}/currency.js +3 -3
  4. package/{globalize → dist/globalize}/date.js +3 -3
  5. package/{globalize → dist/globalize}/message.js +2 -2
  6. package/{globalize → dist/globalize}/number.js +3 -3
  7. package/{globalize → dist/globalize}/plural.js +3 -3
  8. package/{globalize → dist/globalize}/relative-time.js +3 -3
  9. package/{globalize → dist/globalize}/unit.js +0 -0
  10. package/dist/globalize-runtime/currency.js +183 -0
  11. package/dist/globalize-runtime/date.js +1657 -0
  12. package/dist/globalize-runtime/message.js +120 -0
  13. package/dist/globalize-runtime/number.js +919 -0
  14. package/dist/globalize-runtime/plural.js +90 -0
  15. package/dist/globalize-runtime/relative-time.js +120 -0
  16. package/dist/globalize-runtime/unit.js +132 -0
  17. package/{globalize → dist}/globalize-runtime.js +0 -0
  18. package/{globalize → dist}/globalize.js +2 -2
  19. package/{node-main.js → dist/node-main.js} +0 -0
  20. package/doc/api/core/constructor.md +28 -0
  21. package/doc/api/core/load.md +96 -0
  22. package/doc/api/core/locale.md +43 -0
  23. package/doc/api/currency/currency-formatter.md +196 -0
  24. package/doc/api/currency/currency-to-parts-formatter.md +117 -0
  25. package/doc/api/date/date-formatter.md +203 -0
  26. package/doc/api/date/date-parser.md +60 -0
  27. package/doc/api/date/date-to-parts-formatter.md +176 -0
  28. package/doc/api/date/load-iana-time-zone.md +29 -0
  29. package/doc/api/message/load-messages.md +105 -0
  30. package/doc/api/message/message-formatter.md +208 -0
  31. package/doc/api/number/number-formatter.md +202 -0
  32. package/doc/api/number/number-parser.md +130 -0
  33. package/doc/api/number/number-to-parts-formatter.md +140 -0
  34. package/doc/api/plural/plural-generator.md +84 -0
  35. package/doc/api/relative-time/relative-time-formatter.md +60 -0
  36. package/doc/api/unit/unit-formatter.md +72 -0
  37. package/doc/blog-post/2017-07-xx-1.3.0-announcement.md +177 -0
  38. package/doc/cldr.md +114 -0
  39. package/doc/error/e-default-locale-not-defined.md +9 -0
  40. package/doc/error/e-invalid-cldr.md +14 -0
  41. package/doc/error/e-invalid-par-type.md +12 -0
  42. package/doc/error/e-invalid-par-value.md +11 -0
  43. package/doc/error/e-missing-cldr.md +11 -0
  44. package/doc/error/e-missing-parameter.md +10 -0
  45. package/doc/error/e-missing-plural-module.md +9 -0
  46. package/doc/error/e-par-missing-key.md +11 -0
  47. package/doc/error/e-par-out-of-range.md +13 -0
  48. package/doc/error/e-unsupported.md +10 -0
  49. package/doc/migrating-from-0.x.md +64 -0
  50. package/examples/amd-bower/.bowerrc +7 -0
  51. package/examples/amd-bower/README.md +65 -0
  52. package/examples/amd-bower/bower.json +13 -0
  53. package/examples/amd-bower/index.html +46 -0
  54. package/examples/amd-bower/main.js +141 -0
  55. package/examples/amd-bower/messages/en.json +12 -0
  56. package/examples/amd-bower/package.json +14 -0
  57. package/examples/app-npm-webpack/README.md +74 -0
  58. package/examples/app-npm-webpack/app/index.js +89 -0
  59. package/examples/app-npm-webpack/index-template.html +71 -0
  60. package/examples/app-npm-webpack/messages/ar.json +25 -0
  61. package/examples/app-npm-webpack/messages/de.json +21 -0
  62. package/examples/app-npm-webpack/messages/en.json +21 -0
  63. package/examples/app-npm-webpack/messages/es.json +21 -0
  64. package/examples/app-npm-webpack/messages/pt.json +21 -0
  65. package/examples/app-npm-webpack/messages/ru.json +23 -0
  66. package/examples/app-npm-webpack/messages/zh.json +20 -0
  67. package/examples/app-npm-webpack/package.json +17 -0
  68. package/examples/app-npm-webpack/webpack-config.js +63 -0
  69. package/examples/globalize-compiler/README.md +45 -0
  70. package/examples/globalize-compiler/app.js +58 -0
  71. package/examples/globalize-compiler/development.html +121 -0
  72. package/examples/globalize-compiler/messages.json +12 -0
  73. package/examples/globalize-compiler/package.json +15 -0
  74. package/examples/globalize-compiler/production.html +75 -0
  75. package/examples/node-npm/README.md +57 -0
  76. package/examples/node-npm/main.js +65 -0
  77. package/examples/node-npm/messages/en.json +12 -0
  78. package/examples/node-npm/package.json +10 -0
  79. package/examples/plain-javascript/README.md +81 -0
  80. package/examples/plain-javascript/index.html +445 -0
  81. package/package.json +27 -4
@@ -0,0 +1,1657 @@
1
+ /**
2
+ * Globalize Runtime v1.7.0
3
+ *
4
+ * https://github.com/globalizejs/globalize
5
+ *
6
+ * Copyright OpenJS Foundation and other contributors
7
+ * Released under the MIT license
8
+ * https://jquery.org/license
9
+ *
10
+ * Date: 2021-08-02T11:53Z
11
+ */
12
+ /*!
13
+ * Globalize Runtime v1.7.0 2021-08-02T11:53Z Released under the MIT license
14
+ * http://git.io/TrdQbw
15
+ */
16
+ (function( root, factory ) {
17
+
18
+ "use strict";
19
+
20
+ // UMD returnExports
21
+ if ( typeof define === "function" && define.amd ) {
22
+
23
+ // AMD
24
+ define([
25
+ "../globalize-runtime",
26
+ "./number"
27
+ ], factory );
28
+ } else if ( typeof exports === "object" ) {
29
+
30
+ // Node, CommonJS
31
+ module.exports = factory(
32
+ require( "../globalize-runtime" ),
33
+ require( "./number" )
34
+ );
35
+ } else {
36
+
37
+ // Extend global
38
+ factory( root.Globalize );
39
+ }
40
+ }(this, function( Globalize ) {
41
+
42
+
43
+
44
+ var createErrorUnsupportedFeature = Globalize._createErrorUnsupportedFeature,
45
+ looseMatching = Globalize._looseMatching,
46
+ partsJoin = Globalize._partsJoin,
47
+ partsPush = Globalize._partsPush,
48
+ regexpEscape = Globalize._regexpEscape,
49
+ removeLiteralQuotes = Globalize._removeLiteralQuotes,
50
+ runtimeKey = Globalize._runtimeKey,
51
+ stringPad = Globalize._stringPad,
52
+ validateParameterPresence = Globalize._validateParameterPresence,
53
+ validateParameterType = Globalize._validateParameterType,
54
+ validateParameterTypeString = Globalize._validateParameterTypeString;
55
+
56
+
57
+ var validateParameterTypeDate = function( value, name ) {
58
+ validateParameterType( value, name, value === undefined || value instanceof Date, "Date" );
59
+ };
60
+
61
+
62
+ var ZonedDateTime = (function() {
63
+ function definePrivateProperty(object, property, value) {
64
+ Object.defineProperty(object, property, {
65
+ value: value
66
+ });
67
+ }
68
+
69
+ function getUntilsIndex(original, untils) {
70
+ var index = 0;
71
+ var originalTime = original.getTime();
72
+
73
+ // TODO Should we do binary search for improved performance?
74
+ while (index < untils.length - 1 && originalTime >= untils[index]) {
75
+ index++;
76
+ }
77
+ return index;
78
+ }
79
+
80
+ function setWrap(fn) {
81
+ var offset1 = this.getTimezoneOffset();
82
+ var ret = fn();
83
+ this.original.setTime(new Date(this.getTime()));
84
+ var offset2 = this.getTimezoneOffset();
85
+ if (offset2 - offset1) {
86
+ this.original.setMinutes(this.original.getMinutes() + offset2 - offset1);
87
+ }
88
+ return ret;
89
+ }
90
+
91
+ var ZonedDateTime = function(date, timeZoneData) {
92
+ definePrivateProperty(this, "original", new Date(date.getTime()));
93
+ definePrivateProperty(this, "local", new Date(date.getTime()));
94
+ definePrivateProperty(this, "timeZoneData", timeZoneData);
95
+ definePrivateProperty(this, "setWrap", setWrap);
96
+ if (!(timeZoneData.untils && timeZoneData.offsets && timeZoneData.isdsts)) {
97
+ throw new Error("Invalid IANA data");
98
+ }
99
+ this.setTime(this.local.getTime() - this.getTimezoneOffset() * 60 * 1000);
100
+ };
101
+
102
+ ZonedDateTime.prototype.clone = function() {
103
+ return new ZonedDateTime(this.original, this.timeZoneData);
104
+ };
105
+
106
+ // Date field getters.
107
+ ["getFullYear", "getMonth", "getDate", "getDay", "getHours", "getMinutes",
108
+ "getSeconds", "getMilliseconds"].forEach(function(method) {
109
+ // Corresponding UTC method, e.g., "getUTCFullYear" if method === "getFullYear".
110
+ var utcMethod = "getUTC" + method.substr(3);
111
+ ZonedDateTime.prototype[method] = function() {
112
+ return this.local[utcMethod]();
113
+ };
114
+ });
115
+
116
+ // Note: Define .valueOf = .getTime for arithmetic operations like date1 - date2.
117
+ ZonedDateTime.prototype.valueOf =
118
+ ZonedDateTime.prototype.getTime = function() {
119
+ return this.local.getTime() + this.getTimezoneOffset() * 60 * 1000;
120
+ };
121
+
122
+ ZonedDateTime.prototype.getTimezoneOffset = function() {
123
+ var index = getUntilsIndex(this.original, this.timeZoneData.untils);
124
+ return this.timeZoneData.offsets[index];
125
+ };
126
+
127
+ // Date field setters.
128
+ ["setFullYear", "setMonth", "setDate", "setHours", "setMinutes", "setSeconds", "setMilliseconds"].forEach(function(method) {
129
+ // Corresponding UTC method, e.g., "setUTCFullYear" if method === "setFullYear".
130
+ var utcMethod = "setUTC" + method.substr(3);
131
+ ZonedDateTime.prototype[method] = function(value) {
132
+ var local = this.local;
133
+ // Note setWrap is needed for seconds and milliseconds just because
134
+ // abs(value) could be >= a minute.
135
+ return this.setWrap(function() {
136
+ return local[utcMethod](value);
137
+ });
138
+ };
139
+ });
140
+
141
+ ZonedDateTime.prototype.setTime = function(time) {
142
+ return this.local.setTime(time);
143
+ };
144
+
145
+ ZonedDateTime.prototype.isDST = function() {
146
+ var index = getUntilsIndex(this.original, this.timeZoneData.untils);
147
+ return Boolean(this.timeZoneData.isdsts[index]);
148
+ };
149
+
150
+ ZonedDateTime.prototype.inspect = function() {
151
+ var index = getUntilsIndex(this.original, this.timeZoneData.untils);
152
+ var abbrs = this.timeZoneData.abbrs;
153
+ return this.local.toISOString().replace(/Z$/, "") + " " +
154
+ (abbrs && abbrs[index] + " " || (this.getTimezoneOffset() * -1) + " ") +
155
+ (this.isDST() ? "(daylight savings)" : "");
156
+ };
157
+
158
+ ZonedDateTime.prototype.toDate = function() {
159
+ return new Date(this.getTime());
160
+ };
161
+
162
+ // Type cast getters.
163
+ ["toISOString", "toJSON", "toUTCString"].forEach(function(method) {
164
+ ZonedDateTime.prototype[method] = function() {
165
+ return this.toDate()[method]();
166
+ };
167
+ });
168
+
169
+ return ZonedDateTime;
170
+ }());
171
+
172
+
173
+ /**
174
+ * dayOfWeek( date, firstDay )
175
+ *
176
+ * @date
177
+ *
178
+ * @firstDay the result of `dateFirstDayOfWeek( cldr )`
179
+ *
180
+ * Return the day of the week normalized by the territory's firstDay [0-6].
181
+ * Eg for "mon":
182
+ * - return 0 if territory is GB, or BR, or DE, or FR (week starts on "mon");
183
+ * - return 1 if territory is US (week starts on "sun");
184
+ * - return 2 if territory is EG (week starts on "sat");
185
+ */
186
+ var dateDayOfWeek = function( date, firstDay ) {
187
+ return ( date.getDay() - firstDay + 7 ) % 7;
188
+ };
189
+
190
+
191
+
192
+
193
+ /**
194
+ * distanceInDays( from, to )
195
+ *
196
+ * Return the distance in days between from and to Dates.
197
+ */
198
+ var dateDistanceInDays = function( from, to ) {
199
+ var inDays = 864e5;
200
+ return ( to.getTime() - from.getTime() ) / inDays;
201
+ };
202
+
203
+
204
+
205
+
206
+ /**
207
+ * startOf changes the input to the beginning of the given unit.
208
+ *
209
+ * For example, starting at the start of a day, resets hours, minutes
210
+ * seconds and milliseconds to 0. Starting at the month does the same, but
211
+ * also sets the date to 1.
212
+ *
213
+ * Returns the modified date
214
+ */
215
+ var dateStartOf = function( date, unit ) {
216
+ date = date instanceof ZonedDateTime ? date.clone() : new Date( date.getTime() );
217
+ switch ( unit ) {
218
+ case "year":
219
+ date.setMonth( 0 );
220
+ /* falls through */
221
+ case "month":
222
+ date.setDate( 1 );
223
+ /* falls through */
224
+ case "day":
225
+ date.setHours( 0 );
226
+ /* falls through */
227
+ case "hour":
228
+ date.setMinutes( 0 );
229
+ /* falls through */
230
+ case "minute":
231
+ date.setSeconds( 0 );
232
+ /* falls through */
233
+ case "second":
234
+ date.setMilliseconds( 0 );
235
+ }
236
+ return date;
237
+ };
238
+
239
+
240
+
241
+
242
+ /**
243
+ * dayOfYear
244
+ *
245
+ * Return the distance in days of the date to the begin of the year [0-d].
246
+ */
247
+ var dateDayOfYear = function( date ) {
248
+ return Math.floor( dateDistanceInDays( dateStartOf( date, "year" ), date ) );
249
+ };
250
+
251
+
252
+
253
+
254
+ /**
255
+ * Returns a new object created by using `object`'s values as keys, and the keys as values.
256
+ */
257
+ var objectInvert = function( object, fn ) {
258
+ fn = fn || function( object, key, value ) {
259
+ object[ value ] = key;
260
+ return object;
261
+ };
262
+ return Object.keys( object ).reduce(function( newObject, key ) {
263
+ return fn( newObject, key, object[ key ] );
264
+ }, {});
265
+ };
266
+
267
+
268
+
269
+
270
+ // Invert key and values, e.g., {"year": "yY"} ==> {"y": "year", "Y": "year"}
271
+ var dateFieldsMap = objectInvert({
272
+ "era": "G",
273
+ "year": "yY",
274
+ "quarter": "qQ",
275
+ "month": "ML",
276
+ "week": "wW",
277
+ "day": "dDF",
278
+ "weekday": "ecE",
279
+ "dayperiod": "a",
280
+ "hour": "hHkK",
281
+ "minute": "m",
282
+ "second": "sSA",
283
+ "zone": "zvVOxX"
284
+ }, function( object, key, value ) {
285
+ value.split( "" ).forEach(function( symbol ) {
286
+ object[ symbol ] = key;
287
+ });
288
+ return object;
289
+ });
290
+
291
+
292
+
293
+
294
+ /**
295
+ * millisecondsInDay
296
+ */
297
+ var dateMillisecondsInDay = function( date ) {
298
+
299
+ // TODO Handle daylight savings discontinuities
300
+ return date - dateStartOf( date, "day" );
301
+ };
302
+
303
+
304
+
305
+
306
+ var datePatternRe = ( /([a-z])\1*|'([^']|'')+'|''|./ig );
307
+
308
+
309
+
310
+
311
+ /**
312
+ * hourFormat( date, format, timeSeparator, formatNumber )
313
+ *
314
+ * Return date's timezone offset according to the format passed.
315
+ * Eg for format when timezone offset is 180:
316
+ * - "+H;-H": -3
317
+ * - "+HHmm;-HHmm": -0300
318
+ * - "+HH:mm;-HH:mm": -03:00
319
+ * - "+HH:mm:ss;-HH:mm:ss": -03:00:00
320
+ */
321
+ var dateTimezoneHourFormat = function( date, format, timeSeparator, formatNumber ) {
322
+ var absOffset,
323
+ offset = date.getTimezoneOffset();
324
+
325
+ absOffset = Math.abs( offset );
326
+ formatNumber = formatNumber || {
327
+ 1: function( value ) {
328
+ return stringPad( value, 1 );
329
+ },
330
+ 2: function( value ) {
331
+ return stringPad( value, 2 );
332
+ }
333
+ };
334
+
335
+ return format
336
+
337
+ // Pick the correct sign side (+ or -).
338
+ .split( ";" )[ offset > 0 ? 1 : 0 ]
339
+
340
+ // Localize time separator
341
+ .replace( ":", timeSeparator )
342
+
343
+ // Update hours offset.
344
+ .replace( /HH?/, function( match ) {
345
+ return formatNumber[ match.length ]( Math.floor( absOffset / 60 ) );
346
+ })
347
+
348
+ // Update minutes offset and return.
349
+ .replace( /mm/, function() {
350
+ return formatNumber[ 2 ]( Math.floor( absOffset % 60 ) );
351
+ })
352
+
353
+ // Update minutes offset and return.
354
+ .replace( /ss/, function() {
355
+ return formatNumber[ 2 ]( Math.floor( absOffset % 1 * 60 ) );
356
+ });
357
+ };
358
+
359
+
360
+
361
+
362
+ var dateWeekDays = [ "sun", "mon", "tue", "wed", "thu", "fri", "sat" ];
363
+
364
+
365
+
366
+
367
+ /**
368
+ * format( date, properties )
369
+ *
370
+ * @date [Date instance].
371
+ *
372
+ * @properties
373
+ *
374
+ * TODO Support other calendar types.
375
+ *
376
+ * Disclosure: this function borrows excerpts of dojo/date/locale.
377
+ */
378
+ var dateFormat = function( date, numberFormatters, properties ) {
379
+ var parts = [];
380
+
381
+ var timeSeparator = properties.timeSeparator;
382
+
383
+ // create globalize date with given timezone data
384
+ if ( properties.timeZoneData ) {
385
+ date = new ZonedDateTime( date, properties.timeZoneData() );
386
+ }
387
+
388
+ properties.pattern.replace( datePatternRe, function( current ) {
389
+ var aux, dateField, type, value,
390
+ chr = current.charAt( 0 ),
391
+ length = current.length;
392
+
393
+ if ( chr === "j" ) {
394
+
395
+ // Locale preferred hHKk.
396
+ // http://www.unicode.org/reports/tr35/tr35-dates.html#Time_Data
397
+ chr = properties.preferredTime;
398
+ }
399
+
400
+ if ( chr === "Z" ) {
401
+
402
+ // Z..ZZZ: same as "xxxx".
403
+ if ( length < 4 ) {
404
+ chr = "x";
405
+ length = 4;
406
+
407
+ // ZZZZ: same as "OOOO".
408
+ } else if ( length < 5 ) {
409
+ chr = "O";
410
+ length = 4;
411
+
412
+ // ZZZZZ: same as "XXXXX"
413
+ } else {
414
+ chr = "X";
415
+ length = 5;
416
+ }
417
+ }
418
+
419
+ // z...zzz: "{shortRegion}", e.g., "PST" or "PDT".
420
+ // zzzz: "{regionName} {Standard Time}" or "{regionName} {Daylight Time}",
421
+ // e.g., "Pacific Standard Time" or "Pacific Daylight Time".
422
+ if ( chr === "z" ) {
423
+ if ( date.isDST ) {
424
+ value = date.isDST() ? properties.daylightTzName : properties.standardTzName;
425
+ }
426
+
427
+ // Fall back to "O" format.
428
+ if ( !value ) {
429
+ chr = "O";
430
+ if ( length < 4 ) {
431
+ length = 1;
432
+ }
433
+ }
434
+ }
435
+
436
+ switch ( chr ) {
437
+
438
+ // Era
439
+ case "G":
440
+ value = properties.eras[ date.getFullYear() < 0 ? 0 : 1 ];
441
+ break;
442
+
443
+ // Year
444
+ case "y":
445
+
446
+ // Plain year.
447
+ // The length specifies the padding, but for two letters it also specifies the
448
+ // maximum length.
449
+ value = date.getFullYear();
450
+ if ( length === 2 ) {
451
+ value = String( value );
452
+ value = +value.substr( value.length - 2 );
453
+ }
454
+ break;
455
+
456
+ case "Y":
457
+
458
+ // Year in "Week of Year"
459
+ // The length specifies the padding, but for two letters it also specifies the
460
+ // maximum length.
461
+ // yearInWeekofYear = date + DaysInAWeek - (dayOfWeek - firstDay) - minDays
462
+ value = new Date( date.getTime() );
463
+ value.setDate(
464
+ value.getDate() + 7 -
465
+ dateDayOfWeek( date, properties.firstDay ) -
466
+ properties.firstDay -
467
+ properties.minDays
468
+ );
469
+ value = value.getFullYear();
470
+ if ( length === 2 ) {
471
+ value = String( value );
472
+ value = +value.substr( value.length - 2 );
473
+ }
474
+ break;
475
+
476
+ // Quarter
477
+ case "Q":
478
+ case "q":
479
+ value = Math.ceil( ( date.getMonth() + 1 ) / 3 );
480
+ if ( length > 2 ) {
481
+ value = properties.quarters[ chr ][ length ][ value ];
482
+ }
483
+ break;
484
+
485
+ // Month
486
+ case "M":
487
+ case "L":
488
+ value = date.getMonth() + 1;
489
+ if ( length > 2 ) {
490
+ value = properties.months[ chr ][ length ][ value ];
491
+ }
492
+ break;
493
+
494
+ // Week
495
+ case "w":
496
+
497
+ // Week of Year.
498
+ // woy = ceil( ( doy + dow of 1/1 ) / 7 ) - minDaysStuff ? 1 : 0.
499
+ // TODO should pad on ww? Not documented, but I guess so.
500
+ value = dateDayOfWeek( dateStartOf( date, "year" ), properties.firstDay );
501
+ value = Math.ceil( ( dateDayOfYear( date ) + value ) / 7 ) -
502
+ ( 7 - value >= properties.minDays ? 0 : 1 );
503
+ break;
504
+
505
+ case "W":
506
+
507
+ // Week of Month.
508
+ // wom = ceil( ( dom + dow of `1/month` ) / 7 ) - minDaysStuff ? 1 : 0.
509
+ value = dateDayOfWeek( dateStartOf( date, "month" ), properties.firstDay );
510
+ value = Math.ceil( ( date.getDate() + value ) / 7 ) -
511
+ ( 7 - value >= properties.minDays ? 0 : 1 );
512
+ break;
513
+
514
+ // Day
515
+ case "d":
516
+ value = date.getDate();
517
+ break;
518
+
519
+ case "D":
520
+ value = dateDayOfYear( date ) + 1;
521
+ break;
522
+
523
+ case "F":
524
+
525
+ // Day of Week in month. eg. 2nd Wed in July.
526
+ value = Math.floor( date.getDate() / 7 ) + 1;
527
+ break;
528
+
529
+ // Week day
530
+ case "e":
531
+ case "c":
532
+ if ( length <= 2 ) {
533
+
534
+ // Range is [1-7] (deduced by example provided on documentation)
535
+ // TODO Should pad with zeros (not specified in the docs)?
536
+ value = dateDayOfWeek( date, properties.firstDay ) + 1;
537
+ break;
538
+ }
539
+
540
+ /* falls through */
541
+ case "E":
542
+ value = dateWeekDays[ date.getDay() ];
543
+ value = properties.days[ chr ][ length ][ value ];
544
+ break;
545
+
546
+ // Period (AM or PM)
547
+ case "a":
548
+ value = properties.dayPeriods[ date.getHours() < 12 ? "am" : "pm" ];
549
+ break;
550
+
551
+ // Hour
552
+ case "h": // 1-12
553
+ value = ( date.getHours() % 12 ) || 12;
554
+ break;
555
+
556
+ case "H": // 0-23
557
+ value = date.getHours();
558
+ break;
559
+
560
+ case "K": // 0-11
561
+ value = date.getHours() % 12;
562
+ break;
563
+
564
+ case "k": // 1-24
565
+ value = date.getHours() || 24;
566
+ break;
567
+
568
+ // Minute
569
+ case "m":
570
+ value = date.getMinutes();
571
+ break;
572
+
573
+ // Second
574
+ case "s":
575
+ value = date.getSeconds();
576
+ break;
577
+
578
+ case "S":
579
+ value = Math.round( date.getMilliseconds() * Math.pow( 10, length - 3 ) );
580
+ break;
581
+
582
+ case "A":
583
+ value = Math.round( dateMillisecondsInDay( date ) * Math.pow( 10, length - 3 ) );
584
+ break;
585
+
586
+ // Zone
587
+ case "z":
588
+ break;
589
+
590
+ case "v":
591
+
592
+ // v...vvv: "{shortRegion}", eg. "PT".
593
+ // vvvv: "{regionName} {Time}",
594
+ // e.g., "Pacific Time".
595
+ if ( properties.genericTzName ) {
596
+ value = properties.genericTzName;
597
+ break;
598
+ }
599
+
600
+ /* falls through */
601
+ case "V":
602
+
603
+ //VVVV: "{explarCity} {Time}", e.g., "Los Angeles Time"
604
+ if ( properties.timeZoneName ) {
605
+ value = properties.timeZoneName;
606
+ break;
607
+ }
608
+
609
+ if ( current === "v" ) {
610
+ length = 1;
611
+ }
612
+
613
+ /* falls through */
614
+ case "O":
615
+
616
+ // O: "{gmtFormat}+H;{gmtFormat}-H" or "{gmtZeroFormat}", eg. "GMT-8" or "GMT".
617
+ // OOOO: "{gmtFormat}{hourFormat}" or "{gmtZeroFormat}", eg. "GMT-08:00" or "GMT".
618
+ if ( date.getTimezoneOffset() === 0 ) {
619
+ value = properties.gmtZeroFormat;
620
+ } else {
621
+
622
+ // If O..OOO and timezone offset has non-zero minutes, show minutes.
623
+ if ( length < 4 ) {
624
+ aux = date.getTimezoneOffset();
625
+ aux = properties.hourFormat[ aux % 60 - aux % 1 === 0 ? 0 : 1 ];
626
+ } else {
627
+ aux = properties.hourFormat;
628
+ }
629
+
630
+ value = dateTimezoneHourFormat(
631
+ date,
632
+ aux,
633
+ timeSeparator,
634
+ numberFormatters
635
+ );
636
+ value = properties.gmtFormat.replace( /\{0\}/, value );
637
+ }
638
+ break;
639
+
640
+ case "X":
641
+
642
+ // Same as x*, except it uses "Z" for zero offset.
643
+ if ( date.getTimezoneOffset() === 0 ) {
644
+ value = "Z";
645
+ break;
646
+ }
647
+
648
+ /* falls through */
649
+ case "x":
650
+
651
+ // x: hourFormat("+HH[mm];-HH[mm]")
652
+ // xx: hourFormat("+HHmm;-HHmm")
653
+ // xxx: hourFormat("+HH:mm;-HH:mm")
654
+ // xxxx: hourFormat("+HHmm[ss];-HHmm[ss]")
655
+ // xxxxx: hourFormat("+HH:mm[:ss];-HH:mm[:ss]")
656
+ aux = date.getTimezoneOffset();
657
+
658
+ // If x and timezone offset has non-zero minutes, use xx (i.e., show minutes).
659
+ if ( length === 1 && aux % 60 - aux % 1 !== 0 ) {
660
+ length += 1;
661
+ }
662
+
663
+ // If (xxxx or xxxxx) and timezone offset has zero seconds, use xx or xxx
664
+ // respectively (i.e., don't show optional seconds).
665
+ if ( ( length === 4 || length === 5 ) && aux % 1 === 0 ) {
666
+ length -= 2;
667
+ }
668
+
669
+ value = [
670
+ "+HH;-HH",
671
+ "+HHmm;-HHmm",
672
+ "+HH:mm;-HH:mm",
673
+ "+HHmmss;-HHmmss",
674
+ "+HH:mm:ss;-HH:mm:ss"
675
+ ][ length - 1 ];
676
+
677
+ value = dateTimezoneHourFormat( date, value, ":" );
678
+ break;
679
+
680
+ // timeSeparator
681
+ case ":":
682
+ value = timeSeparator;
683
+ break;
684
+
685
+ // ' literals.
686
+ case "'":
687
+ value = removeLiteralQuotes( current );
688
+ break;
689
+
690
+ // Anything else is considered a literal, including [ ,:/.@#], chinese, japonese, and
691
+ // arabic characters.
692
+ default:
693
+ value = current;
694
+
695
+ }
696
+ if ( typeof value === "number" ) {
697
+ value = numberFormatters[ length ]( value );
698
+ }
699
+
700
+ dateField = dateFieldsMap[ chr ];
701
+ type = dateField ? dateField : "literal";
702
+
703
+ partsPush( parts, type, value );
704
+ });
705
+
706
+ return parts;
707
+
708
+ };
709
+
710
+
711
+
712
+
713
+ var dateFormatterFn = function( dateToPartsFormatter ) {
714
+ return function dateFormatter( value ) {
715
+ return partsJoin( dateToPartsFormatter( value ));
716
+ };
717
+ };
718
+
719
+
720
+
721
+
722
+ /**
723
+ * isLeapYear( year )
724
+ *
725
+ * @year [Number]
726
+ *
727
+ * Returns an indication whether the specified year is a leap year.
728
+ */
729
+ var dateIsLeapYear = function( year ) {
730
+ return new Date( year, 1, 29 ).getMonth() === 1;
731
+ };
732
+
733
+
734
+
735
+
736
+ /**
737
+ * lastDayOfMonth( date )
738
+ *
739
+ * @date [Date]
740
+ *
741
+ * Return the last day of the given date's month
742
+ */
743
+ var dateLastDayOfMonth = function( date ) {
744
+ return new Date( date.getFullYear(), date.getMonth() + 1, 0 ).getDate();
745
+ };
746
+
747
+
748
+
749
+
750
+ /**
751
+ * Differently from native date.setDate(), this function returns a date whose
752
+ * day remains inside the month boundaries. For example:
753
+ *
754
+ * setDate( FebDate, 31 ): a "Feb 28" date.
755
+ * setDate( SepDate, 31 ): a "Sep 30" date.
756
+ */
757
+ var dateSetDate = function( date, day ) {
758
+ var lastDay = new Date( date.getFullYear(), date.getMonth() + 1, 0 ).getDate();
759
+
760
+ date.setDate( day < 1 ? 1 : day < lastDay ? day : lastDay );
761
+ };
762
+
763
+
764
+
765
+
766
+ /**
767
+ * Differently from native date.setMonth(), this function adjusts date if
768
+ * needed, so final month is always the one set.
769
+ *
770
+ * setMonth( Jan31Date, 1 ): a "Feb 28" date.
771
+ * setDate( Jan31Date, 8 ): a "Sep 30" date.
772
+ */
773
+ var dateSetMonth = function( date, month ) {
774
+ var originalDate = date.getDate();
775
+
776
+ date.setDate( 1 );
777
+ date.setMonth( month );
778
+ dateSetDate( date, originalDate );
779
+ };
780
+
781
+
782
+
783
+
784
+ var outOfRange = function( value, low, high ) {
785
+ return value < low || value > high;
786
+ };
787
+
788
+
789
+
790
+
791
+ /**
792
+ * parse( value, tokens, properties )
793
+ *
794
+ * @value [String] string date.
795
+ *
796
+ * @tokens [Object] tokens returned by date/tokenizer.
797
+ *
798
+ * @properties [Object] output returned by date/tokenizer-properties.
799
+ *
800
+ * ref: http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
801
+ */
802
+ var dateParse = function( _value, tokens, properties ) {
803
+ var amPm, day, daysOfYear, month, era, hour, hour12, timezoneOffset, valid,
804
+ YEAR = 0,
805
+ MONTH = 1,
806
+ DAY = 2,
807
+ HOUR = 3,
808
+ MINUTE = 4,
809
+ SECOND = 5,
810
+ MILLISECONDS = 6,
811
+ date = new Date(),
812
+ truncateAt = [],
813
+ units = [ "year", "month", "day", "hour", "minute", "second", "milliseconds" ];
814
+
815
+ // Create globalize date with given timezone data.
816
+ if ( properties.timeZoneData ) {
817
+ date = new ZonedDateTime( date, properties.timeZoneData() );
818
+ }
819
+
820
+ if ( !tokens.length ) {
821
+ return null;
822
+ }
823
+
824
+ valid = tokens.every(function( token ) {
825
+ var century, chr, value, length;
826
+
827
+ if ( token.type === "literal" ) {
828
+
829
+ // continue
830
+ return true;
831
+ }
832
+
833
+ chr = token.type.charAt( 0 );
834
+ length = token.type.length;
835
+
836
+ if ( chr === "j" ) {
837
+
838
+ // Locale preferred hHKk.
839
+ // http://www.unicode.org/reports/tr35/tr35-dates.html#Time_Data
840
+ chr = properties.preferredTimeData;
841
+ }
842
+
843
+ switch ( chr ) {
844
+
845
+ // Era
846
+ case "G":
847
+ truncateAt.push( YEAR );
848
+ era = +token.value;
849
+ break;
850
+
851
+ // Year
852
+ case "y":
853
+ value = token.value;
854
+ if ( length === 2 ) {
855
+ if ( outOfRange( value, 0, 99 ) ) {
856
+ return false;
857
+ }
858
+
859
+ // mimic dojo/date/locale: choose century to apply, according to a sliding
860
+ // window of 80 years before and 20 years after present year.
861
+ century = Math.floor( date.getFullYear() / 100 ) * 100;
862
+ value += century;
863
+ if ( value > date.getFullYear() + 20 ) {
864
+ value -= 100;
865
+ }
866
+ }
867
+ date.setFullYear( value );
868
+ truncateAt.push( YEAR );
869
+ break;
870
+
871
+ case "Y": // Year in "Week of Year"
872
+ throw createErrorUnsupportedFeature({
873
+ feature: "year pattern `" + chr + "`"
874
+ });
875
+
876
+ // Quarter (skip)
877
+ case "Q":
878
+ case "q":
879
+ break;
880
+
881
+ // Month
882
+ case "M":
883
+ case "L":
884
+ if ( length <= 2 ) {
885
+ value = token.value;
886
+ } else {
887
+ value = +token.value;
888
+ }
889
+ if ( outOfRange( value, 1, 12 ) ) {
890
+ return false;
891
+ }
892
+
893
+ // Setting the month later so that we have the correct year and can determine
894
+ // the correct last day of February in case of leap year.
895
+ month = value;
896
+ truncateAt.push( MONTH );
897
+ break;
898
+
899
+ // Week (skip)
900
+ case "w": // Week of Year.
901
+ case "W": // Week of Month.
902
+ break;
903
+
904
+ // Day
905
+ case "d":
906
+ day = token.value;
907
+ truncateAt.push( DAY );
908
+ break;
909
+
910
+ case "D":
911
+ daysOfYear = token.value;
912
+ truncateAt.push( DAY );
913
+ break;
914
+
915
+ case "F":
916
+
917
+ // Day of Week in month. eg. 2nd Wed in July.
918
+ // Skip
919
+ break;
920
+
921
+ // Week day
922
+ case "e":
923
+ case "c":
924
+ case "E":
925
+
926
+ // Skip.
927
+ // value = arrayIndexOf( dateWeekDays, token.value );
928
+ break;
929
+
930
+ // Period (AM or PM)
931
+ case "a":
932
+ amPm = token.value;
933
+ break;
934
+
935
+ // Hour
936
+ case "h": // 1-12
937
+ value = token.value;
938
+ if ( outOfRange( value, 1, 12 ) ) {
939
+ return false;
940
+ }
941
+ hour = hour12 = true;
942
+ date.setHours( value === 12 ? 0 : value );
943
+ truncateAt.push( HOUR );
944
+ break;
945
+
946
+ case "K": // 0-11
947
+ value = token.value;
948
+ if ( outOfRange( value, 0, 11 ) ) {
949
+ return false;
950
+ }
951
+ hour = hour12 = true;
952
+ date.setHours( value );
953
+ truncateAt.push( HOUR );
954
+ break;
955
+
956
+ case "k": // 1-24
957
+ value = token.value;
958
+ if ( outOfRange( value, 1, 24 ) ) {
959
+ return false;
960
+ }
961
+ hour = true;
962
+ date.setHours( value === 24 ? 0 : value );
963
+ truncateAt.push( HOUR );
964
+ break;
965
+
966
+ case "H": // 0-23
967
+ value = token.value;
968
+ if ( outOfRange( value, 0, 23 ) ) {
969
+ return false;
970
+ }
971
+ hour = true;
972
+ date.setHours( value );
973
+ truncateAt.push( HOUR );
974
+ break;
975
+
976
+ // Minute
977
+ case "m":
978
+ value = token.value;
979
+ if ( outOfRange( value, 0, 59 ) ) {
980
+ return false;
981
+ }
982
+ date.setMinutes( value );
983
+ truncateAt.push( MINUTE );
984
+ break;
985
+
986
+ // Second
987
+ case "s":
988
+ value = token.value;
989
+ if ( outOfRange( value, 0, 59 ) ) {
990
+ return false;
991
+ }
992
+ date.setSeconds( value );
993
+ truncateAt.push( SECOND );
994
+ break;
995
+
996
+ case "A":
997
+ date.setHours( 0 );
998
+ date.setMinutes( 0 );
999
+ date.setSeconds( 0 );
1000
+
1001
+ /* falls through */
1002
+ case "S":
1003
+ value = Math.round( token.value * Math.pow( 10, 3 - length ) );
1004
+ date.setMilliseconds( value );
1005
+ truncateAt.push( MILLISECONDS );
1006
+ break;
1007
+
1008
+ // Zone
1009
+ case "z":
1010
+ case "Z":
1011
+ case "O":
1012
+ case "v":
1013
+ case "V":
1014
+ case "X":
1015
+ case "x":
1016
+ if ( typeof token.value === "number" ) {
1017
+ timezoneOffset = token.value;
1018
+ }
1019
+ break;
1020
+ }
1021
+
1022
+ return true;
1023
+ });
1024
+
1025
+ if ( !valid ) {
1026
+ return null;
1027
+ }
1028
+
1029
+ // 12-hour format needs AM or PM, 24-hour format doesn't, ie. return null
1030
+ // if amPm && !hour12 || !amPm && hour12.
1031
+ if ( hour && !( !amPm ^ hour12 ) ) {
1032
+ return null;
1033
+ }
1034
+
1035
+ if ( era === 0 ) {
1036
+
1037
+ // 1 BC = year 0
1038
+ date.setFullYear( date.getFullYear() * -1 + 1 );
1039
+ }
1040
+
1041
+ if ( month !== undefined ) {
1042
+ dateSetMonth( date, month - 1 );
1043
+ }
1044
+
1045
+ if ( day !== undefined ) {
1046
+ if ( outOfRange( day, 1, dateLastDayOfMonth( date ) ) ) {
1047
+ return null;
1048
+ }
1049
+ date.setDate( day );
1050
+ } else if ( daysOfYear !== undefined ) {
1051
+ if ( outOfRange( daysOfYear, 1, dateIsLeapYear( date.getFullYear() ) ? 366 : 365 ) ) {
1052
+ return null;
1053
+ }
1054
+ date.setMonth( 0 );
1055
+ date.setDate( daysOfYear );
1056
+ }
1057
+
1058
+ if ( hour12 && amPm === "pm" ) {
1059
+ date.setHours( date.getHours() + 12 );
1060
+ }
1061
+
1062
+ if ( timezoneOffset !== undefined ) {
1063
+ date.setMinutes( date.getMinutes() + timezoneOffset - date.getTimezoneOffset() );
1064
+ }
1065
+
1066
+ // Truncate date at the most precise unit defined. Eg.
1067
+ // If value is "12/31", and pattern is "MM/dd":
1068
+ // => new Date( <current Year>, 12, 31, 0, 0, 0, 0 );
1069
+ truncateAt = Math.max.apply( null, truncateAt );
1070
+ date = dateStartOf( date, units[ truncateAt ] );
1071
+
1072
+ // Get date back from globalize date.
1073
+ if ( date instanceof ZonedDateTime ) {
1074
+ date = date.toDate();
1075
+ }
1076
+
1077
+ return date;
1078
+ };
1079
+
1080
+
1081
+ /* eslint-disable no-unused-expressions */
1082
+
1083
+
1084
+
1085
+ /**
1086
+ * tokenizer( value, numberParser, properties )
1087
+ *
1088
+ * @value [String] string date.
1089
+ *
1090
+ * @numberParser [Function]
1091
+ *
1092
+ * @properties [Object] output returned by date/tokenizer-properties.
1093
+ *
1094
+ * Returns an Array of tokens, eg. value "5 o'clock PM", pattern "h 'o''clock' a":
1095
+ * [{
1096
+ * type: "h",
1097
+ * lexeme: "5"
1098
+ * }, {
1099
+ * type: "literal",
1100
+ * lexeme: " "
1101
+ * }, {
1102
+ * type: "literal",
1103
+ * lexeme: "o'clock"
1104
+ * }, {
1105
+ * type: "literal",
1106
+ * lexeme: " "
1107
+ * }, {
1108
+ * type: "a",
1109
+ * lexeme: "PM",
1110
+ * value: "pm"
1111
+ * }]
1112
+ *
1113
+ * OBS: lexeme's are always String and may return invalid ranges depending of the token type.
1114
+ * Eg. "99" for month number.
1115
+ *
1116
+ * Return an empty Array when not successfully parsed.
1117
+ */
1118
+ var dateTokenizer = function( value, numberParser, properties ) {
1119
+ var digitsRe, valid,
1120
+ tokens = [],
1121
+ widths = [ "abbreviated", "wide", "narrow" ];
1122
+
1123
+ digitsRe = properties.digitsRe;
1124
+ value = looseMatching( value );
1125
+
1126
+ valid = properties.pattern.match( datePatternRe ).every(function( current ) {
1127
+ var aux, chr, length, numeric, tokenRe,
1128
+ token = {};
1129
+
1130
+ function hourFormatParse( tokenRe, numberParser ) {
1131
+ var aux, isPositive,
1132
+ match = value.match( tokenRe );
1133
+ numberParser = numberParser || function( value ) {
1134
+ return +value;
1135
+ };
1136
+
1137
+ if ( !match ) {
1138
+ return false;
1139
+ }
1140
+
1141
+ isPositive = match[ 1 ];
1142
+
1143
+ // hourFormat containing H only, e.g., `+H;-H`
1144
+ if ( match.length < 6 ) {
1145
+ aux = isPositive ? 1 : 3;
1146
+ token.value = numberParser( match[ aux ] ) * 60;
1147
+
1148
+ // hourFormat containing H and m, e.g., `+HHmm;-HHmm`
1149
+ } else if ( match.length < 10 ) {
1150
+ aux = isPositive ? [ 1, 3 ] : [ 5, 7 ];
1151
+ token.value = numberParser( match[ aux[ 0 ] ] ) * 60 +
1152
+ numberParser( match[ aux[ 1 ] ] );
1153
+
1154
+ // hourFormat containing H, m, and s e.g., `+HHmmss;-HHmmss`
1155
+ } else {
1156
+ aux = isPositive ? [ 1, 3, 5 ] : [ 7, 9, 11 ];
1157
+ token.value = numberParser( match[ aux[ 0 ] ] ) * 60 +
1158
+ numberParser( match[ aux[ 1 ] ] ) +
1159
+ numberParser( match[ aux[ 2 ] ] ) / 60;
1160
+ }
1161
+
1162
+ if ( isPositive ) {
1163
+ token.value *= -1;
1164
+ }
1165
+
1166
+ return true;
1167
+ }
1168
+
1169
+ function oneDigitIfLengthOne() {
1170
+ if ( length === 1 ) {
1171
+
1172
+ // Unicode equivalent to /\d/
1173
+ numeric = true;
1174
+ return tokenRe = digitsRe;
1175
+ }
1176
+ }
1177
+
1178
+ function oneOrTwoDigitsIfLengthOne() {
1179
+ if ( length === 1 ) {
1180
+
1181
+ // Unicode equivalent to /\d\d?/
1182
+ numeric = true;
1183
+ return tokenRe = new RegExp( "^(" + digitsRe.source + "){1,2}" );
1184
+ }
1185
+ }
1186
+
1187
+ function oneOrTwoDigitsIfLengthOneOrTwo() {
1188
+ if ( length === 1 || length === 2 ) {
1189
+
1190
+ // Unicode equivalent to /\d\d?/
1191
+ numeric = true;
1192
+ return tokenRe = new RegExp( "^(" + digitsRe.source + "){1,2}" );
1193
+ }
1194
+ }
1195
+
1196
+ function twoDigitsIfLengthTwo() {
1197
+ if ( length === 2 ) {
1198
+
1199
+ // Unicode equivalent to /\d\d/
1200
+ numeric = true;
1201
+ return tokenRe = new RegExp( "^(" + digitsRe.source + "){2}" );
1202
+ }
1203
+ }
1204
+
1205
+ // Brute-force test every locale entry in an attempt to match the given value.
1206
+ // Return the first found one (and set token accordingly), or null.
1207
+ function lookup( path ) {
1208
+ var array = properties[ path.join( "/" ) ];
1209
+
1210
+ if ( !array ) {
1211
+ return null;
1212
+ }
1213
+
1214
+ // array of pairs [key, value] sorted by desc value length.
1215
+ array.some(function( item ) {
1216
+ var valueRe = item[ 1 ];
1217
+ if ( valueRe.test( value ) ) {
1218
+ token.value = item[ 0 ];
1219
+ tokenRe = item[ 1 ];
1220
+ return true;
1221
+ }
1222
+ });
1223
+ return null;
1224
+ }
1225
+
1226
+ token.type = current;
1227
+ chr = current.charAt( 0 );
1228
+ length = current.length;
1229
+
1230
+ if ( chr === "Z" ) {
1231
+
1232
+ // Z..ZZZ: same as "xxxx".
1233
+ if ( length < 4 ) {
1234
+ chr = "x";
1235
+ length = 4;
1236
+
1237
+ // ZZZZ: same as "OOOO".
1238
+ } else if ( length < 5 ) {
1239
+ chr = "O";
1240
+ length = 4;
1241
+
1242
+ // ZZZZZ: same as "XXXXX"
1243
+ } else {
1244
+ chr = "X";
1245
+ length = 5;
1246
+ }
1247
+ }
1248
+
1249
+ if ( chr === "z" ) {
1250
+ if ( properties.standardOrDaylightTzName ) {
1251
+ token.value = null;
1252
+ tokenRe = properties.standardOrDaylightTzName;
1253
+ }
1254
+ }
1255
+
1256
+ // v...vvv: "{shortRegion}", eg. "PT".
1257
+ // vvvv: "{regionName} {Time}" or "{regionName} {Time}",
1258
+ // e.g., "Pacific Time"
1259
+ // http://unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
1260
+ if ( chr === "v" ) {
1261
+ if ( properties.genericTzName ) {
1262
+ token.value = null;
1263
+ tokenRe = properties.genericTzName;
1264
+
1265
+ // Fall back to "V" format.
1266
+ } else {
1267
+ chr = "V";
1268
+ length = 4;
1269
+ }
1270
+ }
1271
+
1272
+ if ( chr === "V" && properties.timeZoneName ) {
1273
+ token.value = length === 2 ? properties.timeZoneName : null;
1274
+ tokenRe = properties.timeZoneNameRe;
1275
+ }
1276
+
1277
+ switch ( chr ) {
1278
+
1279
+ // Era
1280
+ case "G":
1281
+ lookup([
1282
+ "gregorian/eras",
1283
+ length <= 3 ? "eraAbbr" : ( length === 4 ? "eraNames" : "eraNarrow" )
1284
+ ]);
1285
+ break;
1286
+
1287
+ // Year
1288
+ case "y":
1289
+ case "Y":
1290
+ numeric = true;
1291
+
1292
+ // number l=1:+, l=2:{2}, l=3:{3,}, l=4:{4,}, ...
1293
+ if ( length === 1 ) {
1294
+
1295
+ // Unicode equivalent to /\d+/.
1296
+ tokenRe = new RegExp( "^(" + digitsRe.source + ")+" );
1297
+ } else if ( length === 2 ) {
1298
+
1299
+ // Lenient parsing: there's no year pattern to indicate non-zero-padded 2-digits
1300
+ // year, so parser accepts both zero-padded and non-zero-padded for `yy`.
1301
+ //
1302
+ // Unicode equivalent to /\d\d?/
1303
+ tokenRe = new RegExp( "^(" + digitsRe.source + "){1,2}" );
1304
+ } else {
1305
+
1306
+ // Unicode equivalent to /\d{length,}/
1307
+ tokenRe = new RegExp( "^(" + digitsRe.source + "){" + length + ",}" );
1308
+ }
1309
+ break;
1310
+
1311
+ // Quarter
1312
+ case "Q":
1313
+ case "q":
1314
+
1315
+ // number l=1:{1}, l=2:{2}.
1316
+ // lookup l=3...
1317
+ oneDigitIfLengthOne() || twoDigitsIfLengthTwo() ||
1318
+ lookup([
1319
+ "gregorian/quarters",
1320
+ chr === "Q" ? "format" : "stand-alone",
1321
+ widths[ length - 3 ]
1322
+ ]);
1323
+ break;
1324
+
1325
+ // Month
1326
+ case "M":
1327
+ case "L":
1328
+
1329
+ // number l=1:{1,2}, l=2:{2}.
1330
+ // lookup l=3...
1331
+ //
1332
+ // Lenient parsing: skeleton "yMd" (i.e., one M) may include MM for the pattern,
1333
+ // therefore parser accepts both zero-padded and non-zero-padded for M and MM.
1334
+ // Similar for L.
1335
+ oneOrTwoDigitsIfLengthOneOrTwo() || lookup([
1336
+ "gregorian/months",
1337
+ chr === "M" ? "format" : "stand-alone",
1338
+ widths[ length - 3 ]
1339
+ ]);
1340
+ break;
1341
+
1342
+ // Day
1343
+ case "D":
1344
+
1345
+ // number {l,3}.
1346
+ if ( length <= 3 ) {
1347
+
1348
+ // Equivalent to /\d{length,3}/
1349
+ numeric = true;
1350
+ tokenRe = new RegExp( "^(" + digitsRe.source + "){" + length + ",3}" );
1351
+ }
1352
+ break;
1353
+
1354
+ case "W":
1355
+ case "F":
1356
+
1357
+ // number l=1:{1}.
1358
+ oneDigitIfLengthOne();
1359
+ break;
1360
+
1361
+ // Week day
1362
+ case "e":
1363
+ case "c":
1364
+
1365
+ // number l=1:{1}, l=2:{2}.
1366
+ // lookup for length >=3.
1367
+ if ( length <= 2 ) {
1368
+ oneDigitIfLengthOne() || twoDigitsIfLengthTwo();
1369
+ break;
1370
+ }
1371
+
1372
+ /* falls through */
1373
+ case "E":
1374
+ if ( length === 6 ) {
1375
+
1376
+ // Note: if short day names are not explicitly specified, abbreviated day
1377
+ // names are used instead http://www.unicode.org/reports/tr35/tr35-dates.html#months_days_quarters_eras
1378
+ lookup([
1379
+ "gregorian/days",
1380
+ [ chr === "c" ? "stand-alone" : "format" ],
1381
+ "short"
1382
+ ]) || lookup([
1383
+ "gregorian/days",
1384
+ [ chr === "c" ? "stand-alone" : "format" ],
1385
+ "abbreviated"
1386
+ ]);
1387
+ } else {
1388
+ lookup([
1389
+ "gregorian/days",
1390
+ [ chr === "c" ? "stand-alone" : "format" ],
1391
+ widths[ length < 3 ? 0 : length - 3 ]
1392
+ ]);
1393
+ }
1394
+ break;
1395
+
1396
+ // Period (AM or PM)
1397
+ case "a":
1398
+ lookup([
1399
+ "gregorian/dayPeriods/format/wide"
1400
+ ]);
1401
+ break;
1402
+
1403
+ // Week
1404
+ case "w":
1405
+
1406
+ // number l1:{1,2}, l2:{2}.
1407
+ oneOrTwoDigitsIfLengthOne() || twoDigitsIfLengthTwo();
1408
+ break;
1409
+
1410
+ // Day, Hour, Minute, or Second
1411
+ case "d":
1412
+ case "h":
1413
+ case "H":
1414
+ case "K":
1415
+ case "k":
1416
+ case "j":
1417
+ case "m":
1418
+ case "s":
1419
+
1420
+ // number l1:{1,2}, l2:{2}.
1421
+ //
1422
+ // Lenient parsing:
1423
+ // - skeleton "hms" (i.e., one m) always includes mm for the pattern, i.e., it's
1424
+ // impossible to use a different skeleton to parse non-zero-padded minutes,
1425
+ // therefore parser accepts both zero-padded and non-zero-padded for m. Similar
1426
+ // for seconds s.
1427
+ // - skeleton "hms" (i.e., one h) may include h or hh for the pattern, i.e., it's
1428
+ // impossible to use a different skeleton to parser non-zero-padded hours for some
1429
+ // locales, therefore parser accepts both zero-padded and non-zero-padded for h.
1430
+ // Similar for d (in skeleton yMd).
1431
+ oneOrTwoDigitsIfLengthOneOrTwo();
1432
+ break;
1433
+
1434
+ case "S":
1435
+
1436
+ // number {l}.
1437
+
1438
+ // Unicode equivalent to /\d{length}/
1439
+ numeric = true;
1440
+ tokenRe = new RegExp( "^(" + digitsRe.source + "){" + length + "}" );
1441
+ break;
1442
+
1443
+ case "A":
1444
+
1445
+ // number {l+5}.
1446
+
1447
+ // Unicode equivalent to /\d{length+5}/
1448
+ numeric = true;
1449
+ tokenRe = new RegExp( "^(" + digitsRe.source + "){" + ( length + 5 ) + "}" );
1450
+ break;
1451
+
1452
+ // Zone
1453
+ case "v":
1454
+ case "V":
1455
+ case "z":
1456
+ if ( tokenRe && tokenRe.test( value ) ) {
1457
+ break;
1458
+ }
1459
+ if ( chr === "V" && length === 2 ) {
1460
+ break;
1461
+ }
1462
+
1463
+ /* falls through */
1464
+ case "O":
1465
+
1466
+ // O: "{gmtFormat}+H;{gmtFormat}-H" or "{gmtZeroFormat}", eg. "GMT-8" or "GMT".
1467
+ // OOOO: "{gmtFormat}{hourFormat}" or "{gmtZeroFormat}", eg. "GMT-08:00" or "GMT".
1468
+ if ( value === properties[ "timeZoneNames/gmtZeroFormat" ] ) {
1469
+ token.value = 0;
1470
+ tokenRe = properties[ "timeZoneNames/gmtZeroFormatRe" ];
1471
+ } else {
1472
+ aux = properties[ "timeZoneNames/hourFormat" ].some(function( hourFormatRe ) {
1473
+ if ( hourFormatParse( hourFormatRe, numberParser ) ) {
1474
+ tokenRe = hourFormatRe;
1475
+ return true;
1476
+ }
1477
+ });
1478
+ if ( !aux ) {
1479
+ return null;
1480
+ }
1481
+ }
1482
+ break;
1483
+
1484
+ case "X":
1485
+
1486
+ // Same as x*, except it uses "Z" for zero offset.
1487
+ if ( value === "Z" ) {
1488
+ token.value = 0;
1489
+ tokenRe = /^Z/;
1490
+ break;
1491
+ }
1492
+
1493
+ /* falls through */
1494
+ case "x":
1495
+
1496
+ // x: hourFormat("+HH[mm];-HH[mm]")
1497
+ // xx: hourFormat("+HHmm;-HHmm")
1498
+ // xxx: hourFormat("+HH:mm;-HH:mm")
1499
+ // xxxx: hourFormat("+HHmm[ss];-HHmm[ss]")
1500
+ // xxxxx: hourFormat("+HH:mm[:ss];-HH:mm[:ss]")
1501
+ aux = properties.x.some(function( hourFormatRe ) {
1502
+ if ( hourFormatParse( hourFormatRe ) ) {
1503
+ tokenRe = hourFormatRe;
1504
+ return true;
1505
+ }
1506
+ });
1507
+ if ( !aux ) {
1508
+ return null;
1509
+ }
1510
+ break;
1511
+
1512
+ case "'":
1513
+ token.type = "literal";
1514
+ tokenRe = new RegExp( "^" + regexpEscape( removeLiteralQuotes( current ) ) );
1515
+ break;
1516
+
1517
+ default:
1518
+ token.type = "literal";
1519
+ tokenRe = new RegExp( "^" + regexpEscape( current ) );
1520
+ }
1521
+
1522
+ if ( !tokenRe ) {
1523
+ return false;
1524
+ }
1525
+
1526
+ // Get lexeme and consume it.
1527
+ value = value.replace( tokenRe, function( lexeme ) {
1528
+ token.lexeme = lexeme;
1529
+ if ( numeric ) {
1530
+ token.value = numberParser( lexeme );
1531
+ }
1532
+ return "";
1533
+ });
1534
+
1535
+ if ( !token.lexeme ) {
1536
+ return false;
1537
+ }
1538
+
1539
+ if ( numeric && isNaN( token.value ) ) {
1540
+ return false;
1541
+ }
1542
+
1543
+ tokens.push( token );
1544
+ return true;
1545
+ });
1546
+
1547
+ if ( value !== "" ) {
1548
+ valid = false;
1549
+ }
1550
+
1551
+ return valid ? tokens : [];
1552
+ };
1553
+
1554
+
1555
+
1556
+
1557
+ var dateParserFn = function( numberParser, parseProperties, tokenizerProperties ) {
1558
+ return function dateParser( value ) {
1559
+ var tokens;
1560
+
1561
+ validateParameterPresence( value, "value" );
1562
+ validateParameterTypeString( value, "value" );
1563
+
1564
+ tokens = dateTokenizer( value, numberParser, tokenizerProperties );
1565
+ return dateParse( value, tokens, parseProperties ) || null;
1566
+ };
1567
+ };
1568
+
1569
+
1570
+
1571
+
1572
+ var dateToPartsFormatterFn = function( numberFormatters, properties ) {
1573
+ return function dateToPartsFormatter( value ) {
1574
+ validateParameterPresence( value, "value" );
1575
+ validateParameterTypeDate( value, "value" );
1576
+
1577
+ return dateFormat( value, numberFormatters, properties );
1578
+ };
1579
+
1580
+ };
1581
+
1582
+
1583
+
1584
+
1585
+ Globalize._dateFormat = dateFormat;
1586
+ Globalize._dateFormatterFn = dateFormatterFn;
1587
+ Globalize._dateParser = dateParse;
1588
+ Globalize._dateParserFn = dateParserFn;
1589
+ Globalize._dateTokenizer = dateTokenizer;
1590
+ Globalize._dateToPartsFormatterFn = dateToPartsFormatterFn;
1591
+ Globalize._validateParameterTypeDate = validateParameterTypeDate;
1592
+
1593
+ function optionsHasStyle( options ) {
1594
+ return options.skeleton !== undefined ||
1595
+ options.date !== undefined ||
1596
+ options.time !== undefined ||
1597
+ options.datetime !== undefined ||
1598
+ options.raw !== undefined;
1599
+ }
1600
+
1601
+ Globalize.dateFormatter =
1602
+ Globalize.prototype.dateFormatter = function( options ) {
1603
+ options = options || {};
1604
+ if ( !optionsHasStyle( options ) ) {
1605
+ options.skeleton = "yMd";
1606
+ }
1607
+ return Globalize[ runtimeKey( "dateFormatter", this._locale, [ options ] ) ];
1608
+ };
1609
+
1610
+ Globalize.dateToPartsFormatter =
1611
+ Globalize.prototype.dateToPartsFormatter = function( options ) {
1612
+ options = options || {};
1613
+ if ( !optionsHasStyle( options ) ) {
1614
+ options.skeleton = "yMd";
1615
+ }
1616
+ return Globalize[ runtimeKey( "dateToPartsFormatter", this._locale, [ options ] ) ];
1617
+ };
1618
+
1619
+ Globalize.dateParser =
1620
+ Globalize.prototype.dateParser = function( options ) {
1621
+ options = options || {};
1622
+ if ( !optionsHasStyle( options ) ) {
1623
+ options.skeleton = "yMd";
1624
+ }
1625
+ return Globalize[ runtimeKey( "dateParser", this._locale, [ options ] ) ];
1626
+ };
1627
+
1628
+ Globalize.formatDate =
1629
+ Globalize.prototype.formatDate = function( value, options ) {
1630
+ validateParameterPresence( value, "value" );
1631
+ validateParameterTypeDate( value, "value" );
1632
+
1633
+ return this.dateFormatter( options )( value );
1634
+ };
1635
+
1636
+ Globalize.formatDateToParts =
1637
+ Globalize.prototype.formatDateToParts = function( value, options ) {
1638
+ validateParameterPresence( value, "value" );
1639
+ validateParameterTypeDate( value, "value" );
1640
+
1641
+ return this.dateToPartsFormatter( options )( value );
1642
+ };
1643
+
1644
+ Globalize.parseDate =
1645
+ Globalize.prototype.parseDate = function( value, options ) {
1646
+ validateParameterPresence( value, "value" );
1647
+ validateParameterTypeString( value, "value" );
1648
+
1649
+ return this.dateParser( options )( value );
1650
+ };
1651
+
1652
+ return Globalize;
1653
+
1654
+
1655
+
1656
+
1657
+ }));