UNPKG

@ui5/webcomponents-localization

Version:
842 lines (813 loc) 142 kB
/*! * OpenUI5 * (c) Copyright 2009-2024 SAP SE or an SAP affiliate company. * Licensed under the Apache License, Version 2.0 - see LICENSE.txt. */ // Provides class sap.ui.core.format.DateFormat import Log from "../../../base/Log.js"; import formatMessage from "../../../base/strings/formatMessage.js"; import deepEqual from "../../../base/util/deepEqual.js"; import extend from "../../../base/util/extend.js"; import CalendarType from "../CalendarType.js"; import Configuration from "../Configuration.js"; import Core from "../Core.js"; import Locale from "../Locale.js"; import LocaleData from "../LocaleData.js"; import Supportability from "../Supportability.js"; import CalendarUtils from "../date/CalendarUtils.js"; import CalendarWeekNumbering from "../date/CalendarWeekNumbering.js"; import UI5Date from "../date/UI5Date.js"; import UniversalDate from "../date/UniversalDate.js"; import TimezoneUtil from "./TimezoneUtil.js"; /** * Constructor for DateFormat - must not be used: * <ul> * <li>To get a {@link sap.ui.core.format.DateFormat} instance, please use {@link sap.ui.core.format.DateFormat.getDateInstance}, {@link sap.ui.core.format.DateFormat.getDateTimeInstance} or {@link sap.ui.core.format.DateFormat.getTimeInstance}</li> * <li>To get a {@link sap.ui.core.format.DateFormat.DateTimeWithTimezone} instance, please use {@link sap.ui.core.format.DateFormat.getDateTimeWithTimezoneInstance}</li> * </ul> * * @class * The DateFormat is a static class for formatting and parsing single date and time values or date and time intervals according * to a set of format options. * * Important: * Every Date is converted with the timezone taken from {@link sap.ui.core.Configuration#getTimezone}. * The timezone falls back to the browser's local timezone. * * Supported format options are pattern based on Unicode LDML Date Format notation. Please note that only a subset of the LDML date symbols * is supported. * If no pattern is specified a default pattern according to the locale settings is used. * * Documentation links: * <ul> * <li>{@link topic:91f2eba36f4d1014b6dd926db0e91070 Date Format}</li> * <li>{@link http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table}</li> * </ul> * * @public * @hideconstructor * @alias sap.ui.core.format.DateFormat */ var DateFormat = function () { // Do not use the constructor throw new Error(); }; /** * Internal enumeration to differentiate DateFormat types */ var mDateFormatTypes = { DATE: "date", TIME: "time", DATETIME: "datetime", DATETIME_WITH_TIMEZONE: "datetimeWithTimezone" }; // Cache for parsed CLDR DatePattern var mCldrDatePattern = {}; /** * Timezone parameter type check * * @param {string} sTimezone The timezone to check * @throws {TypeError} Thrown if the parameter <code>sTimezone</code> is provided and has the wrong type. */ var checkTimezoneParameterType = function (sTimezone) { if (typeof sTimezone !== "string" && !(sTimezone instanceof String) && sTimezone != null) { throw new TypeError("The given timezone must be a string."); } }; DateFormat.oDateInfo = { type: mDateFormatTypes.DATE, oDefaultFormatOptions: { style: "medium", relativeScale: "day", relativeStyle: "wide" }, aFallbackFormatOptions: [{ style: "short" }, { style: "medium" }, { pattern: "yyyy-MM-dd" }, { pattern: "yyyyMMdd", strictParsing: true }], bShortFallbackFormatOptions: true, bPatternFallbackWithoutDelimiter: true, getPattern: function (oLocaleData, sStyle, sCalendarType) { return oLocaleData.getDatePattern(sStyle, sCalendarType); }, oRequiredParts: { "text": true, "year": true, "weekYear": true, "month": true, "day": true }, aRelativeScales: ["year", "month", "week", "day"], aRelativeParseScales: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"], aIntervalCompareFields: ["Era", "FullYear", "Quarter", "Month", "Week", "Date"] }; DateFormat.oDateTimeInfo = { type: mDateFormatTypes.DATETIME, oDefaultFormatOptions: { style: "medium", relativeScale: "auto", relativeStyle: "wide" }, aFallbackFormatOptions: [{ style: "short" }, { style: "medium" }, { pattern: "yyyy-MM-dd'T'HH:mm:ss" }, { pattern: "yyyyMMdd HHmmss" }], getPattern: function (oLocaleData, sStyle, sCalendarType) { // If style is mixed ("medium/short") split it and pass both parts separately var iSlashIndex = sStyle.indexOf("/"); if (iSlashIndex > 0) { return oLocaleData.getCombinedDateTimePattern(sStyle.substr(0, iSlashIndex), sStyle.substr(iSlashIndex + 1), sCalendarType); } else { return oLocaleData.getCombinedDateTimePattern(sStyle, sStyle, sCalendarType); } }, oRequiredParts: { "text": true, "year": true, "weekYear": true, "month": true, "day": true, "hour0_23": true, "hour1_24": true, "hour0_11": true, "hour1_12": true }, aRelativeScales: ["year", "month", "week", "day", "hour", "minute", "second"], aRelativeParseScales: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"], aIntervalCompareFields: ["Era", "FullYear", "Quarter", "Month", "Week", "Date", "DayPeriod", "Hours", "Minutes", "Seconds"] }; /** * Retrieves info object for timezone instance * * @param {object} oFormatOptions the format options, relevant are: showDate, showTime and showTimezone * @returns {object} info object * @private */ DateFormat._getDateTimeWithTimezoneInfo = function (oFormatOptions) { var bShowDate = oFormatOptions.showDate === undefined || oFormatOptions.showDate; var bShowTime = oFormatOptions.showTime === undefined || oFormatOptions.showTime; var bShowTimezone = oFormatOptions.showTimezone === undefined || oFormatOptions.showTimezone; var oBaselineType = DateFormat.oDateTimeInfo; if (bShowDate && !bShowTime) { oBaselineType = DateFormat.oDateInfo; } else if (!bShowDate && bShowTime) { oBaselineType = DateFormat.oTimeInfo; } return Object.assign({}, oBaselineType, { type: mDateFormatTypes.DATETIME_WITH_TIMEZONE, // This function is used to transform the pattern of the fallbackFormatOptions to a timezone pattern. getTimezonePattern: function (sPattern) { if (!bShowDate && !bShowTime && bShowTimezone) { return "VV"; } else if (!bShowTimezone) { return sPattern; } else { return sPattern + " VV"; } }, getPattern: function (oLocaleData, sStyle, sCalendarType) { if (!bShowDate && !bShowTime && bShowTimezone) { return "VV"; } if (!bShowTimezone) { return oBaselineType.getPattern(oLocaleData, sStyle, sCalendarType); } var sPattern = oBaselineType.getPattern(oLocaleData, sStyle, sCalendarType); return oLocaleData.applyTimezonePattern(sPattern); } }); }; DateFormat.oTimeInfo = { type: mDateFormatTypes.TIME, oDefaultFormatOptions: { style: "medium", relativeScale: "auto", relativeStyle: "wide" }, aFallbackFormatOptions: [{ style: "short" }, { style: "medium" }, { pattern: "HH:mm:ss" }, { pattern: "HHmmss" }], getPattern: function (oLocaleData, sStyle, sCalendarType) { return oLocaleData.getTimePattern(sStyle, sCalendarType); }, oRequiredParts: { "text": true, "hour0_23": true, "hour1_24": true, "hour0_11": true, "hour1_12": true }, aRelativeScales: ["hour", "minute", "second"], aRelativeParseScales: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"], aIntervalCompareFields: ["DayPeriod", "Hours", "Minutes", "Seconds"] }; /** * @see sap.ui.core.format.DateFormat.getDateInstance */ DateFormat.getInstance = function (oFormatOptions, oLocale) { return this.getDateInstance(oFormatOptions, oLocale); }; /** * Get a date instance of the DateFormat, which can be used for formatting. * * @param {object} [oFormatOptions] Object which defines the format options * @param {sap.ui.core.date.CalendarWeekNumbering} [oFormatOptions.calendarWeekNumbering] since 1.108.0 specifies the calendar week numbering. * If specified, this overwrites <code>oFormatOptions.firstDayOfWeek</code> and <code>oFormatOptions.minimalDaysInFirstWeek</code>. * @param {int} [oFormatOptions.firstDayOfWeek] since 1.105.0 specifies the first day of the week starting with <code>0</code> (which is Sunday); if not defined, the value taken from the locale is used * @param {int} [oFormatOptions.minimalDaysInFirstWeek] since 1.105.0 minimal days at the beginning of the year which define the first calendar week; if not defined, the value taken from the locale is used * @param {string} [oFormatOptions.format] since 1.34.0 contains pattern symbols (e.g. "yMMMd" or "Hms") which will be converted into the pattern in the used locale, which matches the wanted symbols best. * The symbols must be in canonical order, that is: Era (G), Year (y/Y), Quarter (q/Q), Month (M/L), Week (w), Day-Of-Week (E/e/c), Day (d), Hour (h/H/k/K/j/J), Minute (m), Second (s), Timezone (z/Z/v/V/O/X/x) * See {@link http://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems} * @param {string} [oFormatOptions.pattern] a data pattern in LDML format. It is not verified whether the pattern represents only a date. * @param {string} [oFormatOptions.style] can be either 'short, 'medium', 'long' or 'full'. If no pattern is given, a locale dependent default date pattern of that style is used from the LocaleData class. * @param {boolean} [oFormatOptions.strictParsing] if true, by parsing it is checked if the value is a valid date * @param {boolean} [oFormatOptions.relative] if true, the date is formatted relatively to todays date if it is within the given day range, e.g. "today", "1 day ago", "in 5 days" * @param {int[]} [oFormatOptions.relativeRange] the day range used for relative formatting. If <code>oFormatOptions.relativeScale</code> is set to default value 'day', the relativeRange is by default [-6, 6], which means only the last 6 days, today and the next 6 days are formatted relatively. Otherwise when <code>oFormatOptions.relativeScale</code> is set to 'auto', all dates are formatted relatively. * @param {string} [oFormatOptions.relativeScale="day"] if 'auto' is set, new relative time format is switched on for all Date/Time Instances. The relative scale is chosen depending on the difference between the given date and now. * @param {string} [oFormatOptions.relativeStyle="wide"] since 1.32.10, 1.34.4 the style of the relative format. The valid values are "wide", "short", "narrow" * @param {boolean} [oFormatOptions.interval=false] since 1.48.0 if true, the {@link sap.ui.core.format.DateFormat#format format} method expects an array with two dates as the first argument and formats them as interval. Further interval "Jan 10, 2008 - Jan 12, 2008" will be formatted as "Jan 10-12, 2008" if the 'format' option is set with necessary symbols. * Otherwise the two given dates are formatted separately and concatenated with local dependent pattern. * @param {string} [oFormatOptions.intervalDelimiter] * Since 1.113.0, a delimiter for intervals. With a given interval delimiter a specific interval format is * created. <b>Example:</b> If <code>oFormatOptions.intervalDelimiter</code> is set to "...", an interval would be * given as "Jan 10, 2008...Feb 12, 2008". * <b>Note:</b> If this format option is set, the locale-specific interval notation is overruled, for example * "Jan 10 – Feb 12, 2008" becomes "Jan 10, 2008...Feb 12, 2008". * @param {boolean} [oFormatOptions.singleIntervalValue=false] Only relevant if oFormatOptions.interval is set to 'true'. This allows to pass an array with only one date object to the {@link sap.ui.core.format.DateFormat#format format} method. * @param {boolean} [oFormatOptions.UTC] if true, the date is formatted and parsed as UTC instead of the local timezone * @param {sap.ui.core.CalendarType} [oFormatOptions.calendarType] The calender type which is used to format and parse the date. This value is by default either set in configuration or calculated based on current locale. * @param {sap.ui.core.Locale} [oLocale] Locale to ask for locale specific texts/settings * @ui5-omissible-params oFormatOptions * @return {sap.ui.core.format.DateFormat} date instance of the DateFormat * @static * @public * @throws {TypeError} If: * <ul> * <li>The <code>calendarWeekNumbering</code> format option has an unsupported value, or</li> * <li>only one of the <code>firstDayOfWeek</code> and <code>minimalDaysInFirstWeek</code> parameters was provided.</li> * </ul> */ DateFormat.getDateInstance = function (oFormatOptions, oLocale) { return this.createInstance(oFormatOptions, oLocale, this.oDateInfo); }; /** * Get a datetime instance of the DateFormat, which can be used for formatting. * * @param {object} [oFormatOptions] Object which defines the format options * @param {sap.ui.core.date.CalendarWeekNumbering} [oFormatOptions.calendarWeekNumbering] since 1.108.0 specifies the calendar week numbering. * If specified, this overwrites <code>oFormatOptions.firstDayOfWeek</code> and <code>oFormatOptions.minimalDaysInFirstWeek</code>. * @param {int} [oFormatOptions.firstDayOfWeek] since 1.105.0 specifies the first day of the week starting with <code>0</code> (which is Sunday); if not defined, the value taken from the locale is used * @param {int} [oFormatOptions.minimalDaysInFirstWeek] since 1.105.0 minimal days at the beginning of the year which define the first calendar week; if not defined, the value taken from the locale is used * @param {string} [oFormatOptions.format] since 1.34.0 contains pattern symbols (e.g. "yMMMd" or "Hms") which will be converted into the pattern in the used locale, which matches the wanted symbols best. * The symbols must be in canonical order, that is: Era (G), Year (y/Y), Quarter (q/Q), Month (M/L), Week (w), Day-Of-Week (E/e/c), Day (d), Hour (h/H/k/K/j/J), Minute (m), Second (s), Timezone (z/Z/v/V/O/X/x) * See http://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems * @param {string} [oFormatOptions.pattern] a datetime pattern in LDML format. It is not verified whether the pattern represents a full datetime. * @param {string} [oFormatOptions.style] can be either 'short, 'medium', 'long' or 'full'. For datetime you can also define mixed styles, separated with a slash, where the first part is the date style and the second part is the time style (e.g. "medium/short"). If no pattern is given, a locale dependent default datetime pattern of that style is used from the LocaleData class. * @param {boolean} [oFormatOptions.strictParsing] if true, by parsing it is checked if the value is a valid datetime * @param {boolean} [oFormatOptions.relative] if true, the date is formatted relatively to today's date if it is within the given day range, e.g. "today", "1 day ago", "in 5 days" * @param {int[]} [oFormatOptions.relativeRange] the day range used for relative formatting. If <code>oFormatOptions.relativeScale</code> is set to default value 'day', the relativeRange is by default [-6, 6], which means only the last 6 days, today and the next 6 days are formatted relatively. Otherwise when <code>oFormatOptions.relativeScale</code> is set to 'auto', all dates are formatted relatively. * @param {string} [oFormatOptions.relativeScale="day"] if 'auto' is set, new relative time format is switched on for all Date/Time Instances. The relative scale is chosen depending on the difference between the given date and now. * @param {string} [oFormatOptions.relativeStyle="wide"] since 1.32.10, 1.34.4 the style of the relative format. The valid values are "wide", "short", "narrow" * @param {boolean} [oFormatOptions.interval=false] since 1.48.0 if true, the {@link sap.ui.core.format.DateFormat#format format} method expects an array with two dates as the first argument and formats them as interval. Further interval "Jan 10, 2008 - Jan 12, 2008" will be formatted as "Jan 10-12, 2008" if the 'format' option is set with necessary symbols. * Otherwise the two given dates are formatted separately and concatenated with local dependent pattern. * @param {string} [oFormatOptions.intervalDelimiter] * Since 1.113.0, a delimiter for intervals. With a given interval delimiter a specific interval format is * created. <b>Example:</b> If <code>oFormatOptions.intervalDelimiter</code> is set to "...", an interval would be * given as "Jan 10, 2008, 9:15:00 AM...Jan 10, 2008, 11:45:00 AM". * <b>Note:</b> If this format option is set, the locale-specific interval notation is overruled, for example * "Jan 10, 2008, 9:15 – 11:45 AM" becomes "Jan 10, 2008, 9:15 AM...Jan 10, 2008, 11:45 AM". * @param {boolean} [oFormatOptions.singleIntervalValue=false] Only relevant if oFormatOptions.interval is set to 'true'. This allows to pass an array with only one date object to the {@link sap.ui.core.format.DateFormat#format format} method. * @param {boolean} [oFormatOptions.UTC] if true, the date is formatted and parsed as UTC instead of the local timezone * @param {sap.ui.core.CalendarType} [oFormatOptions.calendarType] The calender type which is used to format and parse the date. This value is by default either set in configuration or calculated based on current locale. * @param {sap.ui.core.Locale} [oLocale] Locale to ask for locale specific texts/settings * @ui5-omissible-params oFormatOptions * @return {sap.ui.core.format.DateFormat} datetime instance of the DateFormat * @static * @public * @throws {TypeError} If: * <ul> * <li>The <code>calendarWeekNumbering</code> format option has an unsupported value, or</li> * <li>only one of the <code>firstDayOfWeek</code> and <code>minimalDaysInFirstWeek</code> parameters was provided.</li> * </ul> */ DateFormat.getDateTimeInstance = function (oFormatOptions, oLocale) { return this.createInstance(oFormatOptions, oLocale, this.oDateTimeInfo); }; /** * Interface for a timezone-specific DateFormat, which is able to format and parse a date * based on a given timezone. The timezone is used to convert the given date, and also for * timezone-related pattern symbols. The timezone is an IANA timezone ID, e.g. "America/New_York". * * @see sap.ui.core.format.DateFormat * * @author SAP SE * @since 1.99 * @interface * @name sap.ui.core.format.DateFormat.DateTimeWithTimezone * @public */ /** * Format a date object to a string according to the given timezone and format options. * * @example <caption>Format option showTimezone: true (default)</caption> * var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z"); * * DateFormat.getDateTimeWithTimezoneInstance().format(oDate, "Europe/Berlin"); * // output: "Dec 24, 2021, 2:37:00 PM Europe, Berlin" * * DateFormat.getDateTimeWithTimezoneInstance().format(oDate, "America/New_York"); * // output: "Dec 24, 2021, 8:37:00 AM Americas, New York" * * @example <caption>Format option showTimezone: false</caption> * var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z"); * DateFormat.getDateTimeWithTimezoneInstance({showTimezone: false}).format(oDate, "America/New_York"); * // output: "Dec 24, 2021, 8:37:00 AM" * * @example <caption>Format option showDate: false and showTime:false</caption> * var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z"); * DateFormat.getDateTimeWithTimezoneInstance({showDate: false, showTime: false}).format(oDate, "America/New_York"); * // output: "Americas, New York" * * @param {Date} oJSDate The date to format * @param {string} [sTimezone] The IANA timezone ID in which the date will be calculated and * formatted e.g. "America/New_York". If the parameter is omitted, <code>null</code> or an empty string, the timezone * will be taken from {@link sap.ui.core.Configuration#getTimezone}. For an invalid IANA timezone ID, an empty string will be returned. * @throws {TypeError} Thrown if the parameter <code>sTimezone</code> is provided and has the wrong type. * @return {string} the formatted output value. If an invalid date or timezone is given, an empty string is returned. * @name sap.ui.core.format.DateFormat.DateTimeWithTimezone.format * @function * @public * @since 1.99 */ /** * Parse a string which is formatted according to the given format options to an array * containing a date object and the timezone. * * @example <caption>Format option showTimezone: true (default)</caption> * var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z"); * * DateFormat.getDateTimeWithTimezoneInstance().parse("Dec 24, 2021, 2:37:00 PM Europe, Berlin", "Europe/Berlin"); * // output: [oDate, "Europe/Berlin"] * * DateFormat.getDateTimeWithTimezoneInstance().parse("Dec 24, 2021, 8:37:00 AM Americas, New York", "America/New_York"); * // output: [oDate, "America/New_York"] * * @example <caption>Format option showTimezone: false</caption> * var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z"); * DateFormat.getDateTimeWithTimezoneInstance({showTimezone: false}).parse("Dec 24, 2021, 8:37:00 AM", "America/New_York"); * // output: [oDate, undefined] * * @example <caption>Format option showDate: false and showTime: false</caption> * DateFormat.getDateTimeWithTimezoneInstance({showDate: false, showTime: false}).parse("Americas, New York", "America/New_York"); * // output: [undefined, "America/New_York"] * * @param {string} sValue the string containing a formatted date/time value * @param {string} [sTimezone] The IANA timezone ID which should be used to convert the date * e.g. "America/New_York". If the parameter is omitted, <code>null</code> or an empty string, the timezone will be taken * from {@link sap.ui.core.Configuration#getTimezone}. For an invalid IANA timezone ID, <code>null</code> will be returned. * @param {boolean} [bStrict] Whether to be strict with regards to the value ranges of date fields, * e.g. for a month pattern of <code>MM</code> and a value range of [1-12] * <code>strict</code> ensures that the value is within the range; * if it is larger than <code>12</code> it cannot be parsed and <code>null</code> is returned * @throws {TypeError} Thrown if one of the following applies: * <ul> * <li>the <code>sTimezone</code> parameter is provided and has the wrong type</li> * <li>only the time is shown (<code>showDate</code> is <code>false</code>), or only the * date is shown (<code>showTime</code> is <code>false</code>)</li> * </ul> * @return {Array} the parsed values * <ul> * <li>An array containing datetime and timezone depending on the showDate, showTime and showTimezone options * <ul> * <li>(Default): [Date, string], e.g. * [UI5Date.getInstance("2021-11-13T13:22:33Z"), "America/New_York"]</li> * <li><code>showTimezone: false</code>: [Date, undefined], e.g. * [UI5Date.getInstance("2021-11-13T13:22:33Z"), undefined]</li> * <li><code>showDate: false, showTime: false</code>: [undefined, string], e.g. * [undefined, "America/New_York"]</li> * </ul> * </li> * </ul> * * @public * @name sap.ui.core.format.DateFormat.DateTimeWithTimezone.parse * @function * @since 1.99 */ // This method has a TypeScript specific overlay for a better return value documentation, // see 'src/sap.ui.core/.dtsgenrc' /** * Get a datetimeWithTimezone instance of the DateFormat, which can be used for formatting. * * @param {object} [oFormatOptions] An object which defines the format options * @param {sap.ui.core.date.CalendarWeekNumbering} [oFormatOptions.calendarWeekNumbering] since 1.108.0 specifies the calendar week numbering. * If specified, this overwrites <code>oFormatOptions.firstDayOfWeek</code> and <code>oFormatOptions.minimalDaysInFirstWeek</code>. * @param {int} [oFormatOptions.firstDayOfWeek] since 1.105.0 specifies the first day of the week starting with <code>0</code> (which is Sunday); if not defined, the value taken from the locale is used * @param {int} [oFormatOptions.minimalDaysInFirstWeek] since 1.105.0 minimal days at the beginning of the year which define the first calendar week; if not defined, the value taken from the locale is used * @param {string} [oFormatOptions.format] A string containing pattern symbols (e.g. "yMMMd" or "Hms") which will be converted into a pattern for the used locale that matches the wanted symbols best. * The symbols must be in canonical order, that is: Era (G), Year (y/Y), Quarter (q/Q), Month (M/L), Week (w), Day-Of-Week (E/e/c), Day (d), Hour (h/H/k/K/j/J), Minute (m), Second (s), Timezone (z/Z/v/V/O/X/x) * See http://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems * @param {string} [oFormatOptions.pattern] a datetime pattern in LDML format. It is not verified whether the pattern represents a full datetime. * @param {boolean} [oFormatOptions.showDate=true] Specifies if the date should be displayed. * It is ignored for formatting when an options pattern or a format are supplied. * @param {boolean} [oFormatOptions.showTime=true] Specifies if the time should be displayed. * It is ignored for formatting when an options pattern or a format are supplied. * @param {boolean} [oFormatOptions.showTimezone=true] Specifies if the timezone should be displayed. * It is ignored for formatting when an options pattern or a format are supplied. * @param {string} [oFormatOptions.style] Can be either 'short, 'medium', 'long' or 'full'. For datetime you can also define mixed styles, separated with a slash, where the first part is the date style and the second part is the time style (e.g. "medium/short"). If no pattern is given, a locale-dependent default datetime pattern of that style from the LocaleData class is used. * @param {boolean} [oFormatOptions.strictParsing] Whether to check by parsing if the value is a valid datetime * @param {boolean} [oFormatOptions.relative] Whether the date is formatted relatively to today's date if it is within the given day range, e.g. "today", "1 day ago", "in 5 days" * @param {int[]} [oFormatOptions.relativeRange] The day range used for relative formatting. If <code>oFormatOptions.relativeScale</code> is set to the default value 'day', the <code>relativeRange<code> is by default [-6, 6], which means that only the previous 6 and the following 6 days are formatted relatively. If <code>oFormatOptions.relativeScale</code> is set to 'auto', all dates are formatted relatively. * @param {string} [oFormatOptions.relativeScale] If 'auto' is set, a new relative time format is switched on for all Date/Time instances. The default value depends on <code>showDate</code> and <code>showTime</code> options. * @param {string} [oFormatOptions.relativeStyle="wide"] The style of the relative format. The valid values are "wide", "short", "narrow" * @param {sap.ui.core.CalendarType} [oFormatOptions.calendarType] The calendar type which is used to format and parse the date. This value is by default either set in the configuration or calculated based on the current locale. * @param {sap.ui.core.Locale} [oLocale] Locale to ask for locale-specific texts/settings * @ui5-omissible-params oFormatOptions * @throws {TypeError} If an invalid configuration was supplied, i.e. when the * <code>showDate</code>, <code>showTime</code>, and <code>showTimezone</code> format options * are all <code>false</code> * @return {sap.ui.core.format.DateFormat.DateTimeWithTimezone} dateTimeWithTimezone instance of the DateFormat * @static * @public * @since 1.99.0 * @throws {TypeError} If: * <ul> * <li>The <code>calendarWeekNumbering</code> format option has an unsupported value, or</li> * <li>only one of the <code>firstDayOfWeek</code> and <code>minimalDaysInFirstWeek</code> parameters was provided.</li> * </ul> */ DateFormat.getDateTimeWithTimezoneInstance = function (oFormatOptions, oLocale) { if (oFormatOptions && !(oFormatOptions instanceof Locale)) { /** @deprecated As of version 1.101.0 */ (function () { // do not modify the input format options oFormatOptions = Object.assign({}, oFormatOptions); // translate old showTimezone values (backward compatibility) if (typeof oFormatOptions.showTimezone === "string") { var sShowTimezone = oFormatOptions.showTimezone; if (oFormatOptions.showDate === undefined && oFormatOptions.showTime === undefined) { if (sShowTimezone === "Hide") { oFormatOptions.showTimezone = false; } else if (sShowTimezone === "Only") { oFormatOptions.showDate = false; oFormatOptions.showTime = false; } } oFormatOptions.showTimezone = sShowTimezone !== "Hide"; } })(); if (oFormatOptions.showDate === false && oFormatOptions.showTime === false && oFormatOptions.showTimezone === false) { throw new TypeError("Invalid Configuration. One of the following format options must be true: " + "showDate, showTime or showTimezone."); } } return this.createInstance(oFormatOptions, oLocale, DateFormat._getDateTimeWithTimezoneInfo(oFormatOptions || {})); }; /** * Get a time instance of the DateFormat, which can be used for formatting. * * @param {object} [oFormatOptions] Object which defines the format options * @param {sap.ui.core.date.CalendarWeekNumbering} [oFormatOptions.calendarWeekNumbering] since 1.108.0 specifies the calendar week numbering. * If specified, this overwrites <code>oFormatOptions.firstDayOfWeek</code> and <code>oFormatOptions.minimalDaysInFirstWeek</code>. * @param {int} [oFormatOptions.firstDayOfWeek] since 1.105.0 specifies the first day of the week starting with <code>0</code> (which is Sunday); if not defined, the value taken from the locale is used * @param {int} [oFormatOptions.minimalDaysInFirstWeek] since 1.105.0 minimal days at the beginning of the year which define the first calendar week; if not defined, the value taken from the locale is used * @param {string} [oFormatOptions.format] since 1.34.0 contains pattern symbols (e.g. "yMMMd" or "Hms") which will be converted into the pattern in the used locale, which matches the wanted symbols best. * The symbols must be in canonical order, that is: Era (G), Year (y/Y), Quarter (q/Q), Month (M/L), Week (w), Day-Of-Week (E/e/c), Day (d), Hour (h/H/k/K/j/J), Minute (m), Second (s), Timezone (z/Z/v/V/O/X/x) * See http://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems * @param {string} [oFormatOptions.pattern] a time pattern in LDML format. It is not verified whether the pattern only represents a time. * @param {string} [oFormatOptions.style] can be either 'short, 'medium', 'long' or 'full'. If no pattern is given, a locale dependent default time pattern of that style is used from the LocaleData class. * @param {boolean} [oFormatOptions.strictParsing] if true, by parsing it is checked if the value is a valid time * @param {boolean} [oFormatOptions.relative] if true, the date is formatted relatively to todays date if it is within the given day range, e.g. "today", "1 day ago", "in 5 days" * @param {int[]} [oFormatOptions.relativeRange] the day range used for relative formatting. If <code>oFormatOptions.relativeScale</code> is set to default value 'day', the relativeRange is by default [-6, 6], which means only the last 6 days, today and the next 6 days are formatted relatively. Otherwise when <code>oFormatOptions.relativeScale</code> is set to 'auto', all dates are formatted relatively. * @param {string} [oFormatOptions.relativeScale="day"] if 'auto' is set, new relative time format is switched on for all Date/Time Instances. The relative scale is chosen depending on the difference between the given date and now. * @param {string} [oFormatOptions.relativeStyle="wide"] since 1.32.10, 1.34.4 the style of the relative format. The valid values are "wide", "short", "narrow" * @param {boolean} [oFormatOptions.interval=false] since 1.48.0 if true, the {@link sap.ui.core.format.DateFormat#format format} method expects an array with two dates as the first argument and formats them as interval. Further interval "Jan 10, 2008 - Jan 12, 2008" will be formatted as "Jan 10-12, 2008" if the 'format' option is set with necessary symbols. * Otherwise the two given dates are formatted separately and concatenated with local dependent pattern. * @param {string} [oFormatOptions.intervalDelimiter] * Since 1.113.0, a delimiter for intervals. With a given interval delimiter a specific interval format is * created. <b>Example:</b> If <code>oFormatOptions.intervalDelimiter</code> is set to "...", an interval would be * given as "09:15 AM...11:45 AM". * <b>Note:</b> If this format option is set, the locale-specific interval notation is overruled, for example * "09:15 – 11:45 AM" becomes "9:15 AM...11:45 AM". * @param {boolean} [oFormatOptions.singleIntervalValue=false] Only relevant if oFormatOptions.interval is set to 'true'. This allows to pass an array with only one date object to the {@link sap.ui.core.format.DateFormat#format format} method. * @param {boolean} [oFormatOptions.UTC] if true, the time is formatted and parsed as UTC instead of the local timezone * @param {sap.ui.core.CalendarType} [oFormatOptions.calendarType] The calender type which is used to format and parse the date. This value is by default either set in configuration or calculated based on current locale. * @param {sap.ui.core.Locale} [oLocale] Locale to ask for locale specific texts/settings * @ui5-omissible-params oFormatOptions * @return {sap.ui.core.format.DateFormat} time instance of the DateFormat * @static * @public * @throws {TypeError} If: * <ul> * <li>The <code>calendarWeekNumbering</code> format option has an unsupported value, or</li> * <li>only one of the <code>firstDayOfWeek</code> and <code>minimalDaysInFirstWeek</code> parameters was provided.</li> * </ul> */ DateFormat.getTimeInstance = function (oFormatOptions, oLocale) { return this.createInstance(oFormatOptions, oLocale, this.oTimeInfo); }; /** * Create instance of the DateFormat. * * @param {object} [oFormatOptions] Object which defines the format options * @param {sap.ui.core.Locale} [oLocale] Locale to ask for locale specific texts/settings * @param {object} [oInfo] Info information common to all instances of the created "type", * e.g. default format options * @param {boolean} [bIsFallback=false] Whether this is a fallback format instance * @return {sap.ui.core.format.DateFormat} time instance of the DateFormat * @static * @private * @throws {TypeError} If: * <ul> * <li>The <code>calendarWeekNumbering</code> format option has an unsupported value, or</li> * <li>only one of the <code>firstDayOfWeek</code> and <code>minimalDaysInFirstWeek</code> parameters was provided.</li> * </ul> */ DateFormat.createInstance = function (oFormatOptions, oLocale, oInfo, bIsFallback) { var aFallbackFormatOptions, oFormat, sPattern; // Create an instance of the DateFormat oFormat = Object.create(this.prototype); // Handle optional parameters if (oFormatOptions instanceof Locale) { oLocale = oFormatOptions; oFormatOptions = undefined; } // Get Locale and LocaleData to use if (!oLocale) { oLocale = Configuration.getFormatSettings().getFormatLocale(); } oFormat.oLocale = oLocale; oFormat.oLocaleData = LocaleData.getInstance(oLocale); // Extend the default format options with custom format options and retrieve the pattern // from the LocaleData, in case it is not defined yet oFormat.oFormatOptions = extend({}, oInfo.oDefaultFormatOptions, oFormatOptions); // set unsupported properties to false/undefined if (oInfo.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) { oFormat.oFormatOptions.interval = false; oFormat.oFormatOptions.singleIntervalValue = false; oFormat.oFormatOptions.UTC = false; } else { oFormat.oFormatOptions.showTimezone = undefined; oFormat.oFormatOptions.showDate = undefined; oFormat.oFormatOptions.showTime = undefined; } // type cannot be changed and should be an instance property instead of a format option oFormat.type = oInfo.type; if (!oFormat.oFormatOptions.calendarType) { oFormat.oFormatOptions.calendarType = Configuration.getCalendarType(); } if (oFormat.oFormatOptions.firstDayOfWeek === undefined && oFormat.oFormatOptions.minimalDaysInFirstWeek !== undefined || oFormat.oFormatOptions.firstDayOfWeek !== undefined && oFormat.oFormatOptions.minimalDaysInFirstWeek === undefined) { throw new TypeError("Format options firstDayOfWeek and minimalDaysInFirstWeek need both to be set, but only one was provided."); } if (oFormat.oFormatOptions.calendarWeekNumbering && !Object.values(CalendarWeekNumbering).includes(oFormat.oFormatOptions.calendarWeekNumbering)) { throw new TypeError("Illegal format option calendarWeekNumbering: '" + oFormat.oFormatOptions.calendarWeekNumbering + "'"); } if (!oFormat.oFormatOptions.pattern) { if (oFormat.oFormatOptions.format) { oFormat.oFormatOptions.pattern = oFormat.oLocaleData.getCustomDateTimePattern(oFormat.oFormatOptions.format, oFormat.oFormatOptions.calendarType); } else { oFormat.oFormatOptions.pattern = oInfo.getPattern(oFormat.oLocaleData, oFormat.oFormatOptions.style, oFormat.oFormatOptions.calendarType); } } if (oFormat.oFormatOptions.interval) { var sSinglePattern, sDelimiter = oFormat.oFormatOptions.intervalDelimiter; if (oFormat.oFormatOptions.format) { // when 'format' option is set, generate the pattern based on the greatest difference oFormat.intervalPatterns = oFormat.oLocaleData.getCustomIntervalPattern(oFormat.oFormatOptions.format, null /*=no diff*/, oFormat.oFormatOptions.calendarType); // In case oFormat.intervalPatterns is a string, put the single string into array if (typeof oFormat.intervalPatterns === "string") { oFormat.intervalPatterns = [oFormat.intervalPatterns]; } sSinglePattern = oFormat.oLocaleData.getCustomDateTimePattern(oFormat.oFormatOptions.format, oFormat.oFormatOptions.calendarType); // Put the single date pattern, which is generated based on the oFormatOptions.format, into the array in // case the date interval is formatted as a single date oFormat.intervalPatterns.push(sSinglePattern); } else { sSinglePattern = oFormat.oFormatOptions.pattern; oFormat.intervalPatterns = [ // when 'format' option is not set, generate the combined interval pattern oFormat.oLocaleData.getCombinedIntervalPattern(oFormat.oFormatOptions.pattern, oFormat.oFormatOptions.calendarType), // Put the single date pattern into the array in case the date interval is formatted as a single date oFormat.oFormatOptions.pattern]; } oFormat.intervalPatterns.push(oFormat.oFormatOptions.pattern + " - " + oFormat.oFormatOptions.pattern); if (sDelimiter) { // use delimiter pattern as first choice sDelimiter = sDelimiter.replace(/'/g, "''"); sDelimiter = "'" + sDelimiter + "'"; oFormat.intervalPatterns.unshift(sSinglePattern + sDelimiter + sSinglePattern); } oFormat.intervalPatterns = Array.from(new Set(oFormat.intervalPatterns)); } // if the current format isn't a fallback format, create its fallback formats if (!bIsFallback) { aFallbackFormatOptions = oInfo.aFallbackFormatOptions; // Add two fallback patterns for locale-dependent short format without delimiters if (oInfo.bShortFallbackFormatOptions) { sPattern = oInfo.getPattern(oFormat.oLocaleData, "short"); // add the options of fallback formats without delimiters to the fallback options array aFallbackFormatOptions = aFallbackFormatOptions.concat(DateFormat._createFallbackOptionsWithoutDelimiter(sPattern)); } if (oFormat.oFormatOptions.pattern && oInfo.bPatternFallbackWithoutDelimiter) { // create options of fallback formats by removing delimiters from the given pattern // insert the new fallback format options to the front of the array aFallbackFormatOptions = DateFormat._createFallbackOptionsWithoutDelimiter(oFormat.oFormatOptions.pattern).concat(aFallbackFormatOptions); } // remove duplicate format options (e.g. fallback format with same pattern is not needed twice) aFallbackFormatOptions = aFallbackFormatOptions.reduce(function (aFallbacks, oOptions) { var aKeys = Object.keys(oOptions), bDuplicate = aFallbacks.some(function (oOptions0) { return Object.keys(oOptions0).length === aKeys.length && aKeys.every(function (sKey) { return oOptions0[sKey] === oOptions[sKey]; }); }); if (!bDuplicate) { aFallbacks.push(oOptions); } return aFallbacks; }, []); oFormat.aFallbackFormats = DateFormat._createFallbackFormat(aFallbackFormatOptions, oFormat.oFormatOptions.calendarType, oLocale, oInfo, oFormat.oFormatOptions); } oFormat.oRequiredParts = oInfo.oRequiredParts; oFormat.aRelativeScales = oInfo.aRelativeScales; oFormat.aRelativeParseScales = oInfo.aRelativeParseScales; oFormat.aIntervalCompareFields = oInfo.aIntervalCompareFields; oFormat.init(); return oFormat; }; /** * Initialize date format */ DateFormat.prototype.init = function () { var sCalendarType = this.oFormatOptions.calendarType; this.aMonthsAbbrev = this.oLocaleData._getMonthsWithAlternatives("abbreviated", sCalendarType); this.aMonthsWide = this.oLocaleData.getMonths("wide", sCalendarType); this.aMonthsNarrow = this.oLocaleData.getMonths("narrow", sCalendarType); this.aMonthsAbbrevSt = this.oLocaleData._getMonthsStandAloneWithAlternatives("abbreviated", sCalendarType); this.aMonthsWideSt = this.oLocaleData.getMonthsStandAlone("wide", sCalendarType); this.aMonthsNarrowSt = this.oLocaleData.getMonthsStandAlone("narrow", sCalendarType); this.aDaysAbbrev = this.oLocaleData.getDays("abbreviated", sCalendarType); this.aDaysWide = this.oLocaleData.getDays("wide", sCalendarType); this.aDaysNarrow = this.oLocaleData.getDays("narrow", sCalendarType); this.aDaysShort = this.oLocaleData.getDays("short", sCalendarType); this.aDaysAbbrevSt = this.oLocaleData.getDaysStandAlone("abbreviated", sCalendarType); this.aDaysWideSt = this.oLocaleData.getDaysStandAlone("wide", sCalendarType); this.aDaysNarrowSt = this.oLocaleData.getDaysStandAlone("narrow", sCalendarType); this.aDaysShortSt = this.oLocaleData.getDaysStandAlone("short", sCalendarType); this.aQuartersAbbrev = this.oLocaleData.getQuarters("abbreviated", sCalendarType); this.aQuartersWide = this.oLocaleData.getQuarters("wide", sCalendarType); this.aQuartersNarrow = this.oLocaleData.getQuarters("narrow", sCalendarType); this.aQuartersAbbrevSt = this.oLocaleData.getQuartersStandAlone("abbreviated", sCalendarType); this.aQuartersWideSt = this.oLocaleData.getQuartersStandAlone("wide", sCalendarType); this.aQuartersNarrowSt = this.oLocaleData.getQuartersStandAlone("narrow", sCalendarType); this.aErasNarrow = this.oLocaleData.getEras("narrow", sCalendarType); this.aErasAbbrev = this.oLocaleData.getEras("abbreviated", sCalendarType); this.aErasWide = this.oLocaleData.getEras("wide", sCalendarType); this.aDayPeriodsAbbrev = this.oLocaleData.getDayPeriods("abbreviated", sCalendarType); this.aDayPeriodsNarrow = this.oLocaleData.getDayPeriods("narrow", sCalendarType); this.aDayPeriodsWide = this.oLocaleData.getDayPeriods("wide", sCalendarType); this.oFlexibleDayPeriodsAbbrev = this.oLocaleData.getFlexibleDayPeriods("abbreviated", sCalendarType); this.oFlexibleDayPeriodsNarrow = this.oLocaleData.getFlexibleDayPeriods("narrow", sCalendarType); this.oFlexibleDayPeriodsWide = this.oLocaleData.getFlexibleDayPeriods("wide", sCalendarType); this.oFlexibleDayPeriodsAbbrevSt = this.oLocaleData.getFlexibleDayPeriodsStandAlone("abbreviated", sCalendarType); this.oFlexibleDayPeriodsNarrowSt = this.oLocaleData.getFlexibleDayPeriodsStandAlone("narrow", sCalendarType); this.oFlexibleDayPeriodsWideSt = this.oLocaleData.getFlexibleDayPeriodsStandAlone("wide", sCalendarType); this.aFormatArray = this.parseCldrDatePattern(this.oFormatOptions.pattern); this.sAllowedCharacters = this.getAllowedCharacters(this.aFormatArray); }; /** * Creates DateFormat instances based on the given format options. The created * instances are used as fallback formats of another DateFormat instances. * * @param {Object[]} aFallbackFormatOptions the options for creating the fallback DateFormat * @param {sap.ui.core.CalendarType} sCalendarType the type of the current calendarType * @param {sap.ui.core.Locale} oLocale Locale to ask for locale specific texts/settings * @param {Object} oInfo The default info object of the current date type * @param {object} oParentFormatOptions the format options, relevant are: interval, showDate, showTime and showTimezone * @return {sap.ui.core.DateFormat[]} an array of fallback DateFormat instances * @private */ DateFormat._createFallbackFormat = function (aFallbackFormatOptions, sCalendarType, oLocale, oInfo, oParentFormatOptions) { return aFallbackFormatOptions.map(function (oOptions) { // The format options within the aFallbackFormatOptions array are static // and shouldn't be manipulated. Hence, cloning each format option is required. var oFormatOptions = Object.assign({}, oOptions); // Pass the showDate, showTime and showTimezone format options to the fallback instance. oFormatOptions.showDate = oParentFormatOptions.showDate; oFormatOptions.showTime = oParentFormatOptions.showTime; oFormatOptions.showTimezone = oParentFormatOptions.showTimezone; // the timezone instance's fallback patterns depend on the showDate, showTime and // showTimezone format option which means they cannot be static, // therefore they are generated using the getTimezonePattern function if (typeof oInfo.getTimezonePattern === "function" && oFormatOptions.pattern) { oFormatOptions.pattern = oInfo.getTimezonePattern(oFormatOptions.pattern); } if (oParentFormatOptions.interval) { oFormatOptions.interval = true; } oFormatOptions.calendarType = sCalendarType; return DateFormat.createInstance(oFormatOptions, oLocale, oInfo, true); }); }; /** * Creates options for fallback DateFormat instance by removing all delimiters * from the given base pattern. * * @param {string} sBasePattern The pattern where the result pattern will be * generated by removing the delimiters * @return {Object} Format option object which contains the new pattern */ DateFormat._createFallbackOptionsWithoutDelimiter = function (sBasePattern) { var rNonDateFields = /[^dMyGU]/g, oDayReplace = { regex: /d+/g, replace: "dd" }, oMonthReplace = { regex: /M+/g, replace: "MM" }, oYearReplace = { regex: /[yU]+/g, replace: ["yyyy", "yy"] }; sBasePattern = sBasePattern.replace(rNonDateFields, ""); //remove all delimiters sBasePattern = sBasePattern.replace(oDayReplace.regex, oDayReplace.replace); // replace day entries with 2 digits sBasePattern = sBasePattern.replace(oMonthReplace.regex, oMonthReplace.replace); // replace month entries with 2 digits return oYearReplace.replace.map(function (sReplace) { return { pattern: sBasePattern.replace(oYearReplace.regex, sReplace), strictParsing: true }; }); }; var oParseHelper = { isNumber: function (iCharCode) { return iCharCode >= 48 && iCharCode <= 57; }, findNumbers: function (sValue, iMaxLength) { var iLength = 0; while (iLength < iMaxLength && this.isNumber(sValue.charCodeAt(iLength))) { iLength++; } return sValue.substr(0, iLength); }, /** * Returns if the given string starts with another given string ignoring the case. * * Takes the locale into account to ensure the characters are interpreted the right way. * * First, an exact case check is performed to remain backward compatible, then a case-insensitive check * based on the locale is done. * * When during the case conversion the length of the string changes we cannot safely match * it and return <code>false</code>. * * @param {string} sValue the value to check, e.g. "März 2013" * @param {string} sSubstring the string to compare it with, e.g. "MÄRZ" * @param {string} sLocale the locale, e.g. "de-DE" * @returns {boolean} true if the given string <code>sValue</code> starts with <code>sSubstring</code> * @private */ startsWithIgnoreCase: function (sValue, sSubstring, sLocale) { // exact case comparison (backward compatible) if (sValue.startsWith(sSubstring)) { return true; } try { // Use String#toLocaleUpperCase instead of String#toLocaleLowerCase because there // are known cases where an upper case letter has 2 lower case variants, e.g. Greek sigma. var sSubToLocaleUpperCase = sSubstring.toLocaleUpperCase(sLocale); var sValueUpperCase = sValue.toLocaleUpperCase(sLocale); // During the upper-case conversion there are cases where length changes, e.g. ß -> SS. // This cannot be properly determined without probing therefore we do not support this case. if (sSubToLocaleUpperCase.length !== sSubstring.length || sValueUpperCase.length !== sValue.length) { return false; } return sValueUpperCase.startsWith(sSubToLocaleUpperCase); } catch (e) { // Can fail for String#toLocaleUpperCase with an invalid locale // the API fails in the case with: Incorrect locale information provided return false; } }, /** * Finds the longest matching entry for which the following applies: * * <code>sValue</code> starts with