123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663 |
- // Copyright 2017 The Closure Library Authors. All Rights Reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS-IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- /**
- * @fileoverview DateIntervalFormat provides methods to format a date interval
- * into a string in a user friendly way and a locale sensitive manner.
- *
- * Similar to the ICU4J class com/ibm/icu/text/DateIntervalFormat:
- * http://icu-project.org/apiref/icu4j/com/ibm/icu/text/DateIntervalFormat.html
- *
- * Example usage:
- * var DateIntervalFormat = goog.require('goog.i18n.DateIntervalFormat');
- * var DateRange = goog.require('goog.date.DateRange');
- * var DateTime = goog.require('goog.date.DateTime');
- * var DateTimeFormat = goog.require('goog.i18n.DateTimeFormat');
- * var GDate = goog.require('goog.date.Date');
- * var Interval = goog.require('goog.date.Interval');
- *
- * // Formatter.
- * var dtIntFmt = new DateIntervalFormat(DateTimeFormat.Format.MEDIUM_DATE);
- *
- * // Format a date range.
- * var dt1 = new GDate(2016, 8, 23);
- * var dt2 = new GDate(2016, 8, 24);
- * var dtRng = new DateRange(dt1, dt2);
- * dtIntFmt.formatRange(dtRng); // --> 'Sep 23 – 24, 2016'
- *
- * // Format two dates.
- * var dt3 = new DateTime(2016, 8, 23, 14, 53, 0);
- * var dt4 = new DateTime(2016, 8, 23, 14, 54, 0);
- * dtIntFmt.format(dt3, dt4); // --> 'Sep 23, 2016'
- *
- * // Format a date and an interval.
- * var dt5 = new DateTime(2016, 8, 23, 14, 53, 0);
- * var itv = new Interval(0, 1); // One month.
- * dtIntFmt.format(dt5, itv); // --> 'Sep 23 – Oct 23, 2016'
- *
- */
- goog.module('goog.i18n.DateIntervalFormat');
- var DateLike = goog.require('goog.date.DateLike');
- var DateRange = goog.require('goog.date.DateRange');
- var DateTime = goog.require('goog.date.DateTime');
- var DateTimeFormat = goog.require('goog.i18n.DateTimeFormat');
- var DateTimeSymbols = goog.require('goog.i18n.DateTimeSymbols');
- var DateTimeSymbolsType = goog.require('goog.i18n.DateTimeSymbolsType');
- var Interval = goog.require('goog.date.Interval');
- var TimeZone = goog.require('goog.i18n.TimeZone');
- var array = goog.require('goog.array');
- var asserts = goog.require('goog.asserts');
- var dateIntervalSymbols = goog.require('goog.i18n.dateIntervalSymbols');
- var object = goog.require('goog.object');
- /**
- * Constructs a DateIntervalFormat object based on the current locale.
- *
- * @param {number|!dateIntervalSymbols.DateIntervalPatternMap} pattern Pattern
- * specification or pattern object.
- * @param {!dateIntervalSymbols.DateIntervalSymbols=} opt_dateIntervalSymbols
- * Optional DateIntervalSymbols to use for this instance rather than the
- * global symbols.
- * @param {!DateTimeSymbolsType=} opt_dateTimeSymbols Optional DateTimeSymbols
- * to use for this instance rather than the global symbols.
- * @constructor
- * @struct
- * @final
- */
- var DateIntervalFormat = function(
- pattern, opt_dateIntervalSymbols, opt_dateTimeSymbols) {
- asserts.assert(goog.isDef(pattern), 'Pattern must be defined.');
- asserts.assert(
- goog.isDef(opt_dateIntervalSymbols) ||
- goog.isDef(dateIntervalSymbols.getDateIntervalSymbols()),
- 'goog.i18n.DateIntervalSymbols or explicit symbols must be defined');
- asserts.assert(
- goog.isDef(opt_dateTimeSymbols) || goog.isDef(DateTimeSymbols),
- 'goog.i18n.DateTimeSymbols or explicit symbols must be defined');
- /**
- * DateIntervalSymbols object that contains locale data required by the
- * formatter.
- * @private @const {!dateIntervalSymbols.DateIntervalSymbols}
- */
- this.dateIntervalSymbols_ =
- opt_dateIntervalSymbols || dateIntervalSymbols.getDateIntervalSymbols();
- /**
- * DateTimeSymbols object that contain locale data required by the formatter.
- * @private @const {!DateTimeSymbolsType}
- */
- this.dateTimeSymbols_ = opt_dateTimeSymbols || DateTimeSymbols;
- /**
- * Date interval pattern to use.
- * @private @const {!dateIntervalSymbols.DateIntervalPatternMap}
- */
- this.intervalPattern_ = this.getIntervalPattern_(pattern);
- /**
- * Keys of the available date interval patterns. Used to lookup the key that
- * contains a specific pattern letter (e.g. for ['Myd', 'hms'], the key that
- * contains 'y' is 'Myd').
- * @private @const {!Array<string>}
- */
- this.intervalPatternKeys_ = object.getKeys(this.intervalPattern_);
- // Remove the default pattern's key ('_') from intervalPatternKeys_. Is not
- // necesary when looking up for a key: when no key is found it will always
- // default to the default pattern.
- array.remove(this.intervalPatternKeys_, DEFAULT_PATTERN_KEY_);
- /**
- * Default fallback pattern to use.
- * @private @const {string}
- */
- this.fallbackPattern_ =
- this.dateIntervalSymbols_.FALLBACK || DEFAULT_FALLBACK_PATTERN_;
- // Determine which date should be used with each part of the interval
- // pattern.
- var indexOfFirstDate = this.fallbackPattern_.indexOf(FIRST_DATE_PLACEHOLDER_);
- var indexOfSecondDate =
- this.fallbackPattern_.indexOf(SECOND_DATE_PLACEHOLDER_);
- if (indexOfFirstDate < 0 || indexOfSecondDate < 0) {
- throw new Error('Malformed fallback interval pattern');
- }
- /**
- * True if the first date provided should be formatted with the first pattern
- * of the interval pattern.
- * @private @const {boolean}
- */
- this.useFirstDateOnFirstPattern_ = indexOfFirstDate <= indexOfSecondDate;
- /**
- * Map that stores a Formatter_ object per calendar field. Formatters will be
- * instanced on demand and stored on this map until required again.
- * @private @const {!Object<string, !Formatter_>}
- */
- this.formatterMap_ = {};
- };
- /**
- * Default fallback interval pattern.
- * @private @const {string}
- */
- var DEFAULT_FALLBACK_PATTERN_ = '{0} – {1}';
- /**
- * Interval pattern placeholder for the first date.
- * @private @const {string}
- */
- var FIRST_DATE_PLACEHOLDER_ = '{0}';
- /**
- * Interval pattern placeholder for the second date.
- * @private @const {string}
- */
- var SECOND_DATE_PLACEHOLDER_ = '{1}';
- /**
- * Key used by the default datetime pattern.
- * @private @const {string}
- */
- var DEFAULT_PATTERN_KEY_ = '_';
- /**
- * Gregorian calendar Eras.
- * @private @enum {number}
- */
- var Era_ = {BC: 0, AD: 1};
- /**
- * Am Pm markers.
- * @private @enum {number}
- */
- var AmPm_ = {AM: 0, PM: 1};
- /**
- * String of all pattern letters representing the relevant calendar fields.
- * Sorted according to the length of the datetime unit they represent.
- * @private @const {string}
- */
- var RELEVANT_CALENDAR_FIELDS_ = 'GyMdahms';
- /**
- * Regex that matches all possible pattern letters.
- * @private @const {!RegExp}
- */
- var ALL_PATTERN_LETTERS_ = /[a-zA-Z]/;
- /**
- * Returns the interval pattern from a pattern specification or from the pattern
- * object.
- * @param {number|!dateIntervalSymbols.DateIntervalPatternMap} pattern Pattern
- * specification or pattern object.
- * @return {!dateIntervalSymbols.DateIntervalPatternMap}
- * @private
- */
- DateIntervalFormat.prototype.getIntervalPattern_ = function(pattern) {
- if (goog.isNumber(pattern)) {
- switch (pattern) {
- case DateTimeFormat.Format.FULL_DATE:
- return this.dateIntervalSymbols_.FULL_DATE;
- case DateTimeFormat.Format.LONG_DATE:
- return this.dateIntervalSymbols_.LONG_DATE;
- case DateTimeFormat.Format.MEDIUM_DATE:
- return this.dateIntervalSymbols_.MEDIUM_DATE;
- case DateTimeFormat.Format.SHORT_DATE:
- return this.dateIntervalSymbols_.SHORT_DATE;
- case DateTimeFormat.Format.FULL_TIME:
- return this.dateIntervalSymbols_.FULL_TIME;
- case DateTimeFormat.Format.LONG_TIME:
- return this.dateIntervalSymbols_.LONG_TIME;
- case DateTimeFormat.Format.MEDIUM_TIME:
- return this.dateIntervalSymbols_.MEDIUM_TIME;
- case DateTimeFormat.Format.SHORT_TIME:
- return this.dateIntervalSymbols_.SHORT_TIME;
- case DateTimeFormat.Format.FULL_DATETIME:
- return this.dateIntervalSymbols_.FULL_DATETIME;
- case DateTimeFormat.Format.LONG_DATETIME:
- return this.dateIntervalSymbols_.LONG_DATETIME;
- case DateTimeFormat.Format.MEDIUM_DATETIME:
- return this.dateIntervalSymbols_.MEDIUM_DATETIME;
- case DateTimeFormat.Format.SHORT_DATETIME:
- return this.dateIntervalSymbols_.SHORT_DATETIME;
- default:
- return this.dateIntervalSymbols_.MEDIUM_DATETIME;
- }
- } else {
- return pattern;
- }
- };
- /**
- * Formats the given date or date interval objects according to the present
- * pattern and current locale.
- *
- * Parameter combinations:
- * * StartDate: {@link goog.date.DateLike}, EndDate: {@link goog.date.DateLike}
- * * StartDate: {@link goog.date.DateLike}, Interval: {@link goog.date.Interval}
- *
- * @param {!DateLike} startDate Start date of the date range.
- * @param {!DateLike|!Interval} endDate End date of the date range or an
- * interval object.
- * @param {!TimeZone=} opt_timeZone Timezone to be used in the target
- * representation.
- * @return {string} Formatted date interval.
- */
- DateIntervalFormat.prototype.format = function(
- startDate, endDate, opt_timeZone) {
- asserts.assert(
- startDate != null,
- 'The startDate parameter should be defined and not-null.');
- asserts.assert(
- endDate != null, 'The endDate parameter should be defined and not-null.');
- // Convert input to DateLike.
- var endDt;
- if (goog.isDateLike(endDate)) {
- endDt = /** @type {!DateLike} */ (endDate);
- } else {
- asserts.assertInstanceof(
- endDate, Interval,
- 'endDate parameter should be a goog.date.DateLike or ' +
- 'goog.date.Interval');
- endDt = new DateTime(startDate);
- endDt.add(endDate);
- }
- // Obtain the largest different calendar field between the two dates.
- var largestDifferentCalendarField =
- DateIntervalFormat.getLargestDifferentCalendarField_(
- startDate, endDt, opt_timeZone);
- // Get the Formatter_ required to format the specified calendar field and use
- // it to format the dates.
- var formatter =
- this.getFormatterForCalendarField_(largestDifferentCalendarField);
- return formatter.format(
- startDate, endDt, largestDifferentCalendarField, opt_timeZone);
- };
- /**
- * Formats the given date range object according to the present pattern and
- * current locale.
- *
- * @param {!DateRange} dateRange
- * @param {!TimeZone=} opt_timeZone Timezone to be used in the target
- * representation.
- * @return {string} Formatted date interval.
- */
- DateIntervalFormat.prototype.formatRange = function(dateRange, opt_timeZone) {
- asserts.assert(
- dateRange != null,
- 'The dateRange parameter should be defined and non-null.');
- var startDate = dateRange.getStartDate();
- var endDate = dateRange.getEndDate();
- if (startDate == null) {
- throw Error('The dateRange\'s startDate should be defined and non-null.');
- }
- if (endDate == null) {
- throw Error('The dateRange\'s endDate should be defined and non-null.');
- }
- return this.format(startDate, endDate, opt_timeZone);
- };
- /**
- * Returns the Formatter_ to be used to format two dates for the given calendar
- * field.
- * @param {string} calendarField Pattern letter representing the calendar field.
- * @return {!Formatter_}
- * @private
- */
- DateIntervalFormat.prototype.getFormatterForCalendarField_ = function(
- calendarField) {
- if (calendarField != '') {
- for (var i = 0; i < this.intervalPatternKeys_.length; i++) {
- if (this.intervalPatternKeys_[i].indexOf(calendarField) >= 0) {
- return this.getOrCreateFormatterForKey_(this.intervalPatternKeys_[i]);
- }
- }
- }
- return this.getOrCreateFormatterForKey_(DEFAULT_PATTERN_KEY_);
- };
- /**
- * Returns and creates (if necessary) a formatter for the specified key.
- * @param {string} key
- * @return {!Formatter_}
- * @private
- */
- DateIntervalFormat.prototype.getOrCreateFormatterForKey_ = function(key) {
- var fmt = this;
- return object.setWithReturnValueIfNotSet(this.formatterMap_, key, function() {
- var patternParts =
- DateIntervalFormat.divideIntervalPattern_(fmt.intervalPattern_[key]);
- if (patternParts === null) {
- return new DateTimeFormatter_(
- fmt.intervalPattern_[key], fmt.fallbackPattern_,
- fmt.dateTimeSymbols_);
- }
- return new IntervalFormatter_(
- patternParts.firstPart, patternParts.secondPart, fmt.dateTimeSymbols_,
- fmt.useFirstDateOnFirstPattern_);
- });
- };
- /**
- * Divides the interval pattern string into its two parts. Will return null if
- * the pattern can't be divided (e.g. it's a datetime pattern).
- * @param {string} intervalPattern
- * @return {?{firstPart:string, secondPart:string}} Record containing the two
- * parts of the interval pattern. Null if the pattern can't be divided.
- * @private
- */
- DateIntervalFormat.divideIntervalPattern_ = function(intervalPattern) {
- var foundKeys = {};
- var patternParts = null;
- // Iterate over the pattern until a repeated calendar field is found.
- DateIntervalFormat.executeForEveryCalendarField_(
- intervalPattern, function(char, index) {
- if (object.containsKey(foundKeys, char)) {
- patternParts = {
- firstPart: intervalPattern.substring(0, index),
- secondPart: intervalPattern.substring(index)
- };
- return false;
- }
- object.set(foundKeys, char, true);
- return true;
- });
- return patternParts;
- };
- /**
- * Iterates over a pattern string and executes a function for every
- * calendar field. The function will be executed once, independent of the width
- * of the calendar field (number of repeated pattern letters). It will ignore
- * all literal text (enclosed by quotes).
- *
- * For example, on: "H 'h' mm – H 'h' mm" it will call the function for:
- * H (pos:0), m (pos:6), H (pos:11), m (pos:17).
- *
- * @param {string} pattern
- * @param {function(string, number):boolean} func Function which accepts as
- * parameters the current calendar field and the index of its first pattern
- * letter; and returns a boolean which indicates if the iteration should
- * continue.
- * @private
- */
- DateIntervalFormat.executeForEveryCalendarField_ = function(pattern, func) {
- var inQuote = false;
- var previousChar = '';
- for (var i = 0; i < pattern.length; i++) {
- var char = pattern.charAt(i);
- if (inQuote) {
- if (char == '\'') {
- if (i + 1 < pattern.length && pattern.charAt(i + 1) == '\'') {
- i++; // Literal quotation mark: ignore and advance.
- } else {
- inQuote = false;
- }
- }
- } else {
- if (char == '\'') {
- inQuote = true;
- } else if (char != previousChar && ALL_PATTERN_LETTERS_.test(char)) {
- if (!func(char, i)) {
- break;
- }
- }
- }
- previousChar = char;
- }
- };
- /**
- * Returns a pattern letter representing the largest different calendar field
- * between the two dates. This is calculated using the timezone used in the
- * target representation.
- * @param {!DateLike} startDate Start date of the date range.
- * @param {!DateLike} endDate End date of the date range.
- * @param {!TimeZone=} opt_timeZone Timezone to be used in the target
- * representation.
- * @return {string} Pattern letter representing the largest different calendar
- * field or an empty string if all relevant fields for these dates are equal.
- * @private
- */
- DateIntervalFormat.getLargestDifferentCalendarField_ = function(
- startDate, endDate, opt_timeZone) {
- // Before comparing them, dates have to be adjusted by the target timezone's
- // offset.
- var startDiff = 0;
- var endDiff = 0;
- if (opt_timeZone != null) {
- startDiff =
- (startDate.getTimezoneOffset() - opt_timeZone.getOffset(startDate)) *
- 60000;
- endDiff =
- (endDate.getTimezoneOffset() - opt_timeZone.getOffset(endDate)) * 60000;
- }
- var startDt = new Date(startDate.getTime() + startDiff);
- var endDt = new Date(endDate.getTime() + endDiff);
- if (DateIntervalFormat.getEra_(startDt) !=
- DateIntervalFormat.getEra_(endDt)) {
- return 'G';
- } else if (startDt.getFullYear() != endDt.getFullYear()) {
- return 'y';
- } else if (startDt.getMonth() != endDt.getMonth()) {
- return 'M';
- } else if (startDt.getDate() != endDt.getDate()) {
- return 'd';
- } else if (
- DateIntervalFormat.getAmPm_(startDt) !=
- DateIntervalFormat.getAmPm_(endDt)) {
- return 'a';
- } else if (startDt.getHours() != endDt.getHours()) {
- return 'h';
- } else if (startDt.getMinutes() != endDt.getMinutes()) {
- return 'm';
- } else if (startDt.getSeconds() != endDt.getSeconds()) {
- return 's';
- }
- return '';
- };
- /**
- * Returns the Era of a given DateLike object.
- * @param {!Date} date
- * @return {number}
- * @private
- */
- DateIntervalFormat.getEra_ = function(date) {
- return date.getFullYear() > 0 ? Era_.AD : Era_.BC;
- };
- /**
- * Returns if the given date is in AM or PM.
- * @param {!Date} date
- * @return {number}
- * @private
- */
- DateIntervalFormat.getAmPm_ = function(date) {
- var hours = date.getHours();
- return (12 <= hours && hours < 24) ? AmPm_.PM : AmPm_.AM;
- };
- /**
- * Returns true if the calendar field field1 is a larger or equal than field2.
- * Assumes that both string parameters have just one character. Field1 has to
- * be part of the relevant calendar fields set.
- * @param {string} field1
- * @param {string} field2
- * @return {boolean}
- * @private
- */
- DateIntervalFormat.isCalendarFieldLargerOrEqualThan_ = function(
- field1, field2) {
- return RELEVANT_CALENDAR_FIELDS_.indexOf(field1) <=
- RELEVANT_CALENDAR_FIELDS_.indexOf(field2);
- };
- /**
- * Interface implemented by internal date interval formatters.
- * @interface
- * @private
- */
- var Formatter_ = function() {};
- /**
- * Formats two dates with the two parts of the date interval and returns the
- * formatted string.
- * @param {!DateLike} firstDate
- * @param {!DateLike} secondDate
- * @param {string} largestDifferentCalendarField
- * @param {!TimeZone=} opt_timeZone Target timezone in which to format the
- * dates.
- * @return {string} String with the formatted date interval.
- */
- Formatter_.prototype.format = function(
- firstDate, secondDate, largestDifferentCalendarField, opt_timeZone) {};
- /**
- * Constructs an IntervalFormatter_ object which implements the Formatter_
- * interface.
- *
- * Internal object to construct and store a goog.i18n.DateTimeFormat for each
- * part of the date interval pattern.
- *
- * @param {string} firstPattern First part of the date interval pattern.
- * @param {string} secondPattern Second part of the date interval pattern.
- * @param {!DateTimeSymbolsType} dateTimeSymbols Symbols to use with the
- * datetime formatters.
- * @param {boolean} useFirstDateOnFirstPattern Indicates if the first or the
- * second date should be formatted with the first or second part of the date
- * interval pattern.
- * @constructor
- * @implements {Formatter_}
- * @private
- */
- var IntervalFormatter_ = function(
- firstPattern, secondPattern, dateTimeSymbols, useFirstDateOnFirstPattern) {
- /**
- * Formatter_ to format the first part of the date interval.
- * @private {!DateTimeFormat}
- */
- this.firstPartFormatter_ = new DateTimeFormat(firstPattern, dateTimeSymbols);
- /**
- * Formatter_ to format the second part of the date interval.
- * @private {!DateTimeFormat}
- */
- this.secondPartFormatter_ =
- new DateTimeFormat(secondPattern, dateTimeSymbols);
- /**
- * Specifies if the first or the second date should be formatted by the
- * formatter of the first or second part of the date interval.
- * @private {boolean}
- */
- this.useFirstDateOnFirstPattern_ = useFirstDateOnFirstPattern;
- };
- /** @override */
- IntervalFormatter_.prototype.format = function(
- firstDate, secondDate, largestDifferentCalendarField, opt_timeZone) {
- if (this.useFirstDateOnFirstPattern_) {
- return this.firstPartFormatter_.format(firstDate, opt_timeZone) +
- this.secondPartFormatter_.format(secondDate, opt_timeZone);
- } else {
- return this.firstPartFormatter_.format(secondDate, opt_timeZone) +
- this.secondPartFormatter_.format(firstDate, opt_timeZone);
- }
- };
- /**
- * Constructs a DateTimeFormatter_ object which implements the Formatter_
- * interface.
- *
- * Internal object to construct and store a goog.i18n.DateTimeFormat for the
- * a datetime pattern and formats dates using the fallback interval pattern
- * (e.g. '{0} – {1}').
- *
- * @param {string} dateTimePattern Datetime pattern used to format the dates.
- * @param {string} fallbackPattern Fallback interval pattern to be used with the
- * datetime pattern.
- * @param {!DateTimeSymbolsType} dateTimeSymbols Symbols to use with
- * the datetime format.
- * @constructor
- * @implements {Formatter_}
- * @private
- */
- var DateTimeFormatter_ = function(
- dateTimePattern, fallbackPattern, dateTimeSymbols) {
- /**
- * Date time pattern used to format the dates.
- * @private {string}
- */
- this.dateTimePattern_ = dateTimePattern;
- /**
- * Date time formatter used to format the dates.
- * @private {!DateTimeFormat}
- */
- this.dateTimeFormatter_ =
- new DateTimeFormat(dateTimePattern, dateTimeSymbols);
- /**
- * Fallback interval pattern.
- * @private {string}
- */
- this.fallbackPattern_ = fallbackPattern;
- };
- /** @override */
- DateTimeFormatter_.prototype.format = function(
- firstDate, secondDate, largestDifferentCalendarField, opt_timeZone) {
- // Check if the largest different calendar field between the two dates is
- // larger or equal than any calendar field in the datetime pattern. If true,
- // format the string using the datetime pattern and the fallback interval
- // pattern.
- var shouldFormatWithFallbackPattern = false;
- if (largestDifferentCalendarField != '') {
- DateIntervalFormat.executeForEveryCalendarField_(
- this.dateTimePattern_, function(char, index) {
- if (DateIntervalFormat.isCalendarFieldLargerOrEqualThan_(
- largestDifferentCalendarField, char)) {
- shouldFormatWithFallbackPattern = true;
- return false;
- }
- return true;
- });
- }
- if (shouldFormatWithFallbackPattern) {
- return this.fallbackPattern_
- .replace(
- FIRST_DATE_PLACEHOLDER_,
- this.dateTimeFormatter_.format(firstDate, opt_timeZone))
- .replace(
- SECOND_DATE_PLACEHOLDER_,
- this.dateTimeFormatter_.format(secondDate, opt_timeZone));
- }
- // If not, format the first date using the datetime pattern.
- return this.dateTimeFormatter_.format(firstDate, opt_timeZone);
- };
- exports = DateIntervalFormat;
|