Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/i18n/dateintervalformat.js
2868 views
1
// Copyright 2017 The Closure Library Authors. All Rights Reserved.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
// http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS-IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
/**
16
* @fileoverview DateIntervalFormat provides methods to format a date interval
17
* into a string in a user friendly way and a locale sensitive manner.
18
*
19
* Similar to the ICU4J class com/ibm/icu/text/DateIntervalFormat:
20
* http://icu-project.org/apiref/icu4j/com/ibm/icu/text/DateIntervalFormat.html
21
*
22
* Example usage:
23
* var DateIntervalFormat = goog.require('goog.i18n.DateIntervalFormat');
24
* var DateRange = goog.require('goog.date.DateRange');
25
* var DateTime = goog.require('goog.date.DateTime');
26
* var DateTimeFormat = goog.require('goog.i18n.DateTimeFormat');
27
* var GDate = goog.require('goog.date.Date');
28
* var Interval = goog.require('goog.date.Interval');
29
*
30
* // Formatter.
31
* var dtIntFmt = new DateIntervalFormat(DateTimeFormat.Format.MEDIUM_DATE);
32
*
33
* // Format a date range.
34
* var dt1 = new GDate(2016, 8, 23);
35
* var dt2 = new GDate(2016, 8, 24);
36
* var dtRng = new DateRange(dt1, dt2);
37
* dtIntFmt.formatRange(dtRng); // --> 'Sep 23 – 24, 2016'
38
*
39
* // Format two dates.
40
* var dt3 = new DateTime(2016, 8, 23, 14, 53, 0);
41
* var dt4 = new DateTime(2016, 8, 23, 14, 54, 0);
42
* dtIntFmt.format(dt3, dt4); // --> 'Sep 23, 2016'
43
*
44
* // Format a date and an interval.
45
* var dt5 = new DateTime(2016, 8, 23, 14, 53, 0);
46
* var itv = new Interval(0, 1); // One month.
47
* dtIntFmt.format(dt5, itv); // --> 'Sep 23 – Oct 23, 2016'
48
*
49
*/
50
51
goog.module('goog.i18n.DateIntervalFormat');
52
53
var DateLike = goog.require('goog.date.DateLike');
54
var DateRange = goog.require('goog.date.DateRange');
55
var DateTime = goog.require('goog.date.DateTime');
56
var DateTimeFormat = goog.require('goog.i18n.DateTimeFormat');
57
var DateTimeSymbols = goog.require('goog.i18n.DateTimeSymbols');
58
var DateTimeSymbolsType = goog.require('goog.i18n.DateTimeSymbolsType');
59
var Interval = goog.require('goog.date.Interval');
60
var TimeZone = goog.require('goog.i18n.TimeZone');
61
var array = goog.require('goog.array');
62
var asserts = goog.require('goog.asserts');
63
var dateIntervalSymbols = goog.require('goog.i18n.dateIntervalSymbols');
64
var object = goog.require('goog.object');
65
66
/**
67
* Constructs a DateIntervalFormat object based on the current locale.
68
*
69
* @param {number|!dateIntervalSymbols.DateIntervalPatternMap} pattern Pattern
70
* specification or pattern object.
71
* @param {!dateIntervalSymbols.DateIntervalSymbols=} opt_dateIntervalSymbols
72
* Optional DateIntervalSymbols to use for this instance rather than the
73
* global symbols.
74
* @param {!DateTimeSymbolsType=} opt_dateTimeSymbols Optional DateTimeSymbols
75
* to use for this instance rather than the global symbols.
76
* @constructor
77
* @struct
78
* @final
79
*/
80
var DateIntervalFormat = function(
81
pattern, opt_dateIntervalSymbols, opt_dateTimeSymbols) {
82
asserts.assert(goog.isDef(pattern), 'Pattern must be defined.');
83
asserts.assert(
84
goog.isDef(opt_dateIntervalSymbols) ||
85
goog.isDef(dateIntervalSymbols.getDateIntervalSymbols()),
86
'goog.i18n.DateIntervalSymbols or explicit symbols must be defined');
87
asserts.assert(
88
goog.isDef(opt_dateTimeSymbols) || goog.isDef(DateTimeSymbols),
89
'goog.i18n.DateTimeSymbols or explicit symbols must be defined');
90
91
/**
92
* DateIntervalSymbols object that contains locale data required by the
93
* formatter.
94
* @private @const {!dateIntervalSymbols.DateIntervalSymbols}
95
*/
96
this.dateIntervalSymbols_ =
97
opt_dateIntervalSymbols || dateIntervalSymbols.getDateIntervalSymbols();
98
99
/**
100
* DateTimeSymbols object that contain locale data required by the formatter.
101
* @private @const {!DateTimeSymbolsType}
102
*/
103
this.dateTimeSymbols_ = opt_dateTimeSymbols || DateTimeSymbols;
104
105
/**
106
* Date interval pattern to use.
107
* @private @const {!dateIntervalSymbols.DateIntervalPatternMap}
108
*/
109
this.intervalPattern_ = this.getIntervalPattern_(pattern);
110
111
/**
112
* Keys of the available date interval patterns. Used to lookup the key that
113
* contains a specific pattern letter (e.g. for ['Myd', 'hms'], the key that
114
* contains 'y' is 'Myd').
115
* @private @const {!Array<string>}
116
*/
117
this.intervalPatternKeys_ = object.getKeys(this.intervalPattern_);
118
119
// Remove the default pattern's key ('_') from intervalPatternKeys_. Is not
120
// necesary when looking up for a key: when no key is found it will always
121
// default to the default pattern.
122
array.remove(this.intervalPatternKeys_, DEFAULT_PATTERN_KEY_);
123
124
/**
125
* Default fallback pattern to use.
126
* @private @const {string}
127
*/
128
this.fallbackPattern_ =
129
this.dateIntervalSymbols_.FALLBACK || DEFAULT_FALLBACK_PATTERN_;
130
131
// Determine which date should be used with each part of the interval
132
// pattern.
133
var indexOfFirstDate = this.fallbackPattern_.indexOf(FIRST_DATE_PLACEHOLDER_);
134
var indexOfSecondDate =
135
this.fallbackPattern_.indexOf(SECOND_DATE_PLACEHOLDER_);
136
if (indexOfFirstDate < 0 || indexOfSecondDate < 0) {
137
throw new Error('Malformed fallback interval pattern');
138
}
139
140
/**
141
* True if the first date provided should be formatted with the first pattern
142
* of the interval pattern.
143
* @private @const {boolean}
144
*/
145
this.useFirstDateOnFirstPattern_ = indexOfFirstDate <= indexOfSecondDate;
146
147
/**
148
* Map that stores a Formatter_ object per calendar field. Formatters will be
149
* instanced on demand and stored on this map until required again.
150
* @private @const {!Object<string, !Formatter_>}
151
*/
152
this.formatterMap_ = {};
153
};
154
155
/**
156
* Default fallback interval pattern.
157
* @private @const {string}
158
*/
159
var DEFAULT_FALLBACK_PATTERN_ = '{0} – {1}';
160
161
/**
162
* Interval pattern placeholder for the first date.
163
* @private @const {string}
164
*/
165
var FIRST_DATE_PLACEHOLDER_ = '{0}';
166
167
/**
168
* Interval pattern placeholder for the second date.
169
* @private @const {string}
170
*/
171
var SECOND_DATE_PLACEHOLDER_ = '{1}';
172
173
/**
174
* Key used by the default datetime pattern.
175
* @private @const {string}
176
*/
177
var DEFAULT_PATTERN_KEY_ = '_';
178
179
/**
180
* Gregorian calendar Eras.
181
* @private @enum {number}
182
*/
183
var Era_ = {BC: 0, AD: 1};
184
185
/**
186
* Am Pm markers.
187
* @private @enum {number}
188
*/
189
var AmPm_ = {AM: 0, PM: 1};
190
191
/**
192
* String of all pattern letters representing the relevant calendar fields.
193
* Sorted according to the length of the datetime unit they represent.
194
* @private @const {string}
195
*/
196
var RELEVANT_CALENDAR_FIELDS_ = 'GyMdahms';
197
198
/**
199
* Regex that matches all possible pattern letters.
200
* @private @const {!RegExp}
201
*/
202
var ALL_PATTERN_LETTERS_ = /[a-zA-Z]/;
203
204
/**
205
* Returns the interval pattern from a pattern specification or from the pattern
206
* object.
207
* @param {number|!dateIntervalSymbols.DateIntervalPatternMap} pattern Pattern
208
* specification or pattern object.
209
* @return {!dateIntervalSymbols.DateIntervalPatternMap}
210
* @private
211
*/
212
DateIntervalFormat.prototype.getIntervalPattern_ = function(pattern) {
213
if (goog.isNumber(pattern)) {
214
switch (pattern) {
215
case DateTimeFormat.Format.FULL_DATE:
216
return this.dateIntervalSymbols_.FULL_DATE;
217
case DateTimeFormat.Format.LONG_DATE:
218
return this.dateIntervalSymbols_.LONG_DATE;
219
case DateTimeFormat.Format.MEDIUM_DATE:
220
return this.dateIntervalSymbols_.MEDIUM_DATE;
221
case DateTimeFormat.Format.SHORT_DATE:
222
return this.dateIntervalSymbols_.SHORT_DATE;
223
case DateTimeFormat.Format.FULL_TIME:
224
return this.dateIntervalSymbols_.FULL_TIME;
225
case DateTimeFormat.Format.LONG_TIME:
226
return this.dateIntervalSymbols_.LONG_TIME;
227
case DateTimeFormat.Format.MEDIUM_TIME:
228
return this.dateIntervalSymbols_.MEDIUM_TIME;
229
case DateTimeFormat.Format.SHORT_TIME:
230
return this.dateIntervalSymbols_.SHORT_TIME;
231
case DateTimeFormat.Format.FULL_DATETIME:
232
return this.dateIntervalSymbols_.FULL_DATETIME;
233
case DateTimeFormat.Format.LONG_DATETIME:
234
return this.dateIntervalSymbols_.LONG_DATETIME;
235
case DateTimeFormat.Format.MEDIUM_DATETIME:
236
return this.dateIntervalSymbols_.MEDIUM_DATETIME;
237
case DateTimeFormat.Format.SHORT_DATETIME:
238
return this.dateIntervalSymbols_.SHORT_DATETIME;
239
default:
240
return this.dateIntervalSymbols_.MEDIUM_DATETIME;
241
}
242
} else {
243
return pattern;
244
}
245
};
246
247
/**
248
* Formats the given date or date interval objects according to the present
249
* pattern and current locale.
250
*
251
* Parameter combinations:
252
* * StartDate: {@link goog.date.DateLike}, EndDate: {@link goog.date.DateLike}
253
* * StartDate: {@link goog.date.DateLike}, Interval: {@link goog.date.Interval}
254
*
255
* @param {!DateLike} startDate Start date of the date range.
256
* @param {!DateLike|!Interval} endDate End date of the date range or an
257
* interval object.
258
* @param {!TimeZone=} opt_timeZone Timezone to be used in the target
259
* representation.
260
* @return {string} Formatted date interval.
261
*/
262
DateIntervalFormat.prototype.format = function(
263
startDate, endDate, opt_timeZone) {
264
asserts.assert(
265
startDate != null,
266
'The startDate parameter should be defined and not-null.');
267
asserts.assert(
268
endDate != null, 'The endDate parameter should be defined and not-null.');
269
270
// Convert input to DateLike.
271
var endDt;
272
if (goog.isDateLike(endDate)) {
273
endDt = /** @type {!DateLike} */ (endDate);
274
} else {
275
asserts.assertInstanceof(
276
endDate, Interval,
277
'endDate parameter should be a goog.date.DateLike or ' +
278
'goog.date.Interval');
279
endDt = new DateTime(startDate);
280
endDt.add(endDate);
281
}
282
283
// Obtain the largest different calendar field between the two dates.
284
var largestDifferentCalendarField =
285
DateIntervalFormat.getLargestDifferentCalendarField_(
286
startDate, endDt, opt_timeZone);
287
288
// Get the Formatter_ required to format the specified calendar field and use
289
// it to format the dates.
290
var formatter =
291
this.getFormatterForCalendarField_(largestDifferentCalendarField);
292
return formatter.format(
293
startDate, endDt, largestDifferentCalendarField, opt_timeZone);
294
};
295
296
/**
297
* Formats the given date range object according to the present pattern and
298
* current locale.
299
*
300
* @param {!DateRange} dateRange
301
* @param {!TimeZone=} opt_timeZone Timezone to be used in the target
302
* representation.
303
* @return {string} Formatted date interval.
304
*/
305
DateIntervalFormat.prototype.formatRange = function(dateRange, opt_timeZone) {
306
asserts.assert(
307
dateRange != null,
308
'The dateRange parameter should be defined and non-null.');
309
var startDate = dateRange.getStartDate();
310
var endDate = dateRange.getEndDate();
311
if (startDate == null) {
312
throw Error('The dateRange\'s startDate should be defined and non-null.');
313
}
314
if (endDate == null) {
315
throw Error('The dateRange\'s endDate should be defined and non-null.');
316
}
317
return this.format(startDate, endDate, opt_timeZone);
318
};
319
320
/**
321
* Returns the Formatter_ to be used to format two dates for the given calendar
322
* field.
323
* @param {string} calendarField Pattern letter representing the calendar field.
324
* @return {!Formatter_}
325
* @private
326
*/
327
DateIntervalFormat.prototype.getFormatterForCalendarField_ = function(
328
calendarField) {
329
if (calendarField != '') {
330
for (var i = 0; i < this.intervalPatternKeys_.length; i++) {
331
if (this.intervalPatternKeys_[i].indexOf(calendarField) >= 0) {
332
return this.getOrCreateFormatterForKey_(this.intervalPatternKeys_[i]);
333
}
334
}
335
}
336
return this.getOrCreateFormatterForKey_(DEFAULT_PATTERN_KEY_);
337
};
338
339
/**
340
* Returns and creates (if necessary) a formatter for the specified key.
341
* @param {string} key
342
* @return {!Formatter_}
343
* @private
344
*/
345
DateIntervalFormat.prototype.getOrCreateFormatterForKey_ = function(key) {
346
var fmt = this;
347
return object.setWithReturnValueIfNotSet(this.formatterMap_, key, function() {
348
var patternParts =
349
DateIntervalFormat.divideIntervalPattern_(fmt.intervalPattern_[key]);
350
if (patternParts === null) {
351
return new DateTimeFormatter_(
352
fmt.intervalPattern_[key], fmt.fallbackPattern_,
353
fmt.dateTimeSymbols_);
354
}
355
return new IntervalFormatter_(
356
patternParts.firstPart, patternParts.secondPart, fmt.dateTimeSymbols_,
357
fmt.useFirstDateOnFirstPattern_);
358
});
359
};
360
361
/**
362
* Divides the interval pattern string into its two parts. Will return null if
363
* the pattern can't be divided (e.g. it's a datetime pattern).
364
* @param {string} intervalPattern
365
* @return {?{firstPart:string, secondPart:string}} Record containing the two
366
* parts of the interval pattern. Null if the pattern can't be divided.
367
* @private
368
*/
369
DateIntervalFormat.divideIntervalPattern_ = function(intervalPattern) {
370
var foundKeys = {};
371
var patternParts = null;
372
// Iterate over the pattern until a repeated calendar field is found.
373
DateIntervalFormat.executeForEveryCalendarField_(
374
intervalPattern, function(char, index) {
375
if (object.containsKey(foundKeys, char)) {
376
patternParts = {
377
firstPart: intervalPattern.substring(0, index),
378
secondPart: intervalPattern.substring(index)
379
};
380
return false;
381
}
382
object.set(foundKeys, char, true);
383
return true;
384
});
385
386
return patternParts;
387
};
388
389
/**
390
* Iterates over a pattern string and executes a function for every
391
* calendar field. The function will be executed once, independent of the width
392
* of the calendar field (number of repeated pattern letters). It will ignore
393
* all literal text (enclosed by quotes).
394
*
395
* For example, on: "H 'h' mm – H 'h' mm" it will call the function for:
396
* H (pos:0), m (pos:6), H (pos:11), m (pos:17).
397
*
398
* @param {string} pattern
399
* @param {function(string, number):boolean} func Function which accepts as
400
* parameters the current calendar field and the index of its first pattern
401
* letter; and returns a boolean which indicates if the iteration should
402
* continue.
403
* @private
404
*/
405
DateIntervalFormat.executeForEveryCalendarField_ = function(pattern, func) {
406
var inQuote = false;
407
var previousChar = '';
408
for (var i = 0; i < pattern.length; i++) {
409
var char = pattern.charAt(i);
410
if (inQuote) {
411
if (char == '\'') {
412
if (i + 1 < pattern.length && pattern.charAt(i + 1) == '\'') {
413
i++; // Literal quotation mark: ignore and advance.
414
} else {
415
inQuote = false;
416
}
417
}
418
} else {
419
if (char == '\'') {
420
inQuote = true;
421
} else if (char != previousChar && ALL_PATTERN_LETTERS_.test(char)) {
422
if (!func(char, i)) {
423
break;
424
}
425
}
426
}
427
previousChar = char;
428
}
429
};
430
431
/**
432
* Returns a pattern letter representing the largest different calendar field
433
* between the two dates. This is calculated using the timezone used in the
434
* target representation.
435
* @param {!DateLike} startDate Start date of the date range.
436
* @param {!DateLike} endDate End date of the date range.
437
* @param {!TimeZone=} opt_timeZone Timezone to be used in the target
438
* representation.
439
* @return {string} Pattern letter representing the largest different calendar
440
* field or an empty string if all relevant fields for these dates are equal.
441
* @private
442
*/
443
DateIntervalFormat.getLargestDifferentCalendarField_ = function(
444
startDate, endDate, opt_timeZone) {
445
// Before comparing them, dates have to be adjusted by the target timezone's
446
// offset.
447
var startDiff = 0;
448
var endDiff = 0;
449
if (opt_timeZone != null) {
450
startDiff =
451
(startDate.getTimezoneOffset() - opt_timeZone.getOffset(startDate)) *
452
60000;
453
endDiff =
454
(endDate.getTimezoneOffset() - opt_timeZone.getOffset(endDate)) * 60000;
455
}
456
var startDt = new Date(startDate.getTime() + startDiff);
457
var endDt = new Date(endDate.getTime() + endDiff);
458
459
if (DateIntervalFormat.getEra_(startDt) !=
460
DateIntervalFormat.getEra_(endDt)) {
461
return 'G';
462
} else if (startDt.getFullYear() != endDt.getFullYear()) {
463
return 'y';
464
} else if (startDt.getMonth() != endDt.getMonth()) {
465
return 'M';
466
} else if (startDt.getDate() != endDt.getDate()) {
467
return 'd';
468
} else if (
469
DateIntervalFormat.getAmPm_(startDt) !=
470
DateIntervalFormat.getAmPm_(endDt)) {
471
return 'a';
472
} else if (startDt.getHours() != endDt.getHours()) {
473
return 'h';
474
} else if (startDt.getMinutes() != endDt.getMinutes()) {
475
return 'm';
476
} else if (startDt.getSeconds() != endDt.getSeconds()) {
477
return 's';
478
}
479
return '';
480
};
481
482
/**
483
* Returns the Era of a given DateLike object.
484
* @param {!Date} date
485
* @return {number}
486
* @private
487
*/
488
DateIntervalFormat.getEra_ = function(date) {
489
return date.getFullYear() > 0 ? Era_.AD : Era_.BC;
490
};
491
492
/**
493
* Returns if the given date is in AM or PM.
494
* @param {!Date} date
495
* @return {number}
496
* @private
497
*/
498
DateIntervalFormat.getAmPm_ = function(date) {
499
var hours = date.getHours();
500
return (12 <= hours && hours < 24) ? AmPm_.PM : AmPm_.AM;
501
};
502
503
/**
504
* Returns true if the calendar field field1 is a larger or equal than field2.
505
* Assumes that both string parameters have just one character. Field1 has to
506
* be part of the relevant calendar fields set.
507
* @param {string} field1
508
* @param {string} field2
509
* @return {boolean}
510
* @private
511
*/
512
DateIntervalFormat.isCalendarFieldLargerOrEqualThan_ = function(
513
field1, field2) {
514
return RELEVANT_CALENDAR_FIELDS_.indexOf(field1) <=
515
RELEVANT_CALENDAR_FIELDS_.indexOf(field2);
516
};
517
518
/**
519
* Interface implemented by internal date interval formatters.
520
* @interface
521
* @private
522
*/
523
var Formatter_ = function() {};
524
525
/**
526
* Formats two dates with the two parts of the date interval and returns the
527
* formatted string.
528
* @param {!DateLike} firstDate
529
* @param {!DateLike} secondDate
530
* @param {string} largestDifferentCalendarField
531
* @param {!TimeZone=} opt_timeZone Target timezone in which to format the
532
* dates.
533
* @return {string} String with the formatted date interval.
534
*/
535
Formatter_.prototype.format = function(
536
firstDate, secondDate, largestDifferentCalendarField, opt_timeZone) {};
537
538
/**
539
* Constructs an IntervalFormatter_ object which implements the Formatter_
540
* interface.
541
*
542
* Internal object to construct and store a goog.i18n.DateTimeFormat for each
543
* part of the date interval pattern.
544
*
545
* @param {string} firstPattern First part of the date interval pattern.
546
* @param {string} secondPattern Second part of the date interval pattern.
547
* @param {!DateTimeSymbolsType} dateTimeSymbols Symbols to use with the
548
* datetime formatters.
549
* @param {boolean} useFirstDateOnFirstPattern Indicates if the first or the
550
* second date should be formatted with the first or second part of the date
551
* interval pattern.
552
* @constructor
553
* @implements {Formatter_}
554
* @private
555
*/
556
var IntervalFormatter_ = function(
557
firstPattern, secondPattern, dateTimeSymbols, useFirstDateOnFirstPattern) {
558
/**
559
* Formatter_ to format the first part of the date interval.
560
* @private {!DateTimeFormat}
561
*/
562
this.firstPartFormatter_ = new DateTimeFormat(firstPattern, dateTimeSymbols);
563
564
/**
565
* Formatter_ to format the second part of the date interval.
566
* @private {!DateTimeFormat}
567
*/
568
this.secondPartFormatter_ =
569
new DateTimeFormat(secondPattern, dateTimeSymbols);
570
571
/**
572
* Specifies if the first or the second date should be formatted by the
573
* formatter of the first or second part of the date interval.
574
* @private {boolean}
575
*/
576
this.useFirstDateOnFirstPattern_ = useFirstDateOnFirstPattern;
577
};
578
579
/** @override */
580
IntervalFormatter_.prototype.format = function(
581
firstDate, secondDate, largestDifferentCalendarField, opt_timeZone) {
582
if (this.useFirstDateOnFirstPattern_) {
583
return this.firstPartFormatter_.format(firstDate, opt_timeZone) +
584
this.secondPartFormatter_.format(secondDate, opt_timeZone);
585
} else {
586
return this.firstPartFormatter_.format(secondDate, opt_timeZone) +
587
this.secondPartFormatter_.format(firstDate, opt_timeZone);
588
}
589
};
590
591
/**
592
* Constructs a DateTimeFormatter_ object which implements the Formatter_
593
* interface.
594
*
595
* Internal object to construct and store a goog.i18n.DateTimeFormat for the
596
* a datetime pattern and formats dates using the fallback interval pattern
597
* (e.g. '{0} – {1}').
598
*
599
* @param {string} dateTimePattern Datetime pattern used to format the dates.
600
* @param {string} fallbackPattern Fallback interval pattern to be used with the
601
* datetime pattern.
602
* @param {!DateTimeSymbolsType} dateTimeSymbols Symbols to use with
603
* the datetime format.
604
* @constructor
605
* @implements {Formatter_}
606
* @private
607
*/
608
var DateTimeFormatter_ = function(
609
dateTimePattern, fallbackPattern, dateTimeSymbols) {
610
/**
611
* Date time pattern used to format the dates.
612
* @private {string}
613
*/
614
this.dateTimePattern_ = dateTimePattern;
615
616
/**
617
* Date time formatter used to format the dates.
618
* @private {!DateTimeFormat}
619
*/
620
this.dateTimeFormatter_ =
621
new DateTimeFormat(dateTimePattern, dateTimeSymbols);
622
623
/**
624
* Fallback interval pattern.
625
* @private {string}
626
*/
627
this.fallbackPattern_ = fallbackPattern;
628
};
629
630
/** @override */
631
DateTimeFormatter_.prototype.format = function(
632
firstDate, secondDate, largestDifferentCalendarField, opt_timeZone) {
633
// Check if the largest different calendar field between the two dates is
634
// larger or equal than any calendar field in the datetime pattern. If true,
635
// format the string using the datetime pattern and the fallback interval
636
// pattern.
637
var shouldFormatWithFallbackPattern = false;
638
if (largestDifferentCalendarField != '') {
639
DateIntervalFormat.executeForEveryCalendarField_(
640
this.dateTimePattern_, function(char, index) {
641
if (DateIntervalFormat.isCalendarFieldLargerOrEqualThan_(
642
largestDifferentCalendarField, char)) {
643
shouldFormatWithFallbackPattern = true;
644
return false;
645
}
646
return true;
647
});
648
}
649
650
if (shouldFormatWithFallbackPattern) {
651
return this.fallbackPattern_
652
.replace(
653
FIRST_DATE_PLACEHOLDER_,
654
this.dateTimeFormatter_.format(firstDate, opt_timeZone))
655
.replace(
656
SECOND_DATE_PLACEHOLDER_,
657
this.dateTimeFormatter_.format(secondDate, opt_timeZone));
658
}
659
// If not, format the first date using the datetime pattern.
660
return this.dateTimeFormatter_.format(firstDate, opt_timeZone);
661
};
662
663
exports = DateIntervalFormat;
664
665