@ui5/webcomponents-localization 0.0.0-037d08c67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintignore +6 -0
- package/.eslintrc.cjs +3 -0
- package/.npsrc.json +3 -0
- package/CHANGELOG.md +2261 -0
- package/LICENSE.txt +201 -0
- package/README.md +51 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/Assets-fetch.d.ts +1 -0
- package/dist/Assets-fetch.js +3 -0
- package/dist/Assets-fetch.js.map +1 -0
- package/dist/Assets-node.d.ts +11 -0
- package/dist/Assets-node.js +12 -0
- package/dist/Assets-node.js.map +1 -0
- package/dist/Assets.d.ts +1 -0
- package/dist/Assets.js +3 -0
- package/dist/Assets.js.map +1 -0
- package/dist/CalendarUtils.d.ts +3 -0
- package/dist/CalendarUtils.js +6 -0
- package/dist/CalendarUtils.js.map +1 -0
- package/dist/DateFormat.d.ts +5 -0
- package/dist/DateFormat.js +7 -0
- package/dist/DateFormat.js.map +1 -0
- package/dist/LocaleData.d.ts +5 -0
- package/dist/LocaleData.js +7 -0
- package/dist/LocaleData.js.map +1 -0
- package/dist/NumberFormat.d.ts +5 -0
- package/dist/NumberFormat.js +7 -0
- package/dist/NumberFormat.js.map +1 -0
- package/dist/dates/CalendarDate.d.ts +42 -0
- package/dist/dates/CalendarDate.js +193 -0
- package/dist/dates/CalendarDate.js.map +1 -0
- package/dist/dates/ExtremeDates.d.ts +5 -0
- package/dist/dates/ExtremeDates.js +29 -0
- package/dist/dates/ExtremeDates.js.map +1 -0
- package/dist/dates/UI5Date.d.ts +5 -0
- package/dist/dates/UI5Date.js +7 -0
- package/dist/dates/UI5Date.js.map +1 -0
- package/dist/dates/UniversalDate.d.ts +47 -0
- package/dist/dates/UniversalDate.js +5 -0
- package/dist/dates/UniversalDate.js.map +1 -0
- package/dist/dates/convertMonthNumbersToMonthNames.d.ts +16 -0
- package/dist/dates/convertMonthNumbersToMonthNames.js +30 -0
- package/dist/dates/convertMonthNumbersToMonthNames.js.map +1 -0
- package/dist/dates/getDaysInMonth.d.ts +3 -0
- package/dist/dates/getDaysInMonth.js +10 -0
- package/dist/dates/getDaysInMonth.js.map +1 -0
- package/dist/dates/getRoundedTimestamp.d.ts +7 -0
- package/dist/dates/getRoundedTimestamp.js +15 -0
- package/dist/dates/getRoundedTimestamp.js.map +1 -0
- package/dist/dates/getTodayUTCTimestamp.d.ts +7 -0
- package/dist/dates/getTodayUTCTimestamp.js +9 -0
- package/dist/dates/getTodayUTCTimestamp.js.map +1 -0
- package/dist/dates/modifyDateBy.d.ts +14 -0
- package/dist/dates/modifyDateBy.js +55 -0
- package/dist/dates/modifyDateBy.js.map +1 -0
- package/dist/dates/transformDateToSecondaryType.d.ts +7 -0
- package/dist/dates/transformDateToSecondaryType.js +18 -0
- package/dist/dates/transformDateToSecondaryType.js.map +1 -0
- package/dist/features/calendar/Buddhist.d.ts +1 -0
- package/dist/features/calendar/Buddhist.js +2 -0
- package/dist/features/calendar/Buddhist.js.map +1 -0
- package/dist/features/calendar/Gregorian.d.ts +1 -0
- package/dist/features/calendar/Gregorian.js +2 -0
- package/dist/features/calendar/Gregorian.js.map +1 -0
- package/dist/features/calendar/Islamic.d.ts +1 -0
- package/dist/features/calendar/Islamic.js +2 -0
- package/dist/features/calendar/Islamic.js.map +1 -0
- package/dist/features/calendar/Japanese.d.ts +1 -0
- package/dist/features/calendar/Japanese.js +2 -0
- package/dist/features/calendar/Japanese.js.map +1 -0
- package/dist/features/calendar/Persian.d.ts +1 -0
- package/dist/features/calendar/Persian.js +2 -0
- package/dist/features/calendar/Persian.js.map +1 -0
- package/dist/generated/assets/cldr/Unicode-Data-Files-LICENSE.txt +27 -0
- package/dist/generated/assets/cldr/ar.json +7087 -0
- package/dist/generated/assets/cldr/ar_EG.json +7087 -0
- package/dist/generated/assets/cldr/ar_SA.json +7086 -0
- package/dist/generated/assets/cldr/bg.json +5981 -0
- package/dist/generated/assets/cldr/ca.json +6083 -0
- package/dist/generated/assets/cldr/cnr.json +6169 -0
- package/dist/generated/assets/cldr/cs.json +6709 -0
- package/dist/generated/assets/cldr/cy.json +6932 -0
- package/dist/generated/assets/cldr/da.json +5927 -0
- package/dist/generated/assets/cldr/de.json +6048 -0
- package/dist/generated/assets/cldr/de_AT.json +6049 -0
- package/dist/generated/assets/cldr/de_CH.json +6047 -0
- package/dist/generated/assets/cldr/el.json +5832 -0
- package/dist/generated/assets/cldr/el_CY.json +5832 -0
- package/dist/generated/assets/cldr/en.json +6044 -0
- package/dist/generated/assets/cldr/en_AU.json +6084 -0
- package/dist/generated/assets/cldr/en_GB.json +6075 -0
- package/dist/generated/assets/cldr/en_HK.json +6084 -0
- package/dist/generated/assets/cldr/en_IE.json +6075 -0
- package/dist/generated/assets/cldr/en_IN.json +6080 -0
- package/dist/generated/assets/cldr/en_NZ.json +6075 -0
- package/dist/generated/assets/cldr/en_PG.json +6076 -0
- package/dist/generated/assets/cldr/en_SG.json +6080 -0
- package/dist/generated/assets/cldr/en_ZA.json +6076 -0
- package/dist/generated/assets/cldr/es.json +6103 -0
- package/dist/generated/assets/cldr/es_AR.json +6106 -0
- package/dist/generated/assets/cldr/es_BO.json +6105 -0
- package/dist/generated/assets/cldr/es_CL.json +5998 -0
- package/dist/generated/assets/cldr/es_CO.json +5998 -0
- package/dist/generated/assets/cldr/es_MX.json +6107 -0
- package/dist/generated/assets/cldr/es_PE.json +5889 -0
- package/dist/generated/assets/cldr/es_UY.json +5891 -0
- package/dist/generated/assets/cldr/es_VE.json +5890 -0
- package/dist/generated/assets/cldr/et.json +6027 -0
- package/dist/generated/assets/cldr/fa.json +5950 -0
- package/dist/generated/assets/cldr/fi.json +6195 -0
- package/dist/generated/assets/cldr/fr.json +5997 -0
- package/dist/generated/assets/cldr/fr_BE.json +5997 -0
- package/dist/generated/assets/cldr/fr_CA.json +5991 -0
- package/dist/generated/assets/cldr/fr_CH.json +6015 -0
- package/dist/generated/assets/cldr/fr_LU.json +5997 -0
- package/dist/generated/assets/cldr/he.json +6541 -0
- package/dist/generated/assets/cldr/hi.json +5859 -0
- package/dist/generated/assets/cldr/hr.json +6196 -0
- package/dist/generated/assets/cldr/hu.json +5945 -0
- package/dist/generated/assets/cldr/id.json +5730 -0
- package/dist/generated/assets/cldr/it.json +5986 -0
- package/dist/generated/assets/cldr/it_CH.json +5986 -0
- package/dist/generated/assets/cldr/ja.json +5889 -0
- package/dist/generated/assets/cldr/kk.json +5939 -0
- package/dist/generated/assets/cldr/ko.json +5770 -0
- package/dist/generated/assets/cldr/lt.json +6578 -0
- package/dist/generated/assets/cldr/lv.json +6114 -0
- package/dist/generated/assets/cldr/mk.json +6045 -0
- package/dist/generated/assets/cldr/ms.json +5564 -0
- package/dist/generated/assets/cldr/nb.json +6035 -0
- package/dist/generated/assets/cldr/nl.json +6202 -0
- package/dist/generated/assets/cldr/nl_BE.json +6202 -0
- package/dist/generated/assets/cldr/pl.json +6589 -0
- package/dist/generated/assets/cldr/pt.json +6115 -0
- package/dist/generated/assets/cldr/pt_PT.json +6180 -0
- package/dist/generated/assets/cldr/ro.json +6200 -0
- package/dist/generated/assets/cldr/ru.json +6503 -0
- package/dist/generated/assets/cldr/ru_UA.json +6503 -0
- package/dist/generated/assets/cldr/sk.json +6432 -0
- package/dist/generated/assets/cldr/sl.json +6444 -0
- package/dist/generated/assets/cldr/sr.json +6241 -0
- package/dist/generated/assets/cldr/sr_Latn.json +6226 -0
- package/dist/generated/assets/cldr/sv.json +6076 -0
- package/dist/generated/assets/cldr/th.json +5875 -0
- package/dist/generated/assets/cldr/tr.json +6094 -0
- package/dist/generated/assets/cldr/uk.json +6454 -0
- package/dist/generated/assets/cldr/vi.json +5669 -0
- package/dist/generated/assets/cldr/zh_CN.json +5717 -0
- package/dist/generated/assets/cldr/zh_HK.json +5726 -0
- package/dist/generated/assets/cldr/zh_SG.json +5726 -0
- package/dist/generated/assets/cldr/zh_TW.json +5793 -0
- package/dist/generated/json-imports/LocaleData-fetch.d.ts +1 -0
- package/dist/generated/json-imports/LocaleData-fetch.js +93 -0
- package/dist/generated/json-imports/LocaleData-fetch.js.map +1 -0
- package/dist/generated/json-imports/LocaleData-node.d.ts +1 -0
- package/dist/generated/json-imports/LocaleData-node.js +93 -0
- package/dist/generated/json-imports/LocaleData-node.js.map +1 -0
- package/dist/generated/json-imports/LocaleData.d.ts +1 -0
- package/dist/generated/json-imports/LocaleData.js +93 -0
- package/dist/generated/json-imports/LocaleData.js.map +1 -0
- package/dist/getCachedLocaleDataInstance.d.ts +4 -0
- package/dist/getCachedLocaleDataInstance.js +10 -0
- package/dist/getCachedLocaleDataInstance.js.map +1 -0
- package/dist/locale/getLocaleData.d.ts +11 -0
- package/dist/locale/getLocaleData.js +23 -0
- package/dist/locale/getLocaleData.js.map +1 -0
- package/dist/sap/base/Event.js +59 -0
- package/dist/sap/base/Eventing.js +146 -0
- package/dist/sap/base/Log.js +3 -0
- package/dist/sap/base/assert.js +34 -0
- package/dist/sap/base/config/MemoryConfigurationProvider.js +20 -0
- package/dist/sap/base/config.js +17 -0
- package/dist/sap/base/i18n/Formatting.d.ts +8 -0
- package/dist/sap/base/i18n/Formatting.js +11 -0
- package/dist/sap/base/i18n/Formatting.js.map +1 -0
- package/dist/sap/base/i18n/LanguageTag.js +173 -0
- package/dist/sap/base/i18n/Localization.d.ts +4 -0
- package/dist/sap/base/i18n/Localization.js +12 -0
- package/dist/sap/base/i18n/Localization.js.map +1 -0
- package/dist/sap/base/i18n/date/CalendarType.js +43 -0
- package/dist/sap/base/i18n/date/CalendarWeekNumbering.js +105 -0
- package/dist/sap/base/i18n/date/TimezoneUtils.js +319 -0
- package/dist/sap/base/strings/camelize.js +30 -0
- package/dist/sap/base/strings/formatMessage.js +93 -0
- package/dist/sap/base/util/LoaderExtensions.d.ts +4 -0
- package/dist/sap/base/util/LoaderExtensions.js +14 -0
- package/dist/sap/base/util/LoaderExtensions.js.map +1 -0
- package/dist/sap/base/util/ObjectPath.d.ts +4 -0
- package/dist/sap/base/util/ObjectPath.js +6 -0
- package/dist/sap/base/util/ObjectPath.js.map +1 -0
- package/dist/sap/base/util/Version.js +157 -0
- package/dist/sap/base/util/_merge.js +89 -0
- package/dist/sap/base/util/array/uniqueSort.js +41 -0
- package/dist/sap/base/util/deepClone.js +102 -0
- package/dist/sap/base/util/deepEqual.js +83 -0
- package/dist/sap/base/util/extend.js +61 -0
- package/dist/sap/base/util/isEmptyObject.js +34 -0
- package/dist/sap/base/util/isPlainObject.js +52 -0
- package/dist/sap/base/util/now.js +28 -0
- package/dist/sap/base/util/resolveReference.js +3 -0
- package/dist/sap/base/util/uid.js +27 -0
- package/dist/sap/ui/base/DataType.js +657 -0
- package/dist/sap/ui/base/Interface.js +72 -0
- package/dist/sap/ui/base/Metadata.js +483 -0
- package/dist/sap/ui/base/Object.js +300 -0
- package/dist/sap/ui/core/CalendarType.js +24 -0
- package/dist/sap/ui/core/Configuration.d.ts +17 -0
- package/dist/sap/ui/core/Configuration.js +23 -0
- package/dist/sap/ui/core/Configuration.js.map +1 -0
- package/dist/sap/ui/core/Core.d.ts +25 -0
- package/dist/sap/ui/core/Core.js +13 -0
- package/dist/sap/ui/core/Core.js.map +1 -0
- package/dist/sap/ui/core/FormatSettings.d.ts +9 -0
- package/dist/sap/ui/core/FormatSettings.js +12 -0
- package/dist/sap/ui/core/FormatSettings.js.map +1 -0
- package/dist/sap/ui/core/Locale.js +194 -0
- package/dist/sap/ui/core/LocaleData.js +2717 -0
- package/dist/sap/ui/core/Supportability.js +5 -0
- package/dist/sap/ui/core/Theming.js +539 -0
- package/dist/sap/ui/core/date/Buddhist.js +196 -0
- package/dist/sap/ui/core/date/CalendarUtils.js +65 -0
- package/dist/sap/ui/core/date/CalendarWeekNumbering.js +30 -0
- package/dist/sap/ui/core/date/Gregorian.js +32 -0
- package/dist/sap/ui/core/date/Islamic.js +367 -0
- package/dist/sap/ui/core/date/Japanese.js +257 -0
- package/dist/sap/ui/core/date/Persian.js +394 -0
- package/dist/sap/ui/core/date/UI5Date.js +991 -0
- package/dist/sap/ui/core/date/UniversalDate.js +1324 -0
- package/dist/sap/ui/core/date/_Calendars.js +22 -0
- package/dist/sap/ui/core/format/DateFormat.js +3310 -0
- package/dist/sap/ui/core/format/NumberFormat.js +2835 -0
- package/dist/sap/ui/core/format/TimezoneUtil.js +24 -0
- package/package-scripts.cjs +35 -0
- package/package.json +46 -0
- package/tsconfig.json +24 -0
- package/used-modules.txt +52 -0
|
@@ -0,0 +1,3310 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* OpenUI5
|
|
3
|
+
* (c) Copyright 2009-2024 SAP SE or an SAP affiliate company.
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
|
|
5
|
+
*/
|
|
6
|
+
// Provides class sap.ui.core.format.DateFormat
|
|
7
|
+
import Log from "../../../base/Log.js";
|
|
8
|
+
import formatMessage from "../../../base/strings/formatMessage.js";
|
|
9
|
+
import deepEqual from "../../../base/util/deepEqual.js";
|
|
10
|
+
import extend from "../../../base/util/extend.js";
|
|
11
|
+
import CalendarType from "../CalendarType.js";
|
|
12
|
+
import Configuration from "../Configuration.js";
|
|
13
|
+
import Core from "../Core.js";
|
|
14
|
+
import Locale from "../Locale.js";
|
|
15
|
+
import LocaleData from "../LocaleData.js";
|
|
16
|
+
import Supportability from "../Supportability.js";
|
|
17
|
+
import CalendarUtils from "../date/CalendarUtils.js";
|
|
18
|
+
import CalendarWeekNumbering from "../date/CalendarWeekNumbering.js";
|
|
19
|
+
import UI5Date from "../date/UI5Date.js";
|
|
20
|
+
import UniversalDate from "../date/UniversalDate.js";
|
|
21
|
+
import TimezoneUtil from "./TimezoneUtil.js";
|
|
22
|
+
/**
|
|
23
|
+
* Constructor for DateFormat - must not be used:
|
|
24
|
+
* <ul>
|
|
25
|
+
* <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>
|
|
26
|
+
* <li>To get a {@link sap.ui.core.format.DateFormat.DateTimeWithTimezone} instance, please use {@link sap.ui.core.format.DateFormat.getDateTimeWithTimezoneInstance}</li>
|
|
27
|
+
* </ul>
|
|
28
|
+
*
|
|
29
|
+
* @class
|
|
30
|
+
* The DateFormat is a static class for formatting and parsing single date and time values or date and time intervals according
|
|
31
|
+
* to a set of format options.
|
|
32
|
+
*
|
|
33
|
+
* Important:
|
|
34
|
+
* Every Date is converted with the timezone taken from {@link sap.ui.core.Configuration#getTimezone}.
|
|
35
|
+
* The timezone falls back to the browser's local timezone.
|
|
36
|
+
*
|
|
37
|
+
* Supported format options are pattern based on Unicode LDML Date Format notation. Please note that only a subset of the LDML date symbols
|
|
38
|
+
* is supported.
|
|
39
|
+
* If no pattern is specified a default pattern according to the locale settings is used.
|
|
40
|
+
*
|
|
41
|
+
* Documentation links:
|
|
42
|
+
* <ul>
|
|
43
|
+
* <li>{@link topic:91f2eba36f4d1014b6dd926db0e91070 Date Format}</li>
|
|
44
|
+
* <li>{@link http://unicode.org/reports/tr35/tr35-dates.html#Date_Field_Symbol_Table}</li>
|
|
45
|
+
* </ul>
|
|
46
|
+
*
|
|
47
|
+
* @public
|
|
48
|
+
* @hideconstructor
|
|
49
|
+
* @alias sap.ui.core.format.DateFormat
|
|
50
|
+
*/
|
|
51
|
+
var DateFormat = function () {
|
|
52
|
+
// Do not use the constructor
|
|
53
|
+
throw new Error();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Internal enumeration to differentiate DateFormat types
|
|
58
|
+
*/
|
|
59
|
+
var mDateFormatTypes = {
|
|
60
|
+
DATE: "date",
|
|
61
|
+
TIME: "time",
|
|
62
|
+
DATETIME: "datetime",
|
|
63
|
+
DATETIME_WITH_TIMEZONE: "datetimeWithTimezone"
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Cache for parsed CLDR DatePattern
|
|
67
|
+
var mCldrDatePattern = {};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Timezone parameter type check
|
|
71
|
+
*
|
|
72
|
+
* @param {string} sTimezone The timezone to check
|
|
73
|
+
* @throws {TypeError} Thrown if the parameter <code>sTimezone</code> is provided and has the wrong type.
|
|
74
|
+
*/
|
|
75
|
+
var checkTimezoneParameterType = function (sTimezone) {
|
|
76
|
+
if (typeof sTimezone !== "string" && !(sTimezone instanceof String) && sTimezone != null) {
|
|
77
|
+
throw new TypeError("The given timezone must be a string.");
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
DateFormat.oDateInfo = {
|
|
81
|
+
type: mDateFormatTypes.DATE,
|
|
82
|
+
oDefaultFormatOptions: {
|
|
83
|
+
style: "medium",
|
|
84
|
+
relativeScale: "day",
|
|
85
|
+
relativeStyle: "wide"
|
|
86
|
+
},
|
|
87
|
+
aFallbackFormatOptions: [{
|
|
88
|
+
style: "short"
|
|
89
|
+
}, {
|
|
90
|
+
style: "medium"
|
|
91
|
+
}, {
|
|
92
|
+
pattern: "yyyy-MM-dd"
|
|
93
|
+
}, {
|
|
94
|
+
pattern: "yyyyMMdd",
|
|
95
|
+
strictParsing: true
|
|
96
|
+
}],
|
|
97
|
+
bShortFallbackFormatOptions: true,
|
|
98
|
+
bPatternFallbackWithoutDelimiter: true,
|
|
99
|
+
getPattern: function (oLocaleData, sStyle, sCalendarType) {
|
|
100
|
+
return oLocaleData.getDatePattern(sStyle, sCalendarType);
|
|
101
|
+
},
|
|
102
|
+
oRequiredParts: {
|
|
103
|
+
"text": true,
|
|
104
|
+
"year": true,
|
|
105
|
+
"weekYear": true,
|
|
106
|
+
"month": true,
|
|
107
|
+
"day": true
|
|
108
|
+
},
|
|
109
|
+
aRelativeScales: ["year", "month", "week", "day"],
|
|
110
|
+
aRelativeParseScales: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"],
|
|
111
|
+
aIntervalCompareFields: ["Era", "FullYear", "Quarter", "Month", "Week", "Date"]
|
|
112
|
+
};
|
|
113
|
+
DateFormat.oDateTimeInfo = {
|
|
114
|
+
type: mDateFormatTypes.DATETIME,
|
|
115
|
+
oDefaultFormatOptions: {
|
|
116
|
+
style: "medium",
|
|
117
|
+
relativeScale: "auto",
|
|
118
|
+
relativeStyle: "wide"
|
|
119
|
+
},
|
|
120
|
+
aFallbackFormatOptions: [{
|
|
121
|
+
style: "short"
|
|
122
|
+
}, {
|
|
123
|
+
style: "medium"
|
|
124
|
+
}, {
|
|
125
|
+
pattern: "yyyy-MM-dd'T'HH:mm:ss"
|
|
126
|
+
}, {
|
|
127
|
+
pattern: "yyyyMMdd HHmmss"
|
|
128
|
+
}],
|
|
129
|
+
getPattern: function (oLocaleData, sStyle, sCalendarType) {
|
|
130
|
+
// If style is mixed ("medium/short") split it and pass both parts separately
|
|
131
|
+
var iSlashIndex = sStyle.indexOf("/");
|
|
132
|
+
if (iSlashIndex > 0) {
|
|
133
|
+
return oLocaleData.getCombinedDateTimePattern(sStyle.substr(0, iSlashIndex), sStyle.substr(iSlashIndex + 1), sCalendarType);
|
|
134
|
+
} else {
|
|
135
|
+
return oLocaleData.getCombinedDateTimePattern(sStyle, sStyle, sCalendarType);
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
oRequiredParts: {
|
|
139
|
+
"text": true,
|
|
140
|
+
"year": true,
|
|
141
|
+
"weekYear": true,
|
|
142
|
+
"month": true,
|
|
143
|
+
"day": true,
|
|
144
|
+
"hour0_23": true,
|
|
145
|
+
"hour1_24": true,
|
|
146
|
+
"hour0_11": true,
|
|
147
|
+
"hour1_12": true
|
|
148
|
+
},
|
|
149
|
+
aRelativeScales: ["year", "month", "week", "day", "hour", "minute", "second"],
|
|
150
|
+
aRelativeParseScales: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"],
|
|
151
|
+
aIntervalCompareFields: ["Era", "FullYear", "Quarter", "Month", "Week", "Date", "DayPeriod", "Hours", "Minutes", "Seconds"]
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Retrieves info object for timezone instance
|
|
156
|
+
*
|
|
157
|
+
* @param {object} oFormatOptions the format options, relevant are: showDate, showTime and showTimezone
|
|
158
|
+
* @returns {object} info object
|
|
159
|
+
* @private
|
|
160
|
+
*/
|
|
161
|
+
DateFormat._getDateTimeWithTimezoneInfo = function (oFormatOptions) {
|
|
162
|
+
var bShowDate = oFormatOptions.showDate === undefined || oFormatOptions.showDate;
|
|
163
|
+
var bShowTime = oFormatOptions.showTime === undefined || oFormatOptions.showTime;
|
|
164
|
+
var bShowTimezone = oFormatOptions.showTimezone === undefined || oFormatOptions.showTimezone;
|
|
165
|
+
var oBaselineType = DateFormat.oDateTimeInfo;
|
|
166
|
+
if (bShowDate && !bShowTime) {
|
|
167
|
+
oBaselineType = DateFormat.oDateInfo;
|
|
168
|
+
} else if (!bShowDate && bShowTime) {
|
|
169
|
+
oBaselineType = DateFormat.oTimeInfo;
|
|
170
|
+
}
|
|
171
|
+
return Object.assign({}, oBaselineType, {
|
|
172
|
+
type: mDateFormatTypes.DATETIME_WITH_TIMEZONE,
|
|
173
|
+
// This function is used to transform the pattern of the fallbackFormatOptions to a timezone pattern.
|
|
174
|
+
getTimezonePattern: function (sPattern) {
|
|
175
|
+
if (!bShowDate && !bShowTime && bShowTimezone) {
|
|
176
|
+
return "VV";
|
|
177
|
+
} else if (!bShowTimezone) {
|
|
178
|
+
return sPattern;
|
|
179
|
+
} else {
|
|
180
|
+
return sPattern + " VV";
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
getPattern: function (oLocaleData, sStyle, sCalendarType) {
|
|
184
|
+
if (!bShowDate && !bShowTime && bShowTimezone) {
|
|
185
|
+
return "VV";
|
|
186
|
+
}
|
|
187
|
+
if (!bShowTimezone) {
|
|
188
|
+
return oBaselineType.getPattern(oLocaleData, sStyle, sCalendarType);
|
|
189
|
+
}
|
|
190
|
+
var sPattern = oBaselineType.getPattern(oLocaleData, sStyle, sCalendarType);
|
|
191
|
+
return oLocaleData.applyTimezonePattern(sPattern);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
};
|
|
195
|
+
DateFormat.oTimeInfo = {
|
|
196
|
+
type: mDateFormatTypes.TIME,
|
|
197
|
+
oDefaultFormatOptions: {
|
|
198
|
+
style: "medium",
|
|
199
|
+
relativeScale: "auto",
|
|
200
|
+
relativeStyle: "wide"
|
|
201
|
+
},
|
|
202
|
+
aFallbackFormatOptions: [{
|
|
203
|
+
style: "short"
|
|
204
|
+
}, {
|
|
205
|
+
style: "medium"
|
|
206
|
+
}, {
|
|
207
|
+
pattern: "HH:mm:ss"
|
|
208
|
+
}, {
|
|
209
|
+
pattern: "HHmmss"
|
|
210
|
+
}],
|
|
211
|
+
getPattern: function (oLocaleData, sStyle, sCalendarType) {
|
|
212
|
+
return oLocaleData.getTimePattern(sStyle, sCalendarType);
|
|
213
|
+
},
|
|
214
|
+
oRequiredParts: {
|
|
215
|
+
"text": true,
|
|
216
|
+
"hour0_23": true,
|
|
217
|
+
"hour1_24": true,
|
|
218
|
+
"hour0_11": true,
|
|
219
|
+
"hour1_12": true
|
|
220
|
+
},
|
|
221
|
+
aRelativeScales: ["hour", "minute", "second"],
|
|
222
|
+
aRelativeParseScales: ["year", "quarter", "month", "week", "day", "hour", "minute", "second"],
|
|
223
|
+
aIntervalCompareFields: ["DayPeriod", "Hours", "Minutes", "Seconds"]
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @see sap.ui.core.format.DateFormat.getDateInstance
|
|
228
|
+
*/
|
|
229
|
+
DateFormat.getInstance = function (oFormatOptions, oLocale) {
|
|
230
|
+
return this.getDateInstance(oFormatOptions, oLocale);
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get a date instance of the DateFormat, which can be used for formatting.
|
|
235
|
+
*
|
|
236
|
+
* @param {object} [oFormatOptions] Object which defines the format options
|
|
237
|
+
* @param {sap.ui.core.date.CalendarWeekNumbering} [oFormatOptions.calendarWeekNumbering] since 1.108.0 specifies the calendar week numbering.
|
|
238
|
+
* If specified, this overwrites <code>oFormatOptions.firstDayOfWeek</code> and <code>oFormatOptions.minimalDaysInFirstWeek</code>.
|
|
239
|
+
* @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
|
|
240
|
+
* @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
|
|
241
|
+
* @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.
|
|
242
|
+
* 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)
|
|
243
|
+
* See {@link http://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems}
|
|
244
|
+
* @param {string} [oFormatOptions.pattern] a data pattern in LDML format. It is not verified whether the pattern represents only a date.
|
|
245
|
+
* @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.
|
|
246
|
+
* @param {boolean} [oFormatOptions.strictParsing] if true, by parsing it is checked if the value is a valid date
|
|
247
|
+
* @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"
|
|
248
|
+
* @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.
|
|
249
|
+
* @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.
|
|
250
|
+
* @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"
|
|
251
|
+
* @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.
|
|
252
|
+
* Otherwise the two given dates are formatted separately and concatenated with local dependent pattern.
|
|
253
|
+
* @param {string} [oFormatOptions.intervalDelimiter]
|
|
254
|
+
* Since 1.113.0, a delimiter for intervals. With a given interval delimiter a specific interval format is
|
|
255
|
+
* created. <b>Example:</b> If <code>oFormatOptions.intervalDelimiter</code> is set to "...", an interval would be
|
|
256
|
+
* given as "Jan 10, 2008...Feb 12, 2008".
|
|
257
|
+
* <b>Note:</b> If this format option is set, the locale-specific interval notation is overruled, for example
|
|
258
|
+
* "Jan 10 – Feb 12, 2008" becomes "Jan 10, 2008...Feb 12, 2008".
|
|
259
|
+
* @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.
|
|
260
|
+
* @param {boolean} [oFormatOptions.UTC] if true, the date is formatted and parsed as UTC instead of the local timezone
|
|
261
|
+
* @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.
|
|
262
|
+
* @param {sap.ui.core.Locale} [oLocale] Locale to ask for locale specific texts/settings
|
|
263
|
+
* @ui5-omissible-params oFormatOptions
|
|
264
|
+
* @return {sap.ui.core.format.DateFormat} date instance of the DateFormat
|
|
265
|
+
* @static
|
|
266
|
+
* @public
|
|
267
|
+
* @throws {TypeError} If:
|
|
268
|
+
* <ul>
|
|
269
|
+
* <li>The <code>calendarWeekNumbering</code> format option has an unsupported value, or</li>
|
|
270
|
+
* <li>only one of the <code>firstDayOfWeek</code> and <code>minimalDaysInFirstWeek</code> parameters was provided.</li>
|
|
271
|
+
* </ul>
|
|
272
|
+
*/
|
|
273
|
+
DateFormat.getDateInstance = function (oFormatOptions, oLocale) {
|
|
274
|
+
return this.createInstance(oFormatOptions, oLocale, this.oDateInfo);
|
|
275
|
+
};
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get a datetime instance of the DateFormat, which can be used for formatting.
|
|
279
|
+
*
|
|
280
|
+
* @param {object} [oFormatOptions] Object which defines the format options
|
|
281
|
+
* @param {sap.ui.core.date.CalendarWeekNumbering} [oFormatOptions.calendarWeekNumbering] since 1.108.0 specifies the calendar week numbering.
|
|
282
|
+
* If specified, this overwrites <code>oFormatOptions.firstDayOfWeek</code> and <code>oFormatOptions.minimalDaysInFirstWeek</code>.
|
|
283
|
+
* @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
|
|
284
|
+
* @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
|
|
285
|
+
* @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.
|
|
286
|
+
* 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)
|
|
287
|
+
* See http://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems
|
|
288
|
+
* @param {string} [oFormatOptions.pattern] a datetime pattern in LDML format. It is not verified whether the pattern represents a full datetime.
|
|
289
|
+
* @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.
|
|
290
|
+
* @param {boolean} [oFormatOptions.strictParsing] if true, by parsing it is checked if the value is a valid datetime
|
|
291
|
+
* @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"
|
|
292
|
+
* @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.
|
|
293
|
+
* @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.
|
|
294
|
+
* @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"
|
|
295
|
+
* @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.
|
|
296
|
+
* Otherwise the two given dates are formatted separately and concatenated with local dependent pattern.
|
|
297
|
+
* @param {string} [oFormatOptions.intervalDelimiter]
|
|
298
|
+
* Since 1.113.0, a delimiter for intervals. With a given interval delimiter a specific interval format is
|
|
299
|
+
* created. <b>Example:</b> If <code>oFormatOptions.intervalDelimiter</code> is set to "...", an interval would be
|
|
300
|
+
* given as "Jan 10, 2008, 9:15:00 AM...Jan 10, 2008, 11:45:00 AM".
|
|
301
|
+
* <b>Note:</b> If this format option is set, the locale-specific interval notation is overruled, for example
|
|
302
|
+
* "Jan 10, 2008, 9:15 – 11:45 AM" becomes "Jan 10, 2008, 9:15 AM...Jan 10, 2008, 11:45 AM".
|
|
303
|
+
* @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.
|
|
304
|
+
* @param {boolean} [oFormatOptions.UTC] if true, the date is formatted and parsed as UTC instead of the local timezone
|
|
305
|
+
* @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.
|
|
306
|
+
* @param {sap.ui.core.Locale} [oLocale] Locale to ask for locale specific texts/settings
|
|
307
|
+
* @ui5-omissible-params oFormatOptions
|
|
308
|
+
* @return {sap.ui.core.format.DateFormat} datetime instance of the DateFormat
|
|
309
|
+
* @static
|
|
310
|
+
* @public
|
|
311
|
+
* @throws {TypeError} If:
|
|
312
|
+
* <ul>
|
|
313
|
+
* <li>The <code>calendarWeekNumbering</code> format option has an unsupported value, or</li>
|
|
314
|
+
* <li>only one of the <code>firstDayOfWeek</code> and <code>minimalDaysInFirstWeek</code> parameters was provided.</li>
|
|
315
|
+
* </ul>
|
|
316
|
+
*/
|
|
317
|
+
DateFormat.getDateTimeInstance = function (oFormatOptions, oLocale) {
|
|
318
|
+
return this.createInstance(oFormatOptions, oLocale, this.oDateTimeInfo);
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Interface for a timezone-specific DateFormat, which is able to format and parse a date
|
|
323
|
+
* based on a given timezone. The timezone is used to convert the given date, and also for
|
|
324
|
+
* timezone-related pattern symbols. The timezone is an IANA timezone ID, e.g. "America/New_York".
|
|
325
|
+
*
|
|
326
|
+
* @see sap.ui.core.format.DateFormat
|
|
327
|
+
*
|
|
328
|
+
* @author SAP SE
|
|
329
|
+
* @since 1.99
|
|
330
|
+
* @interface
|
|
331
|
+
* @name sap.ui.core.format.DateFormat.DateTimeWithTimezone
|
|
332
|
+
* @public
|
|
333
|
+
*/
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Format a date object to a string according to the given timezone and format options.
|
|
337
|
+
*
|
|
338
|
+
* @example <caption>Format option showTimezone: true (default)</caption>
|
|
339
|
+
* var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z");
|
|
340
|
+
*
|
|
341
|
+
* DateFormat.getDateTimeWithTimezoneInstance().format(oDate, "Europe/Berlin");
|
|
342
|
+
* // output: "Dec 24, 2021, 2:37:00 PM Europe, Berlin"
|
|
343
|
+
*
|
|
344
|
+
* DateFormat.getDateTimeWithTimezoneInstance().format(oDate, "America/New_York");
|
|
345
|
+
* // output: "Dec 24, 2021, 8:37:00 AM Americas, New York"
|
|
346
|
+
*
|
|
347
|
+
* @example <caption>Format option showTimezone: false</caption>
|
|
348
|
+
* var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z");
|
|
349
|
+
* DateFormat.getDateTimeWithTimezoneInstance({showTimezone: false}).format(oDate, "America/New_York");
|
|
350
|
+
* // output: "Dec 24, 2021, 8:37:00 AM"
|
|
351
|
+
*
|
|
352
|
+
* @example <caption>Format option showDate: false and showTime:false</caption>
|
|
353
|
+
* var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z");
|
|
354
|
+
* DateFormat.getDateTimeWithTimezoneInstance({showDate: false, showTime: false}).format(oDate, "America/New_York");
|
|
355
|
+
* // output: "Americas, New York"
|
|
356
|
+
*
|
|
357
|
+
* @param {Date} oJSDate The date to format
|
|
358
|
+
* @param {string} [sTimezone] The IANA timezone ID in which the date will be calculated and
|
|
359
|
+
* formatted e.g. "America/New_York". If the parameter is omitted, <code>null</code> or an empty string, the timezone
|
|
360
|
+
* will be taken from {@link sap.ui.core.Configuration#getTimezone}. For an invalid IANA timezone ID, an empty string will be returned.
|
|
361
|
+
* @throws {TypeError} Thrown if the parameter <code>sTimezone</code> is provided and has the wrong type.
|
|
362
|
+
* @return {string} the formatted output value. If an invalid date or timezone is given, an empty string is returned.
|
|
363
|
+
* @name sap.ui.core.format.DateFormat.DateTimeWithTimezone.format
|
|
364
|
+
* @function
|
|
365
|
+
* @public
|
|
366
|
+
* @since 1.99
|
|
367
|
+
*/
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Parse a string which is formatted according to the given format options to an array
|
|
371
|
+
* containing a date object and the timezone.
|
|
372
|
+
*
|
|
373
|
+
* @example <caption>Format option showTimezone: true (default)</caption>
|
|
374
|
+
* var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z");
|
|
375
|
+
*
|
|
376
|
+
* DateFormat.getDateTimeWithTimezoneInstance().parse("Dec 24, 2021, 2:37:00 PM Europe, Berlin", "Europe/Berlin");
|
|
377
|
+
* // output: [oDate, "Europe/Berlin"]
|
|
378
|
+
*
|
|
379
|
+
* DateFormat.getDateTimeWithTimezoneInstance().parse("Dec 24, 2021, 8:37:00 AM Americas, New York", "America/New_York");
|
|
380
|
+
* // output: [oDate, "America/New_York"]
|
|
381
|
+
*
|
|
382
|
+
* @example <caption>Format option showTimezone: false</caption>
|
|
383
|
+
* var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z");
|
|
384
|
+
* DateFormat.getDateTimeWithTimezoneInstance({showTimezone: false}).parse("Dec 24, 2021, 8:37:00 AM", "America/New_York");
|
|
385
|
+
* // output: [oDate, undefined]
|
|
386
|
+
*
|
|
387
|
+
* @example <caption>Format option showDate: false and showTime: false</caption>
|
|
388
|
+
* DateFormat.getDateTimeWithTimezoneInstance({showDate: false, showTime: false}).parse("Americas, New York", "America/New_York");
|
|
389
|
+
* // output: [undefined, "America/New_York"]
|
|
390
|
+
*
|
|
391
|
+
* @param {string} sValue the string containing a formatted date/time value
|
|
392
|
+
* @param {string} [sTimezone] The IANA timezone ID which should be used to convert the date
|
|
393
|
+
* e.g. "America/New_York". If the parameter is omitted, <code>null</code> or an empty string, the timezone will be taken
|
|
394
|
+
* from {@link sap.ui.core.Configuration#getTimezone}. For an invalid IANA timezone ID, <code>null</code> will be returned.
|
|
395
|
+
* @param {boolean} [bStrict] Whether to be strict with regards to the value ranges of date fields,
|
|
396
|
+
* e.g. for a month pattern of <code>MM</code> and a value range of [1-12]
|
|
397
|
+
* <code>strict</code> ensures that the value is within the range;
|
|
398
|
+
* if it is larger than <code>12</code> it cannot be parsed and <code>null</code> is returned
|
|
399
|
+
* @throws {TypeError} Thrown if one of the following applies:
|
|
400
|
+
* <ul>
|
|
401
|
+
* <li>the <code>sTimezone</code> parameter is provided and has the wrong type</li>
|
|
402
|
+
* <li>only the time is shown (<code>showDate</code> is <code>false</code>), or only the
|
|
403
|
+
* date is shown (<code>showTime</code> is <code>false</code>)</li>
|
|
404
|
+
* </ul>
|
|
405
|
+
* @return {Array} the parsed values
|
|
406
|
+
* <ul>
|
|
407
|
+
* <li>An array containing datetime and timezone depending on the showDate, showTime and showTimezone options
|
|
408
|
+
* <ul>
|
|
409
|
+
* <li>(Default): [Date, string], e.g.
|
|
410
|
+
* [UI5Date.getInstance("2021-11-13T13:22:33Z"), "America/New_York"]</li>
|
|
411
|
+
* <li><code>showTimezone: false</code>: [Date, undefined], e.g.
|
|
412
|
+
* [UI5Date.getInstance("2021-11-13T13:22:33Z"), undefined]</li>
|
|
413
|
+
* <li><code>showDate: false, showTime: false</code>: [undefined, string], e.g.
|
|
414
|
+
* [undefined, "America/New_York"]</li>
|
|
415
|
+
* </ul>
|
|
416
|
+
* </li>
|
|
417
|
+
* </ul>
|
|
418
|
+
*
|
|
419
|
+
* @public
|
|
420
|
+
* @name sap.ui.core.format.DateFormat.DateTimeWithTimezone.parse
|
|
421
|
+
* @function
|
|
422
|
+
* @since 1.99
|
|
423
|
+
*/
|
|
424
|
+
// This method has a TypeScript specific overlay for a better return value documentation,
|
|
425
|
+
// see 'src/sap.ui.core/.dtsgenrc'
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Get a datetimeWithTimezone instance of the DateFormat, which can be used for formatting.
|
|
429
|
+
*
|
|
430
|
+
* @param {object} [oFormatOptions] An object which defines the format options
|
|
431
|
+
* @param {sap.ui.core.date.CalendarWeekNumbering} [oFormatOptions.calendarWeekNumbering] since 1.108.0 specifies the calendar week numbering.
|
|
432
|
+
* If specified, this overwrites <code>oFormatOptions.firstDayOfWeek</code> and <code>oFormatOptions.minimalDaysInFirstWeek</code>.
|
|
433
|
+
* @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
|
|
434
|
+
* @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
|
|
435
|
+
* @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.
|
|
436
|
+
* 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)
|
|
437
|
+
* See http://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems
|
|
438
|
+
* @param {string} [oFormatOptions.pattern] a datetime pattern in LDML format. It is not verified whether the pattern represents a full datetime.
|
|
439
|
+
* @param {boolean} [oFormatOptions.showDate=true] Specifies if the date should be displayed.
|
|
440
|
+
* It is ignored for formatting when an options pattern or a format are supplied.
|
|
441
|
+
* @param {boolean} [oFormatOptions.showTime=true] Specifies if the time should be displayed.
|
|
442
|
+
* It is ignored for formatting when an options pattern or a format are supplied.
|
|
443
|
+
* @param {boolean} [oFormatOptions.showTimezone=true] Specifies if the timezone should be displayed.
|
|
444
|
+
* It is ignored for formatting when an options pattern or a format are supplied.
|
|
445
|
+
* @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.
|
|
446
|
+
* @param {boolean} [oFormatOptions.strictParsing] Whether to check by parsing if the value is a valid datetime
|
|
447
|
+
* @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"
|
|
448
|
+
* @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.
|
|
449
|
+
* @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.
|
|
450
|
+
* @param {string} [oFormatOptions.relativeStyle="wide"] The style of the relative format. The valid values are "wide", "short", "narrow"
|
|
451
|
+
* @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.
|
|
452
|
+
* @param {sap.ui.core.Locale} [oLocale] Locale to ask for locale-specific texts/settings
|
|
453
|
+
* @ui5-omissible-params oFormatOptions
|
|
454
|
+
* @throws {TypeError} If an invalid configuration was supplied, i.e. when the
|
|
455
|
+
* <code>showDate</code>, <code>showTime</code>, and <code>showTimezone</code> format options
|
|
456
|
+
* are all <code>false</code>
|
|
457
|
+
* @return {sap.ui.core.format.DateFormat.DateTimeWithTimezone} dateTimeWithTimezone instance of the DateFormat
|
|
458
|
+
* @static
|
|
459
|
+
* @public
|
|
460
|
+
* @since 1.99.0
|
|
461
|
+
* @throws {TypeError} If:
|
|
462
|
+
* <ul>
|
|
463
|
+
* <li>The <code>calendarWeekNumbering</code> format option has an unsupported value, or</li>
|
|
464
|
+
* <li>only one of the <code>firstDayOfWeek</code> and <code>minimalDaysInFirstWeek</code> parameters was provided.</li>
|
|
465
|
+
* </ul>
|
|
466
|
+
*/
|
|
467
|
+
DateFormat.getDateTimeWithTimezoneInstance = function (oFormatOptions, oLocale) {
|
|
468
|
+
if (oFormatOptions && !(oFormatOptions instanceof Locale)) {
|
|
469
|
+
/** @deprecated As of version 1.101.0 */
|
|
470
|
+
(function () {
|
|
471
|
+
// do not modify the input format options
|
|
472
|
+
oFormatOptions = Object.assign({}, oFormatOptions);
|
|
473
|
+
// translate old showTimezone values (backward compatibility)
|
|
474
|
+
if (typeof oFormatOptions.showTimezone === "string") {
|
|
475
|
+
var sShowTimezone = oFormatOptions.showTimezone;
|
|
476
|
+
if (oFormatOptions.showDate === undefined && oFormatOptions.showTime === undefined) {
|
|
477
|
+
if (sShowTimezone === "Hide") {
|
|
478
|
+
oFormatOptions.showTimezone = false;
|
|
479
|
+
} else if (sShowTimezone === "Only") {
|
|
480
|
+
oFormatOptions.showDate = false;
|
|
481
|
+
oFormatOptions.showTime = false;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
oFormatOptions.showTimezone = sShowTimezone !== "Hide";
|
|
485
|
+
}
|
|
486
|
+
})();
|
|
487
|
+
if (oFormatOptions.showDate === false && oFormatOptions.showTime === false && oFormatOptions.showTimezone === false) {
|
|
488
|
+
throw new TypeError("Invalid Configuration. One of the following format options must be true: " + "showDate, showTime or showTimezone.");
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return this.createInstance(oFormatOptions, oLocale, DateFormat._getDateTimeWithTimezoneInfo(oFormatOptions || {}));
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Get a time instance of the DateFormat, which can be used for formatting.
|
|
496
|
+
*
|
|
497
|
+
* @param {object} [oFormatOptions] Object which defines the format options
|
|
498
|
+
* @param {sap.ui.core.date.CalendarWeekNumbering} [oFormatOptions.calendarWeekNumbering] since 1.108.0 specifies the calendar week numbering.
|
|
499
|
+
* If specified, this overwrites <code>oFormatOptions.firstDayOfWeek</code> and <code>oFormatOptions.minimalDaysInFirstWeek</code>.
|
|
500
|
+
* @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
|
|
501
|
+
* @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
|
|
502
|
+
* @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.
|
|
503
|
+
* 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)
|
|
504
|
+
* See http://unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems
|
|
505
|
+
* @param {string} [oFormatOptions.pattern] a time pattern in LDML format. It is not verified whether the pattern only represents a time.
|
|
506
|
+
* @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.
|
|
507
|
+
* @param {boolean} [oFormatOptions.strictParsing] if true, by parsing it is checked if the value is a valid time
|
|
508
|
+
* @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"
|
|
509
|
+
* @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.
|
|
510
|
+
* @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.
|
|
511
|
+
* @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"
|
|
512
|
+
* @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.
|
|
513
|
+
* Otherwise the two given dates are formatted separately and concatenated with local dependent pattern.
|
|
514
|
+
* @param {string} [oFormatOptions.intervalDelimiter]
|
|
515
|
+
* Since 1.113.0, a delimiter for intervals. With a given interval delimiter a specific interval format is
|
|
516
|
+
* created. <b>Example:</b> If <code>oFormatOptions.intervalDelimiter</code> is set to "...", an interval would be
|
|
517
|
+
* given as "09:15 AM...11:45 AM".
|
|
518
|
+
* <b>Note:</b> If this format option is set, the locale-specific interval notation is overruled, for example
|
|
519
|
+
* "09:15 – 11:45 AM" becomes "9:15 AM...11:45 AM".
|
|
520
|
+
* @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.
|
|
521
|
+
* @param {boolean} [oFormatOptions.UTC] if true, the time is formatted and parsed as UTC instead of the local timezone
|
|
522
|
+
* @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.
|
|
523
|
+
* @param {sap.ui.core.Locale} [oLocale] Locale to ask for locale specific texts/settings
|
|
524
|
+
* @ui5-omissible-params oFormatOptions
|
|
525
|
+
* @return {sap.ui.core.format.DateFormat} time instance of the DateFormat
|
|
526
|
+
* @static
|
|
527
|
+
* @public
|
|
528
|
+
* @throws {TypeError} If:
|
|
529
|
+
* <ul>
|
|
530
|
+
* <li>The <code>calendarWeekNumbering</code> format option has an unsupported value, or</li>
|
|
531
|
+
* <li>only one of the <code>firstDayOfWeek</code> and <code>minimalDaysInFirstWeek</code> parameters was provided.</li>
|
|
532
|
+
* </ul>
|
|
533
|
+
*/
|
|
534
|
+
DateFormat.getTimeInstance = function (oFormatOptions, oLocale) {
|
|
535
|
+
return this.createInstance(oFormatOptions, oLocale, this.oTimeInfo);
|
|
536
|
+
};
|
|
537
|
+
|
|
538
|
+
/**
|
|
539
|
+
* Create instance of the DateFormat.
|
|
540
|
+
*
|
|
541
|
+
* @param {object} [oFormatOptions] Object which defines the format options
|
|
542
|
+
* @param {sap.ui.core.Locale} [oLocale] Locale to ask for locale specific texts/settings
|
|
543
|
+
* @param {object} [oInfo] Info information common to all instances of the created "type",
|
|
544
|
+
* e.g. default format options
|
|
545
|
+
* @param {boolean} [bIsFallback=false] Whether this is a fallback format instance
|
|
546
|
+
* @return {sap.ui.core.format.DateFormat} time instance of the DateFormat
|
|
547
|
+
* @static
|
|
548
|
+
* @private
|
|
549
|
+
* @throws {TypeError} If:
|
|
550
|
+
* <ul>
|
|
551
|
+
* <li>The <code>calendarWeekNumbering</code> format option has an unsupported value, or</li>
|
|
552
|
+
* <li>only one of the <code>firstDayOfWeek</code> and <code>minimalDaysInFirstWeek</code> parameters was provided.</li>
|
|
553
|
+
* </ul>
|
|
554
|
+
*/
|
|
555
|
+
DateFormat.createInstance = function (oFormatOptions, oLocale, oInfo, bIsFallback) {
|
|
556
|
+
var aFallbackFormatOptions, oFormat, sPattern;
|
|
557
|
+
|
|
558
|
+
// Create an instance of the DateFormat
|
|
559
|
+
oFormat = Object.create(this.prototype);
|
|
560
|
+
|
|
561
|
+
// Handle optional parameters
|
|
562
|
+
if (oFormatOptions instanceof Locale) {
|
|
563
|
+
oLocale = oFormatOptions;
|
|
564
|
+
oFormatOptions = undefined;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Get Locale and LocaleData to use
|
|
568
|
+
if (!oLocale) {
|
|
569
|
+
oLocale = Configuration.getFormatSettings().getFormatLocale();
|
|
570
|
+
}
|
|
571
|
+
oFormat.oLocale = oLocale;
|
|
572
|
+
oFormat.oLocaleData = LocaleData.getInstance(oLocale);
|
|
573
|
+
|
|
574
|
+
// Extend the default format options with custom format options and retrieve the pattern
|
|
575
|
+
// from the LocaleData, in case it is not defined yet
|
|
576
|
+
oFormat.oFormatOptions = extend({}, oInfo.oDefaultFormatOptions, oFormatOptions);
|
|
577
|
+
|
|
578
|
+
// set unsupported properties to false/undefined
|
|
579
|
+
if (oInfo.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
|
|
580
|
+
oFormat.oFormatOptions.interval = false;
|
|
581
|
+
oFormat.oFormatOptions.singleIntervalValue = false;
|
|
582
|
+
oFormat.oFormatOptions.UTC = false;
|
|
583
|
+
} else {
|
|
584
|
+
oFormat.oFormatOptions.showTimezone = undefined;
|
|
585
|
+
oFormat.oFormatOptions.showDate = undefined;
|
|
586
|
+
oFormat.oFormatOptions.showTime = undefined;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
// type cannot be changed and should be an instance property instead of a format option
|
|
590
|
+
oFormat.type = oInfo.type;
|
|
591
|
+
if (!oFormat.oFormatOptions.calendarType) {
|
|
592
|
+
oFormat.oFormatOptions.calendarType = Configuration.getCalendarType();
|
|
593
|
+
}
|
|
594
|
+
if (oFormat.oFormatOptions.firstDayOfWeek === undefined && oFormat.oFormatOptions.minimalDaysInFirstWeek !== undefined || oFormat.oFormatOptions.firstDayOfWeek !== undefined && oFormat.oFormatOptions.minimalDaysInFirstWeek === undefined) {
|
|
595
|
+
throw new TypeError("Format options firstDayOfWeek and minimalDaysInFirstWeek need both to be set, but only one was provided.");
|
|
596
|
+
}
|
|
597
|
+
if (oFormat.oFormatOptions.calendarWeekNumbering && !Object.values(CalendarWeekNumbering).includes(oFormat.oFormatOptions.calendarWeekNumbering)) {
|
|
598
|
+
throw new TypeError("Illegal format option calendarWeekNumbering: '" + oFormat.oFormatOptions.calendarWeekNumbering + "'");
|
|
599
|
+
}
|
|
600
|
+
if (!oFormat.oFormatOptions.pattern) {
|
|
601
|
+
if (oFormat.oFormatOptions.format) {
|
|
602
|
+
oFormat.oFormatOptions.pattern = oFormat.oLocaleData.getCustomDateTimePattern(oFormat.oFormatOptions.format, oFormat.oFormatOptions.calendarType);
|
|
603
|
+
} else {
|
|
604
|
+
oFormat.oFormatOptions.pattern = oInfo.getPattern(oFormat.oLocaleData, oFormat.oFormatOptions.style, oFormat.oFormatOptions.calendarType);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if (oFormat.oFormatOptions.interval) {
|
|
608
|
+
var sSinglePattern,
|
|
609
|
+
sDelimiter = oFormat.oFormatOptions.intervalDelimiter;
|
|
610
|
+
if (oFormat.oFormatOptions.format) {
|
|
611
|
+
// when 'format' option is set, generate the pattern based on the greatest difference
|
|
612
|
+
oFormat.intervalPatterns = oFormat.oLocaleData.getCustomIntervalPattern(oFormat.oFormatOptions.format, null /*=no diff*/, oFormat.oFormatOptions.calendarType);
|
|
613
|
+
|
|
614
|
+
// In case oFormat.intervalPatterns is a string, put the single string into array
|
|
615
|
+
if (typeof oFormat.intervalPatterns === "string") {
|
|
616
|
+
oFormat.intervalPatterns = [oFormat.intervalPatterns];
|
|
617
|
+
}
|
|
618
|
+
sSinglePattern = oFormat.oLocaleData.getCustomDateTimePattern(oFormat.oFormatOptions.format, oFormat.oFormatOptions.calendarType);
|
|
619
|
+
// Put the single date pattern, which is generated based on the oFormatOptions.format, into the array in
|
|
620
|
+
// case the date interval is formatted as a single date
|
|
621
|
+
oFormat.intervalPatterns.push(sSinglePattern);
|
|
622
|
+
} else {
|
|
623
|
+
sSinglePattern = oFormat.oFormatOptions.pattern;
|
|
624
|
+
oFormat.intervalPatterns = [
|
|
625
|
+
// when 'format' option is not set, generate the combined interval pattern
|
|
626
|
+
oFormat.oLocaleData.getCombinedIntervalPattern(oFormat.oFormatOptions.pattern, oFormat.oFormatOptions.calendarType),
|
|
627
|
+
// Put the single date pattern into the array in case the date interval is formatted as a single date
|
|
628
|
+
oFormat.oFormatOptions.pattern];
|
|
629
|
+
}
|
|
630
|
+
oFormat.intervalPatterns.push(oFormat.oFormatOptions.pattern + " - " + oFormat.oFormatOptions.pattern);
|
|
631
|
+
if (sDelimiter) {
|
|
632
|
+
// use delimiter pattern as first choice
|
|
633
|
+
sDelimiter = sDelimiter.replace(/'/g, "''");
|
|
634
|
+
sDelimiter = "'" + sDelimiter + "'";
|
|
635
|
+
oFormat.intervalPatterns.unshift(sSinglePattern + sDelimiter + sSinglePattern);
|
|
636
|
+
}
|
|
637
|
+
oFormat.intervalPatterns = Array.from(new Set(oFormat.intervalPatterns));
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// if the current format isn't a fallback format, create its fallback formats
|
|
641
|
+
if (!bIsFallback) {
|
|
642
|
+
aFallbackFormatOptions = oInfo.aFallbackFormatOptions;
|
|
643
|
+
// Add two fallback patterns for locale-dependent short format without delimiters
|
|
644
|
+
if (oInfo.bShortFallbackFormatOptions) {
|
|
645
|
+
sPattern = oInfo.getPattern(oFormat.oLocaleData, "short");
|
|
646
|
+
// add the options of fallback formats without delimiters to the fallback options array
|
|
647
|
+
aFallbackFormatOptions = aFallbackFormatOptions.concat(DateFormat._createFallbackOptionsWithoutDelimiter(sPattern));
|
|
648
|
+
}
|
|
649
|
+
if (oFormat.oFormatOptions.pattern && oInfo.bPatternFallbackWithoutDelimiter) {
|
|
650
|
+
// create options of fallback formats by removing delimiters from the given pattern
|
|
651
|
+
// insert the new fallback format options to the front of the array
|
|
652
|
+
aFallbackFormatOptions = DateFormat._createFallbackOptionsWithoutDelimiter(oFormat.oFormatOptions.pattern).concat(aFallbackFormatOptions);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// remove duplicate format options (e.g. fallback format with same pattern is not needed twice)
|
|
656
|
+
aFallbackFormatOptions = aFallbackFormatOptions.reduce(function (aFallbacks, oOptions) {
|
|
657
|
+
var aKeys = Object.keys(oOptions),
|
|
658
|
+
bDuplicate = aFallbacks.some(function (oOptions0) {
|
|
659
|
+
return Object.keys(oOptions0).length === aKeys.length && aKeys.every(function (sKey) {
|
|
660
|
+
return oOptions0[sKey] === oOptions[sKey];
|
|
661
|
+
});
|
|
662
|
+
});
|
|
663
|
+
if (!bDuplicate) {
|
|
664
|
+
aFallbacks.push(oOptions);
|
|
665
|
+
}
|
|
666
|
+
return aFallbacks;
|
|
667
|
+
}, []);
|
|
668
|
+
oFormat.aFallbackFormats = DateFormat._createFallbackFormat(aFallbackFormatOptions, oFormat.oFormatOptions.calendarType, oLocale, oInfo, oFormat.oFormatOptions);
|
|
669
|
+
}
|
|
670
|
+
oFormat.oRequiredParts = oInfo.oRequiredParts;
|
|
671
|
+
oFormat.aRelativeScales = oInfo.aRelativeScales;
|
|
672
|
+
oFormat.aRelativeParseScales = oInfo.aRelativeParseScales;
|
|
673
|
+
oFormat.aIntervalCompareFields = oInfo.aIntervalCompareFields;
|
|
674
|
+
oFormat.init();
|
|
675
|
+
return oFormat;
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Initialize date format
|
|
680
|
+
*/
|
|
681
|
+
DateFormat.prototype.init = function () {
|
|
682
|
+
var sCalendarType = this.oFormatOptions.calendarType;
|
|
683
|
+
this.aMonthsAbbrev = this.oLocaleData._getMonthsWithAlternatives("abbreviated", sCalendarType);
|
|
684
|
+
this.aMonthsWide = this.oLocaleData.getMonths("wide", sCalendarType);
|
|
685
|
+
this.aMonthsNarrow = this.oLocaleData.getMonths("narrow", sCalendarType);
|
|
686
|
+
this.aMonthsAbbrevSt = this.oLocaleData._getMonthsStandAloneWithAlternatives("abbreviated", sCalendarType);
|
|
687
|
+
this.aMonthsWideSt = this.oLocaleData.getMonthsStandAlone("wide", sCalendarType);
|
|
688
|
+
this.aMonthsNarrowSt = this.oLocaleData.getMonthsStandAlone("narrow", sCalendarType);
|
|
689
|
+
this.aDaysAbbrev = this.oLocaleData.getDays("abbreviated", sCalendarType);
|
|
690
|
+
this.aDaysWide = this.oLocaleData.getDays("wide", sCalendarType);
|
|
691
|
+
this.aDaysNarrow = this.oLocaleData.getDays("narrow", sCalendarType);
|
|
692
|
+
this.aDaysShort = this.oLocaleData.getDays("short", sCalendarType);
|
|
693
|
+
this.aDaysAbbrevSt = this.oLocaleData.getDaysStandAlone("abbreviated", sCalendarType);
|
|
694
|
+
this.aDaysWideSt = this.oLocaleData.getDaysStandAlone("wide", sCalendarType);
|
|
695
|
+
this.aDaysNarrowSt = this.oLocaleData.getDaysStandAlone("narrow", sCalendarType);
|
|
696
|
+
this.aDaysShortSt = this.oLocaleData.getDaysStandAlone("short", sCalendarType);
|
|
697
|
+
this.aQuartersAbbrev = this.oLocaleData.getQuarters("abbreviated", sCalendarType);
|
|
698
|
+
this.aQuartersWide = this.oLocaleData.getQuarters("wide", sCalendarType);
|
|
699
|
+
this.aQuartersNarrow = this.oLocaleData.getQuarters("narrow", sCalendarType);
|
|
700
|
+
this.aQuartersAbbrevSt = this.oLocaleData.getQuartersStandAlone("abbreviated", sCalendarType);
|
|
701
|
+
this.aQuartersWideSt = this.oLocaleData.getQuartersStandAlone("wide", sCalendarType);
|
|
702
|
+
this.aQuartersNarrowSt = this.oLocaleData.getQuartersStandAlone("narrow", sCalendarType);
|
|
703
|
+
this.aErasNarrow = this.oLocaleData.getEras("narrow", sCalendarType);
|
|
704
|
+
this.aErasAbbrev = this.oLocaleData.getEras("abbreviated", sCalendarType);
|
|
705
|
+
this.aErasWide = this.oLocaleData.getEras("wide", sCalendarType);
|
|
706
|
+
this.aDayPeriodsAbbrev = this.oLocaleData.getDayPeriods("abbreviated", sCalendarType);
|
|
707
|
+
this.aDayPeriodsNarrow = this.oLocaleData.getDayPeriods("narrow", sCalendarType);
|
|
708
|
+
this.aDayPeriodsWide = this.oLocaleData.getDayPeriods("wide", sCalendarType);
|
|
709
|
+
this.oFlexibleDayPeriodsAbbrev = this.oLocaleData.getFlexibleDayPeriods("abbreviated", sCalendarType);
|
|
710
|
+
this.oFlexibleDayPeriodsNarrow = this.oLocaleData.getFlexibleDayPeriods("narrow", sCalendarType);
|
|
711
|
+
this.oFlexibleDayPeriodsWide = this.oLocaleData.getFlexibleDayPeriods("wide", sCalendarType);
|
|
712
|
+
this.oFlexibleDayPeriodsAbbrevSt = this.oLocaleData.getFlexibleDayPeriodsStandAlone("abbreviated", sCalendarType);
|
|
713
|
+
this.oFlexibleDayPeriodsNarrowSt = this.oLocaleData.getFlexibleDayPeriodsStandAlone("narrow", sCalendarType);
|
|
714
|
+
this.oFlexibleDayPeriodsWideSt = this.oLocaleData.getFlexibleDayPeriodsStandAlone("wide", sCalendarType);
|
|
715
|
+
this.aFormatArray = this.parseCldrDatePattern(this.oFormatOptions.pattern);
|
|
716
|
+
this.sAllowedCharacters = this.getAllowedCharacters(this.aFormatArray);
|
|
717
|
+
};
|
|
718
|
+
|
|
719
|
+
/**
|
|
720
|
+
* Creates DateFormat instances based on the given format options. The created
|
|
721
|
+
* instances are used as fallback formats of another DateFormat instances.
|
|
722
|
+
*
|
|
723
|
+
* @param {Object[]} aFallbackFormatOptions the options for creating the fallback DateFormat
|
|
724
|
+
* @param {sap.ui.core.CalendarType} sCalendarType the type of the current calendarType
|
|
725
|
+
* @param {sap.ui.core.Locale} oLocale Locale to ask for locale specific texts/settings
|
|
726
|
+
* @param {Object} oInfo The default info object of the current date type
|
|
727
|
+
* @param {object} oParentFormatOptions the format options, relevant are: interval, showDate, showTime and showTimezone
|
|
728
|
+
* @return {sap.ui.core.DateFormat[]} an array of fallback DateFormat instances
|
|
729
|
+
* @private
|
|
730
|
+
*/
|
|
731
|
+
DateFormat._createFallbackFormat = function (aFallbackFormatOptions, sCalendarType, oLocale, oInfo, oParentFormatOptions) {
|
|
732
|
+
return aFallbackFormatOptions.map(function (oOptions) {
|
|
733
|
+
// The format options within the aFallbackFormatOptions array are static
|
|
734
|
+
// and shouldn't be manipulated. Hence, cloning each format option is required.
|
|
735
|
+
var oFormatOptions = Object.assign({}, oOptions);
|
|
736
|
+
|
|
737
|
+
// Pass the showDate, showTime and showTimezone format options to the fallback instance.
|
|
738
|
+
oFormatOptions.showDate = oParentFormatOptions.showDate;
|
|
739
|
+
oFormatOptions.showTime = oParentFormatOptions.showTime;
|
|
740
|
+
oFormatOptions.showTimezone = oParentFormatOptions.showTimezone;
|
|
741
|
+
|
|
742
|
+
// the timezone instance's fallback patterns depend on the showDate, showTime and
|
|
743
|
+
// showTimezone format option which means they cannot be static,
|
|
744
|
+
// therefore they are generated using the getTimezonePattern function
|
|
745
|
+
if (typeof oInfo.getTimezonePattern === "function" && oFormatOptions.pattern) {
|
|
746
|
+
oFormatOptions.pattern = oInfo.getTimezonePattern(oFormatOptions.pattern);
|
|
747
|
+
}
|
|
748
|
+
if (oParentFormatOptions.interval) {
|
|
749
|
+
oFormatOptions.interval = true;
|
|
750
|
+
}
|
|
751
|
+
oFormatOptions.calendarType = sCalendarType;
|
|
752
|
+
return DateFormat.createInstance(oFormatOptions, oLocale, oInfo, true);
|
|
753
|
+
});
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
/**
|
|
757
|
+
* Creates options for fallback DateFormat instance by removing all delimiters
|
|
758
|
+
* from the given base pattern.
|
|
759
|
+
*
|
|
760
|
+
* @param {string} sBasePattern The pattern where the result pattern will be
|
|
761
|
+
* generated by removing the delimiters
|
|
762
|
+
* @return {Object} Format option object which contains the new pattern
|
|
763
|
+
*/
|
|
764
|
+
DateFormat._createFallbackOptionsWithoutDelimiter = function (sBasePattern) {
|
|
765
|
+
var rNonDateFields = /[^dMyGU]/g,
|
|
766
|
+
oDayReplace = {
|
|
767
|
+
regex: /d+/g,
|
|
768
|
+
replace: "dd"
|
|
769
|
+
},
|
|
770
|
+
oMonthReplace = {
|
|
771
|
+
regex: /M+/g,
|
|
772
|
+
replace: "MM"
|
|
773
|
+
},
|
|
774
|
+
oYearReplace = {
|
|
775
|
+
regex: /[yU]+/g,
|
|
776
|
+
replace: ["yyyy", "yy"]
|
|
777
|
+
};
|
|
778
|
+
sBasePattern = sBasePattern.replace(rNonDateFields, ""); //remove all delimiters
|
|
779
|
+
sBasePattern = sBasePattern.replace(oDayReplace.regex, oDayReplace.replace); // replace day entries with 2 digits
|
|
780
|
+
sBasePattern = sBasePattern.replace(oMonthReplace.regex, oMonthReplace.replace); // replace month entries with 2 digits
|
|
781
|
+
|
|
782
|
+
return oYearReplace.replace.map(function (sReplace) {
|
|
783
|
+
return {
|
|
784
|
+
pattern: sBasePattern.replace(oYearReplace.regex, sReplace),
|
|
785
|
+
strictParsing: true
|
|
786
|
+
};
|
|
787
|
+
});
|
|
788
|
+
};
|
|
789
|
+
var oParseHelper = {
|
|
790
|
+
isNumber: function (iCharCode) {
|
|
791
|
+
return iCharCode >= 48 && iCharCode <= 57;
|
|
792
|
+
},
|
|
793
|
+
findNumbers: function (sValue, iMaxLength) {
|
|
794
|
+
var iLength = 0;
|
|
795
|
+
while (iLength < iMaxLength && this.isNumber(sValue.charCodeAt(iLength))) {
|
|
796
|
+
iLength++;
|
|
797
|
+
}
|
|
798
|
+
return sValue.substr(0, iLength);
|
|
799
|
+
},
|
|
800
|
+
/**
|
|
801
|
+
* Returns if the given string starts with another given string ignoring the case.
|
|
802
|
+
*
|
|
803
|
+
* Takes the locale into account to ensure the characters are interpreted the right way.
|
|
804
|
+
*
|
|
805
|
+
* First, an exact case check is performed to remain backward compatible, then a case-insensitive check
|
|
806
|
+
* based on the locale is done.
|
|
807
|
+
*
|
|
808
|
+
* When during the case conversion the length of the string changes we cannot safely match
|
|
809
|
+
* it and return <code>false</code>.
|
|
810
|
+
*
|
|
811
|
+
* @param {string} sValue the value to check, e.g. "März 2013"
|
|
812
|
+
* @param {string} sSubstring the string to compare it with, e.g. "MÄRZ"
|
|
813
|
+
* @param {string} sLocale the locale, e.g. "de-DE"
|
|
814
|
+
* @returns {boolean} true if the given string <code>sValue</code> starts with <code>sSubstring</code>
|
|
815
|
+
* @private
|
|
816
|
+
*/
|
|
817
|
+
startsWithIgnoreCase: function (sValue, sSubstring, sLocale) {
|
|
818
|
+
// exact case comparison (backward compatible)
|
|
819
|
+
if (sValue.startsWith(sSubstring)) {
|
|
820
|
+
return true;
|
|
821
|
+
}
|
|
822
|
+
try {
|
|
823
|
+
// Use String#toLocaleUpperCase instead of String#toLocaleLowerCase because there
|
|
824
|
+
// are known cases where an upper case letter has 2 lower case variants, e.g. Greek sigma.
|
|
825
|
+
var sSubToLocaleUpperCase = sSubstring.toLocaleUpperCase(sLocale);
|
|
826
|
+
var sValueUpperCase = sValue.toLocaleUpperCase(sLocale);
|
|
827
|
+
|
|
828
|
+
// During the upper-case conversion there are cases where length changes, e.g. ß -> SS.
|
|
829
|
+
// This cannot be properly determined without probing therefore we do not support this case.
|
|
830
|
+
if (sSubToLocaleUpperCase.length !== sSubstring.length || sValueUpperCase.length !== sValue.length) {
|
|
831
|
+
return false;
|
|
832
|
+
}
|
|
833
|
+
return sValueUpperCase.startsWith(sSubToLocaleUpperCase);
|
|
834
|
+
} catch (e) {
|
|
835
|
+
// Can fail for String#toLocaleUpperCase with an invalid locale
|
|
836
|
+
// the API fails in the case with: Incorrect locale information provided
|
|
837
|
+
return false;
|
|
838
|
+
}
|
|
839
|
+
},
|
|
840
|
+
/**
|
|
841
|
+
* Finds the longest matching entry for which the following applies:
|
|
842
|
+
* * <code>sValue</code> starts with the found entry
|
|
843
|
+
*
|
|
844
|
+
* The index of the finding in <code>aList</code> and the length of the match is returned.
|
|
845
|
+
* The case is ignored and the given locale is used for the string comparison.
|
|
846
|
+
*
|
|
847
|
+
* @example
|
|
848
|
+
* findEntry("MÄRZ 2013", ["Januar", "Februar", "März", "April", ...], "de-DE");
|
|
849
|
+
* // {length: 4, index: 2}
|
|
850
|
+
* @example
|
|
851
|
+
* findEntry("Sep 2013", [..., "Aug", ["Sept", "Sep"], "Oct", ...], "en-GB");
|
|
852
|
+
* // {length: 3, index: 8}
|
|
853
|
+
*
|
|
854
|
+
* @param {string} sValue the input value, e.g. "MÄRZ 2013"
|
|
855
|
+
* @param {string[]|Array<string[]>} aList
|
|
856
|
+
* The list of values to check, e.g. ["Januar", "Februar", "März", "April", ...]; the list may contain also
|
|
857
|
+
* arrays of strings containing alternatives, e.g. [..., "Aug", ["Sept", "Sep"], "Oct", ...]
|
|
858
|
+
* @param {string} sLocale the locale which is used for the string comparison, e.g. "de-DE"
|
|
859
|
+
* @returns {{length: number, index: number}} the length of the match in sValue, the index in the list of values
|
|
860
|
+
* e.g. length: 4, index: 2 ("MÄRZ")
|
|
861
|
+
* @private
|
|
862
|
+
*/
|
|
863
|
+
findEntry: function (sValue, aList, sLocale) {
|
|
864
|
+
let iFoundIndex = -1;
|
|
865
|
+
let iMatchedLength = 0;
|
|
866
|
+
aList.forEach((vEntry, j) => {
|
|
867
|
+
(Array.isArray(vEntry) ? vEntry : [vEntry]).forEach(sEntry => {
|
|
868
|
+
if (sEntry.length > iMatchedLength && this.startsWithIgnoreCase(sValue, sEntry, sLocale)) {
|
|
869
|
+
iFoundIndex = j;
|
|
870
|
+
iMatchedLength = sEntry.length;
|
|
871
|
+
}
|
|
872
|
+
});
|
|
873
|
+
});
|
|
874
|
+
return {
|
|
875
|
+
index: iFoundIndex,
|
|
876
|
+
length: iMatchedLength
|
|
877
|
+
};
|
|
878
|
+
},
|
|
879
|
+
/**
|
|
880
|
+
* Parses a given timezone
|
|
881
|
+
*
|
|
882
|
+
* @param {string} sValue String to parse, e.g. "-0800", "-08:00", "-08"
|
|
883
|
+
* @param {boolean} bColonSeparated Whether or not the values are colon separated, e.g. "-08:00"
|
|
884
|
+
* @returns {{tzDiff: number, length: number}} Object containing the timezone difference in seconds and the length of the parsed segment
|
|
885
|
+
*/
|
|
886
|
+
parseTZ: function (sValue, bColonSeparated) {
|
|
887
|
+
var iLength = 0;
|
|
888
|
+
var iTZFactor = sValue.charAt(0) === "+" ? -1 : 1;
|
|
889
|
+
var sPart;
|
|
890
|
+
if (sValue[0] === "Z") {
|
|
891
|
+
return {
|
|
892
|
+
length: 1,
|
|
893
|
+
tzDiff: 0
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
iLength++; //"+" or "-"
|
|
897
|
+
sPart = this.findNumbers(sValue.substr(iLength), 2);
|
|
898
|
+
var iTZDiffHour = parseInt(sPart);
|
|
899
|
+
iLength += 2; //hh: 2 digits for hours
|
|
900
|
+
|
|
901
|
+
if (bColonSeparated) {
|
|
902
|
+
iLength++; //":"
|
|
903
|
+
}
|
|
904
|
+
sPart = this.findNumbers(sValue.substr(iLength), 2);
|
|
905
|
+
var iTZDiff = 0;
|
|
906
|
+
// timezone pattern "X": will produce only 2 digits: "-08"
|
|
907
|
+
if (sPart) {
|
|
908
|
+
iLength += 2; //mm: 2 digits for minutes
|
|
909
|
+
iTZDiff = parseInt(sPart);
|
|
910
|
+
}
|
|
911
|
+
return {
|
|
912
|
+
length: iLength,
|
|
913
|
+
tzDiff: (iTZDiff + 60 * iTZDiffHour) * 60 * iTZFactor
|
|
914
|
+
};
|
|
915
|
+
},
|
|
916
|
+
/**
|
|
917
|
+
* Returns <code>false</code> if the given pattern symbol name is required and the value for that part is
|
|
918
|
+
* invalid, otherwise <code>true</code> is returned.
|
|
919
|
+
*
|
|
920
|
+
* @param {string} sSymbolName
|
|
921
|
+
* A unique pattern symbol name
|
|
922
|
+
* @param {boolean} bPartInvalid
|
|
923
|
+
* Whether the value for the given pattern symbol name is invalid
|
|
924
|
+
* @param {sap.ui.core.format.DateFormat} oFormat
|
|
925
|
+
* The <code>DateFormat</code> instance
|
|
926
|
+
* @returns {boolean}
|
|
927
|
+
* <code>false</code> if the given pattern symbol name is required and the value for that part is invalid,
|
|
928
|
+
* otherwise <code>true</code>
|
|
929
|
+
*/
|
|
930
|
+
checkValid: function (sSymbolName, bPartInvalid, oFormat) {
|
|
931
|
+
if (sSymbolName in oFormat.oRequiredParts && bPartInvalid) {
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
return true;
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
DateFormat._oParseHelper = oParseHelper; // make parse helper a private static member for testing
|
|
938
|
+
|
|
939
|
+
/**
|
|
940
|
+
* Creates a pattern symbol object containing all needed functions to be used for formatting and parsing.
|
|
941
|
+
* Functions which are not given in <code>mParameters</code> are provided with a default implementation.
|
|
942
|
+
*
|
|
943
|
+
* @param {Object<string,any>} mParameters
|
|
944
|
+
* A parameters map for creating a pattern symbol
|
|
945
|
+
* @param {string} mParameters.name
|
|
946
|
+
* An internal unique name describing this symbol
|
|
947
|
+
* @param {function(Object<string, any>, sap.ui.core.date.UniversalDate, boolean, sap.ui.core.format.DateFormat,
|
|
948
|
+
* string): string} [mParameters.format]
|
|
949
|
+
* A function to format the symbol part based on a given date object
|
|
950
|
+
* @param {function(string, Object<string, any>, sap.ui.core.format.DateFormat, object, string): object}
|
|
951
|
+
* [mParameters.parse]
|
|
952
|
+
* A function to parse the symbol part based on a given date string
|
|
953
|
+
* @param {boolean|function(int): boolean} [mParameters.isNumeric]
|
|
954
|
+
* A boolean to describe, or a function to evaluate, whether the pattern symbol expects a
|
|
955
|
+
* numeric representation. For example pattern "MM" results in "02" and is therefore numeric,
|
|
956
|
+
* but "MMM" results in "Feb" which is not numeric.
|
|
957
|
+
* @returns {{name: string, format: function, parse: function, isNumeric: function}}
|
|
958
|
+
* A pattern symbol object
|
|
959
|
+
*
|
|
960
|
+
* @private
|
|
961
|
+
*/
|
|
962
|
+
DateFormat._createPatternSymbol = function (mParameters) {
|
|
963
|
+
var fnIsNumeric = typeof mParameters.isNumeric === "function" && mParameters.isNumeric
|
|
964
|
+
// Default: false
|
|
965
|
+
|| function () {
|
|
966
|
+
return mParameters.isNumeric || false;
|
|
967
|
+
};
|
|
968
|
+
return {
|
|
969
|
+
name: mParameters.name,
|
|
970
|
+
/**
|
|
971
|
+
* Formatter for a pattern symbol.
|
|
972
|
+
*
|
|
973
|
+
* @param {Object<string, any>} oField
|
|
974
|
+
* The date pattern field as parsed by {@link DateFormat#parseCldrDatePattern}
|
|
975
|
+
* @param {sap.ui.core.date.UniversalDate} oDate
|
|
976
|
+
* The date object to format
|
|
977
|
+
* @param {boolean} bUTC
|
|
978
|
+
* Whether the UTC option is set
|
|
979
|
+
* @param {sap.ui.core.format.DateFormat} oFormat
|
|
980
|
+
* The <code>DateFormat</code> instance
|
|
981
|
+
* @returns {string}
|
|
982
|
+
* The formatted date information for this date pattern part
|
|
983
|
+
*/
|
|
984
|
+
format: mParameters.format
|
|
985
|
+
// not supported, but reserved
|
|
986
|
+
|| function () {
|
|
987
|
+
return "";
|
|
988
|
+
},
|
|
989
|
+
/**
|
|
990
|
+
* Parser for a pattern symbol.
|
|
991
|
+
*
|
|
992
|
+
* @param {string} sValue
|
|
993
|
+
* The given input
|
|
994
|
+
* @param {Object<string, any>} oPart
|
|
995
|
+
* The date pattern field as parsed by {@link DateFormat#parseCldrDatePattern}
|
|
996
|
+
* @param {sap.ui.core.format.DateFormat} oFormat
|
|
997
|
+
* The <code>DateFormat</code> instance
|
|
998
|
+
* @param {object} oConfig
|
|
999
|
+
* The configuration object for parsing the value
|
|
1000
|
+
* @param {object} oConfig.dateValue
|
|
1001
|
+
* The already parsed date fields
|
|
1002
|
+
* @param {boolean} oConfig.exactLength
|
|
1003
|
+
* Whether parsing with the exact length specified by {@link DateFormat#parseCldrDatePattern} is needed
|
|
1004
|
+
* @param {object[]} oConfig.formatArray
|
|
1005
|
+
* The complete format array as parsed by {@link DateFormat#parseCldrDatePattern}
|
|
1006
|
+
* @param {int} oConfig.index
|
|
1007
|
+
* The current index in the format array
|
|
1008
|
+
* @param {boolean} oConfig.strict
|
|
1009
|
+
* Whether to disallow overflows for component values of a date (see
|
|
1010
|
+
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date).
|
|
1011
|
+
* Note that the corresponding checks are just for number ranges which are possible <em>at max</em>
|
|
1012
|
+
* without overflow; the check for day does not consider the month and year to compute the maximum
|
|
1013
|
+
* number of days allowed.
|
|
1014
|
+
* @param {string} sTimezone
|
|
1015
|
+
* The IANA timezone ID
|
|
1016
|
+
* @returns {object}
|
|
1017
|
+
* The parsed date information for this date pattern part; could contain the property <code>valid</code>
|
|
1018
|
+
* set to <code>false</code> if parsing was not successful
|
|
1019
|
+
*/
|
|
1020
|
+
parse: mParameters.parse
|
|
1021
|
+
// not supported, but reserved
|
|
1022
|
+
|| function () {
|
|
1023
|
+
return {};
|
|
1024
|
+
},
|
|
1025
|
+
/**
|
|
1026
|
+
* Evaluates whether this symbol has a numeric representation.
|
|
1027
|
+
*
|
|
1028
|
+
* @param {int} [iDigits] The number of repetitions of the pattern symbol, e.g. <code>3</code> for "aaa"
|
|
1029
|
+
* @returns {boolean} Whether this symbol has a numeric representation
|
|
1030
|
+
*/
|
|
1031
|
+
isNumeric: fnIsNumeric
|
|
1032
|
+
};
|
|
1033
|
+
};
|
|
1034
|
+
|
|
1035
|
+
/**
|
|
1036
|
+
* Provides functionality to format and parse a given pattern symbol.
|
|
1037
|
+
* @see https://unicode.org/reports/tr35/tr35-dates.html#table-date-field-symbol-table
|
|
1038
|
+
*/
|
|
1039
|
+
DateFormat.prototype.oSymbols = {
|
|
1040
|
+
"": DateFormat._createPatternSymbol({
|
|
1041
|
+
name: "text",
|
|
1042
|
+
format: function (oField, oDate) {
|
|
1043
|
+
return oField.value;
|
|
1044
|
+
},
|
|
1045
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1046
|
+
var sChar;
|
|
1047
|
+
var bValid = true;
|
|
1048
|
+
var iValueIndex = 0;
|
|
1049
|
+
var iPatternIndex = 0;
|
|
1050
|
+
// https://www.compart.com/en/unicode/category/Pd
|
|
1051
|
+
var sDelimiter = "\u002d\u007E\u2010\u2011\u2012\u2013\u2014\ufe58\ufe63\uff0d\uFF5E";
|
|
1052
|
+
|
|
1053
|
+
// Compare the letters in oPart.value (the pattern) and sValue (the given string to parse)
|
|
1054
|
+
// one by one.
|
|
1055
|
+
// If the current letter in the pattern is " ", sValue is allowed to have no match, exact match
|
|
1056
|
+
// or multiple " ". This makes the parsing more tolerant. Special spaces or RTL characters have
|
|
1057
|
+
// to be normalized before comparison.
|
|
1058
|
+
const sPartValue = DateFormat._normalize(oPart.value);
|
|
1059
|
+
for (; iPatternIndex < sPartValue.length; iPatternIndex++) {
|
|
1060
|
+
sChar = sPartValue.charAt(iPatternIndex);
|
|
1061
|
+
if (sChar === " ") {
|
|
1062
|
+
// allows to have multiple spaces
|
|
1063
|
+
while (sValue.charAt(iValueIndex) === " ") {
|
|
1064
|
+
iValueIndex++;
|
|
1065
|
+
}
|
|
1066
|
+
} else if (sDelimiter.includes(sChar)) {
|
|
1067
|
+
if (!sDelimiter.includes(sValue.charAt(iValueIndex))) {
|
|
1068
|
+
bValid = false;
|
|
1069
|
+
}
|
|
1070
|
+
iValueIndex++;
|
|
1071
|
+
} else {
|
|
1072
|
+
if (sValue.charAt(iValueIndex) !== sChar) {
|
|
1073
|
+
// if it's not a space, there must be an exact match
|
|
1074
|
+
bValid = false;
|
|
1075
|
+
}
|
|
1076
|
+
iValueIndex++;
|
|
1077
|
+
}
|
|
1078
|
+
if (!bValid) {
|
|
1079
|
+
break;
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
if (bValid) {
|
|
1083
|
+
return {
|
|
1084
|
+
length: iValueIndex
|
|
1085
|
+
};
|
|
1086
|
+
} else {
|
|
1087
|
+
var bPartInvalid = false;
|
|
1088
|
+
|
|
1089
|
+
// only require text, if next part is also required
|
|
1090
|
+
if (oConfig.index < oConfig.formatArray.length - 1) {
|
|
1091
|
+
bPartInvalid = oConfig.formatArray[oConfig.index + 1].type in oFormat.oRequiredParts;
|
|
1092
|
+
}
|
|
1093
|
+
return {
|
|
1094
|
+
valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat)
|
|
1095
|
+
};
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}),
|
|
1099
|
+
"G": DateFormat._createPatternSymbol({
|
|
1100
|
+
name: "era",
|
|
1101
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1102
|
+
var iEra = oDate.getUTCEra();
|
|
1103
|
+
if (oField.digits <= 3) {
|
|
1104
|
+
return oFormat.aErasAbbrev[iEra];
|
|
1105
|
+
} else if (oField.digits === 4) {
|
|
1106
|
+
return oFormat.aErasWide[iEra];
|
|
1107
|
+
} else {
|
|
1108
|
+
return oFormat.aErasNarrow[iEra];
|
|
1109
|
+
}
|
|
1110
|
+
},
|
|
1111
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1112
|
+
var aErasVariants = [oFormat.aErasWide, oFormat.aErasAbbrev, oFormat.aErasNarrow];
|
|
1113
|
+
for (var i = 0; i < aErasVariants.length; i++) {
|
|
1114
|
+
var aVariants = aErasVariants[i];
|
|
1115
|
+
var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
|
|
1116
|
+
if (oFound.index !== -1) {
|
|
1117
|
+
return {
|
|
1118
|
+
era: oFound.index,
|
|
1119
|
+
length: oFound.length
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
return {
|
|
1124
|
+
era: oFormat.aErasWide.length - 1,
|
|
1125
|
+
valid: oParseHelper.checkValid(oPart.type, true, oFormat)
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
}),
|
|
1129
|
+
"y": DateFormat._createPatternSymbol({
|
|
1130
|
+
name: "year",
|
|
1131
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1132
|
+
var iYear = oDate.getUTCFullYear();
|
|
1133
|
+
var sYear = String(iYear);
|
|
1134
|
+
var sCalendarType = oFormat.oFormatOptions.calendarType;
|
|
1135
|
+
if (oField.digits === 2 && sYear.length > 2) {
|
|
1136
|
+
sYear = sYear.substr(sYear.length - 2);
|
|
1137
|
+
}
|
|
1138
|
+
// When parsing we assume dates less than 100 to be in the current/last century,
|
|
1139
|
+
// so when formatting we have to make sure they are differentiable by prefixing with zeros
|
|
1140
|
+
if (sCalendarType !== CalendarType.Japanese && oField.digits === 1 && iYear < 100) {
|
|
1141
|
+
sYear = sYear.padStart(4, "0");
|
|
1142
|
+
}
|
|
1143
|
+
return sYear.padStart(oField.digits, "0");
|
|
1144
|
+
},
|
|
1145
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1146
|
+
var iExpectedDigits,
|
|
1147
|
+
sPart,
|
|
1148
|
+
bPartInvalid,
|
|
1149
|
+
sCalendarType = oFormat.oFormatOptions.calendarType;
|
|
1150
|
+
if (oPart.digits === 1) {
|
|
1151
|
+
iExpectedDigits = 4;
|
|
1152
|
+
} else if (oPart.digits === 2) {
|
|
1153
|
+
iExpectedDigits = 2;
|
|
1154
|
+
} else {
|
|
1155
|
+
iExpectedDigits = oPart.digits;
|
|
1156
|
+
}
|
|
1157
|
+
sPart = oParseHelper.findNumbers(sValue, iExpectedDigits);
|
|
1158
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length !== iExpectedDigits;
|
|
1159
|
+
var iYear = parseInt(sPart);
|
|
1160
|
+
// Find the right century for two-digit years
|
|
1161
|
+
// https://tc39.es/ecma262/#sec-date.parse
|
|
1162
|
+
// "The function first attempts to parse the String according to the format
|
|
1163
|
+
// described in Date Time String Format (https://tc39.es/ecma262/#sec-date-time-string-format),
|
|
1164
|
+
// including expanded years.
|
|
1165
|
+
// If the String does not conform to that format the function may fall back to
|
|
1166
|
+
// any implementation-specific heuristics or implementation-specific date formats."
|
|
1167
|
+
//
|
|
1168
|
+
// Since a two-digit year is not format conform, each JS implementations might differ.
|
|
1169
|
+
// Therefore we provide an own implementation:
|
|
1170
|
+
|
|
1171
|
+
// current year: 1978
|
|
1172
|
+
// 1978: 08 = 1908 (diff: -70)
|
|
1173
|
+
// 1978: 07 = 2007 (diff: -71)
|
|
1174
|
+
|
|
1175
|
+
// current year: 2018
|
|
1176
|
+
// 2018: 48 = 1948 (diff: 30)
|
|
1177
|
+
// 2018: 47 = 2047 (diff: 29)
|
|
1178
|
+
if (sCalendarType !== CalendarType.Japanese && sPart.length <= 2) {
|
|
1179
|
+
var oCurrentDate = UniversalDate.getInstance(UI5Date.getInstance(), sCalendarType),
|
|
1180
|
+
iCurrentYear = oCurrentDate.getUTCFullYear(),
|
|
1181
|
+
iCurrentCentury = Math.floor(iCurrentYear / 100),
|
|
1182
|
+
iYearDiff = iCurrentCentury * 100 + iYear - iCurrentYear;
|
|
1183
|
+
if (iYearDiff < -70) {
|
|
1184
|
+
iYear += (iCurrentCentury + 1) * 100;
|
|
1185
|
+
} else if (iYearDiff < 30) {
|
|
1186
|
+
iYear += iCurrentCentury * 100;
|
|
1187
|
+
} else {
|
|
1188
|
+
iYear += (iCurrentCentury - 1) * 100;
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
return {
|
|
1192
|
+
length: sPart.length,
|
|
1193
|
+
valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat),
|
|
1194
|
+
year: iYear
|
|
1195
|
+
};
|
|
1196
|
+
},
|
|
1197
|
+
isNumeric: true
|
|
1198
|
+
}),
|
|
1199
|
+
"Y": DateFormat._createPatternSymbol({
|
|
1200
|
+
name: "weekYear",
|
|
1201
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1202
|
+
var oWeek = oDate.getUTCWeek(oFormat.oLocale, getCalendarWeekParameter(oFormat.oFormatOptions));
|
|
1203
|
+
var iWeekYear = oWeek.year;
|
|
1204
|
+
var sWeekYear = String(iWeekYear);
|
|
1205
|
+
var sCalendarType = oFormat.oFormatOptions.calendarType;
|
|
1206
|
+
if (oField.digits === 2 && sWeekYear.length > 2) {
|
|
1207
|
+
sWeekYear = sWeekYear.substr(sWeekYear.length - 2);
|
|
1208
|
+
}
|
|
1209
|
+
// When parsing we assume dates less than 100 to be in the current/last century,
|
|
1210
|
+
// so when formatting we have to make sure they are differentiable by prefixing with zeros
|
|
1211
|
+
if (sCalendarType !== CalendarType.Japanese && oField.digits === 1 && iWeekYear < 100) {
|
|
1212
|
+
sWeekYear = sWeekYear.padStart(4, "0");
|
|
1213
|
+
}
|
|
1214
|
+
return sWeekYear.padStart(oField.digits, "0");
|
|
1215
|
+
},
|
|
1216
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1217
|
+
var iExpectedDigits,
|
|
1218
|
+
sPart,
|
|
1219
|
+
bPartInvalid,
|
|
1220
|
+
sCalendarType = oFormat.oFormatOptions.calendarType;
|
|
1221
|
+
if (oPart.digits === 1) {
|
|
1222
|
+
iExpectedDigits = 4;
|
|
1223
|
+
} else if (oPart.digits === 2) {
|
|
1224
|
+
iExpectedDigits = 2;
|
|
1225
|
+
} else {
|
|
1226
|
+
iExpectedDigits = oPart.digits;
|
|
1227
|
+
}
|
|
1228
|
+
sPart = oParseHelper.findNumbers(sValue, iExpectedDigits);
|
|
1229
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length !== iExpectedDigits;
|
|
1230
|
+
var iYear = parseInt(sPart);
|
|
1231
|
+
var iWeekYear = iYear;
|
|
1232
|
+
// Find the right century for two-digit years
|
|
1233
|
+
if (sCalendarType !== CalendarType.Japanese && sPart.length <= 2) {
|
|
1234
|
+
var oCurrentDate = UniversalDate.getInstance(UI5Date.getInstance(), sCalendarType),
|
|
1235
|
+
iCurrentYear = oCurrentDate.getUTCFullYear(),
|
|
1236
|
+
iCurrentCentury = Math.floor(iCurrentYear / 100),
|
|
1237
|
+
iYearDiff = iCurrentCentury * 100 + iWeekYear - iCurrentYear;
|
|
1238
|
+
if (iYearDiff < -70) {
|
|
1239
|
+
iWeekYear += (iCurrentCentury + 1) * 100;
|
|
1240
|
+
} else if (iYearDiff < 30) {
|
|
1241
|
+
iWeekYear += iCurrentCentury * 100;
|
|
1242
|
+
} else {
|
|
1243
|
+
iWeekYear += (iCurrentCentury - 1) * 100;
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
return {
|
|
1247
|
+
length: sPart.length,
|
|
1248
|
+
valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat),
|
|
1249
|
+
year: iYear,
|
|
1250
|
+
weekYear: iWeekYear
|
|
1251
|
+
};
|
|
1252
|
+
},
|
|
1253
|
+
isNumeric: true
|
|
1254
|
+
}),
|
|
1255
|
+
"M": DateFormat._createPatternSymbol({
|
|
1256
|
+
name: "month",
|
|
1257
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1258
|
+
var iMonth = oDate.getUTCMonth();
|
|
1259
|
+
if (oField.digits === 3) {
|
|
1260
|
+
const vName = oFormat.aMonthsAbbrev[iMonth]; // vName may be an array if there are alternatives
|
|
1261
|
+
return Array.isArray(vName) ? vName[0] : vName;
|
|
1262
|
+
} else if (oField.digits === 4) {
|
|
1263
|
+
return oFormat.aMonthsWide[iMonth];
|
|
1264
|
+
} else if (oField.digits > 4) {
|
|
1265
|
+
return oFormat.aMonthsNarrow[iMonth];
|
|
1266
|
+
} else {
|
|
1267
|
+
return String(iMonth + 1).padStart(oField.digits, "0");
|
|
1268
|
+
}
|
|
1269
|
+
},
|
|
1270
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1271
|
+
var iMonth,
|
|
1272
|
+
sPart,
|
|
1273
|
+
bPartInvalid,
|
|
1274
|
+
bValid,
|
|
1275
|
+
aMonthsVariants = [oFormat.aMonthsWide, oFormat.aMonthsWideSt, oFormat.aMonthsAbbrev, oFormat.aMonthsAbbrevSt, oFormat.aMonthsNarrow, oFormat.aMonthsNarrowSt];
|
|
1276
|
+
if (oPart.digits < 3) {
|
|
1277
|
+
sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
|
|
1278
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < 2;
|
|
1279
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1280
|
+
iMonth = parseInt(sPart) - 1;
|
|
1281
|
+
if (oConfig.strict && (iMonth > 11 || iMonth < 0)) {
|
|
1282
|
+
bValid = false;
|
|
1283
|
+
}
|
|
1284
|
+
} else {
|
|
1285
|
+
for (var i = 0; i < aMonthsVariants.length; i++) {
|
|
1286
|
+
var aVariants = aMonthsVariants[i];
|
|
1287
|
+
var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
|
|
1288
|
+
if (oFound.index !== -1) {
|
|
1289
|
+
return {
|
|
1290
|
+
month: oFound.index,
|
|
1291
|
+
length: oFound.length
|
|
1292
|
+
};
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
bValid = oParseHelper.checkValid(oPart.type, true, oFormat);
|
|
1296
|
+
}
|
|
1297
|
+
return {
|
|
1298
|
+
month: iMonth,
|
|
1299
|
+
length: sPart ? sPart.length : 0,
|
|
1300
|
+
valid: bValid
|
|
1301
|
+
};
|
|
1302
|
+
},
|
|
1303
|
+
isNumeric: function (iDigits) {
|
|
1304
|
+
return iDigits < 3;
|
|
1305
|
+
}
|
|
1306
|
+
}),
|
|
1307
|
+
"L": DateFormat._createPatternSymbol({
|
|
1308
|
+
name: "monthStandalone",
|
|
1309
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1310
|
+
var iMonth = oDate.getUTCMonth();
|
|
1311
|
+
if (oField.digits === 3) {
|
|
1312
|
+
const vName = oFormat.aMonthsAbbrevSt[iMonth]; // vName may be an array if there are alternatives
|
|
1313
|
+
return Array.isArray(vName) ? vName[0] : vName;
|
|
1314
|
+
} else if (oField.digits === 4) {
|
|
1315
|
+
return oFormat.aMonthsWideSt[iMonth];
|
|
1316
|
+
} else if (oField.digits > 4) {
|
|
1317
|
+
return oFormat.aMonthsNarrowSt[iMonth];
|
|
1318
|
+
} else {
|
|
1319
|
+
return String(iMonth + 1).padStart(oField.digits, "0");
|
|
1320
|
+
}
|
|
1321
|
+
},
|
|
1322
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1323
|
+
var iMonth,
|
|
1324
|
+
sPart,
|
|
1325
|
+
bPartInvalid,
|
|
1326
|
+
bValid,
|
|
1327
|
+
aMonthsVariants = [oFormat.aMonthsWide, oFormat.aMonthsWideSt, oFormat.aMonthsAbbrev, oFormat.aMonthsAbbrevSt, oFormat.aMonthsNarrow, oFormat.aMonthsNarrowSt];
|
|
1328
|
+
if (oPart.digits < 3) {
|
|
1329
|
+
sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
|
|
1330
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < 2;
|
|
1331
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1332
|
+
iMonth = parseInt(sPart) - 1;
|
|
1333
|
+
if (oConfig.strict && (iMonth > 11 || iMonth < 0)) {
|
|
1334
|
+
bValid = false;
|
|
1335
|
+
}
|
|
1336
|
+
} else {
|
|
1337
|
+
for (var i = 0; i < aMonthsVariants.length; i++) {
|
|
1338
|
+
var aVariants = aMonthsVariants[i];
|
|
1339
|
+
var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
|
|
1340
|
+
if (oFound.index !== -1) {
|
|
1341
|
+
return {
|
|
1342
|
+
month: oFound.index,
|
|
1343
|
+
length: oFound.length
|
|
1344
|
+
};
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
bValid = oParseHelper.checkValid(oPart.type, true, oFormat);
|
|
1348
|
+
}
|
|
1349
|
+
return {
|
|
1350
|
+
month: iMonth,
|
|
1351
|
+
length: sPart ? sPart.length : 0,
|
|
1352
|
+
valid: bValid
|
|
1353
|
+
};
|
|
1354
|
+
},
|
|
1355
|
+
isNumeric: function (iDigits) {
|
|
1356
|
+
return iDigits < 3;
|
|
1357
|
+
}
|
|
1358
|
+
}),
|
|
1359
|
+
"w": DateFormat._createPatternSymbol({
|
|
1360
|
+
name: "weekInYear",
|
|
1361
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1362
|
+
var oWeek = oDate.getUTCWeek(oFormat.oLocale, getCalendarWeekParameter(oFormat.oFormatOptions));
|
|
1363
|
+
var iWeek = oWeek.week;
|
|
1364
|
+
var sWeek = String(iWeek + 1);
|
|
1365
|
+
if (oField.digits < 3) {
|
|
1366
|
+
sWeek = sWeek.padStart(oField.digits, "0");
|
|
1367
|
+
} else {
|
|
1368
|
+
sWeek = oFormat.oLocaleData.getCalendarWeek(oField.digits === 3 ? "narrow" : "wide", sWeek.padStart(2, "0"));
|
|
1369
|
+
}
|
|
1370
|
+
return sWeek;
|
|
1371
|
+
},
|
|
1372
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1373
|
+
var sPart,
|
|
1374
|
+
bPartInvalid,
|
|
1375
|
+
bValid,
|
|
1376
|
+
iWeek,
|
|
1377
|
+
iLength = 0;
|
|
1378
|
+
if (oPart.digits < 3) {
|
|
1379
|
+
sPart = oParseHelper.findNumbers(sValue, 2);
|
|
1380
|
+
iLength = sPart.length;
|
|
1381
|
+
iWeek = parseInt(sPart) - 1;
|
|
1382
|
+
bPartInvalid = !sPart || oConfig.exactLength && iLength < 2;
|
|
1383
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1384
|
+
} else {
|
|
1385
|
+
sPart = oFormat.oLocaleData.getCalendarWeek(oPart.digits === 3 ? "narrow" : "wide");
|
|
1386
|
+
sPart = sPart.replace("{0}", "([0-9]+)");
|
|
1387
|
+
var rWeekNumber = new RegExp(sPart),
|
|
1388
|
+
oResult = rWeekNumber.exec(sValue);
|
|
1389
|
+
if (oResult) {
|
|
1390
|
+
// e.g. for input "CW 01" create pattern "CW ([0-9]+)"
|
|
1391
|
+
// and extract number from "01" part of the input
|
|
1392
|
+
iLength = oResult[0].length;
|
|
1393
|
+
iWeek = parseInt(oResult[oResult.length - 1]) - 1;
|
|
1394
|
+
} else {
|
|
1395
|
+
bValid = oParseHelper.checkValid(oPart.type, true, oFormat);
|
|
1396
|
+
}
|
|
1397
|
+
}
|
|
1398
|
+
return {
|
|
1399
|
+
length: iLength,
|
|
1400
|
+
valid: bValid,
|
|
1401
|
+
week: iWeek
|
|
1402
|
+
};
|
|
1403
|
+
},
|
|
1404
|
+
isNumeric: function (iDigits) {
|
|
1405
|
+
return iDigits < 3;
|
|
1406
|
+
}
|
|
1407
|
+
}),
|
|
1408
|
+
"W": DateFormat._createPatternSymbol({
|
|
1409
|
+
name: "weekInMonth"
|
|
1410
|
+
}),
|
|
1411
|
+
"D": DateFormat._createPatternSymbol({
|
|
1412
|
+
name: "dayInYear"
|
|
1413
|
+
}),
|
|
1414
|
+
"d": DateFormat._createPatternSymbol({
|
|
1415
|
+
name: "day",
|
|
1416
|
+
format: function (oField, oDate) {
|
|
1417
|
+
var iDate = oDate.getUTCDate();
|
|
1418
|
+
return String(iDate).padStart(oField.digits, "0");
|
|
1419
|
+
},
|
|
1420
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1421
|
+
var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)),
|
|
1422
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < 2,
|
|
1423
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat),
|
|
1424
|
+
iDay = parseInt(sPart);
|
|
1425
|
+
if (oConfig.strict && (iDay > 31 || iDay < 1)) {
|
|
1426
|
+
bValid = false;
|
|
1427
|
+
}
|
|
1428
|
+
return {
|
|
1429
|
+
day: iDay,
|
|
1430
|
+
length: sPart.length,
|
|
1431
|
+
valid: bValid
|
|
1432
|
+
};
|
|
1433
|
+
},
|
|
1434
|
+
isNumeric: true
|
|
1435
|
+
}),
|
|
1436
|
+
"Q": DateFormat._createPatternSymbol({
|
|
1437
|
+
name: "quarter",
|
|
1438
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1439
|
+
var iQuarter = oDate.getUTCQuarter();
|
|
1440
|
+
if (oField.digits === 3) {
|
|
1441
|
+
return oFormat.aQuartersAbbrev[iQuarter];
|
|
1442
|
+
} else if (oField.digits === 4) {
|
|
1443
|
+
return oFormat.aQuartersWide[iQuarter];
|
|
1444
|
+
} else if (oField.digits > 4) {
|
|
1445
|
+
return oFormat.aQuartersNarrow[iQuarter];
|
|
1446
|
+
} else {
|
|
1447
|
+
return String(iQuarter + 1).padStart(oField.digits, "0");
|
|
1448
|
+
}
|
|
1449
|
+
},
|
|
1450
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1451
|
+
var sPart, bPartInvalid, iQuarter, bValid;
|
|
1452
|
+
var aQuartersVariants = [oFormat.aQuartersWide, oFormat.aQuartersWideSt, oFormat.aQuartersAbbrev, oFormat.aQuartersAbbrevSt, oFormat.aQuartersNarrow, oFormat.aQuartersNarrowSt];
|
|
1453
|
+
if (oPart.digits < 3) {
|
|
1454
|
+
sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
|
|
1455
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < 2;
|
|
1456
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1457
|
+
iQuarter = parseInt(sPart) - 1;
|
|
1458
|
+
if (oConfig.strict && iQuarter > 3) {
|
|
1459
|
+
bValid = false;
|
|
1460
|
+
}
|
|
1461
|
+
} else {
|
|
1462
|
+
for (var i = 0; i < aQuartersVariants.length; i++) {
|
|
1463
|
+
var aVariants = aQuartersVariants[i];
|
|
1464
|
+
var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
|
|
1465
|
+
if (oFound.index !== -1) {
|
|
1466
|
+
return {
|
|
1467
|
+
quarter: oFound.index,
|
|
1468
|
+
length: oFound.length
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
bValid = oParseHelper.checkValid(oPart.type, true, oFormat);
|
|
1473
|
+
}
|
|
1474
|
+
return {
|
|
1475
|
+
length: sPart ? sPart.length : 0,
|
|
1476
|
+
quarter: iQuarter,
|
|
1477
|
+
valid: bValid
|
|
1478
|
+
};
|
|
1479
|
+
},
|
|
1480
|
+
isNumeric: function (iDigits) {
|
|
1481
|
+
return iDigits < 3;
|
|
1482
|
+
}
|
|
1483
|
+
}),
|
|
1484
|
+
"q": DateFormat._createPatternSymbol({
|
|
1485
|
+
name: "quarterStandalone",
|
|
1486
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1487
|
+
var iQuarter = oDate.getUTCQuarter();
|
|
1488
|
+
if (oField.digits === 3) {
|
|
1489
|
+
return oFormat.aQuartersAbbrevSt[iQuarter];
|
|
1490
|
+
} else if (oField.digits === 4) {
|
|
1491
|
+
return oFormat.aQuartersWideSt[iQuarter];
|
|
1492
|
+
} else if (oField.digits > 4) {
|
|
1493
|
+
return oFormat.aQuartersNarrowSt[iQuarter];
|
|
1494
|
+
} else {
|
|
1495
|
+
return String(iQuarter + 1).padStart(oField.digits, "0");
|
|
1496
|
+
}
|
|
1497
|
+
},
|
|
1498
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1499
|
+
var sPart, bPartInvalid, iQuarter, bValid;
|
|
1500
|
+
var aQuartersVariants = [oFormat.aQuartersWide, oFormat.aQuartersWideSt, oFormat.aQuartersAbbrev, oFormat.aQuartersAbbrevSt, oFormat.aQuartersNarrow, oFormat.aQuartersNarrowSt];
|
|
1501
|
+
if (oPart.digits < 3) {
|
|
1502
|
+
sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
|
|
1503
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < 2;
|
|
1504
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1505
|
+
iQuarter = parseInt(sPart) - 1;
|
|
1506
|
+
if (oConfig.strict && iQuarter > 3) {
|
|
1507
|
+
bValid = false;
|
|
1508
|
+
}
|
|
1509
|
+
} else {
|
|
1510
|
+
for (var i = 0; i < aQuartersVariants.length; i++) {
|
|
1511
|
+
var aVariants = aQuartersVariants[i];
|
|
1512
|
+
var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
|
|
1513
|
+
if (oFound.index !== -1) {
|
|
1514
|
+
return {
|
|
1515
|
+
quarter: oFound.index,
|
|
1516
|
+
length: oFound.length
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
bValid = oParseHelper.checkValid(oPart.type, true, oFormat);
|
|
1521
|
+
}
|
|
1522
|
+
return {
|
|
1523
|
+
length: sPart ? sPart.length : 0,
|
|
1524
|
+
quarter: iQuarter,
|
|
1525
|
+
valid: bValid
|
|
1526
|
+
};
|
|
1527
|
+
},
|
|
1528
|
+
isNumeric: function (iDigits) {
|
|
1529
|
+
return iDigits < 3;
|
|
1530
|
+
}
|
|
1531
|
+
}),
|
|
1532
|
+
"F": DateFormat._createPatternSymbol({
|
|
1533
|
+
name: "dayOfWeekInMonth"
|
|
1534
|
+
}),
|
|
1535
|
+
"E": DateFormat._createPatternSymbol({
|
|
1536
|
+
name: "dayNameInWeek",
|
|
1537
|
+
//Day of week name, format style.
|
|
1538
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1539
|
+
var iDay = oDate.getUTCDay();
|
|
1540
|
+
if (oField.digits < 4) {
|
|
1541
|
+
return oFormat.aDaysAbbrev[iDay];
|
|
1542
|
+
} else if (oField.digits === 4) {
|
|
1543
|
+
return oFormat.aDaysWide[iDay];
|
|
1544
|
+
} else if (oField.digits === 5) {
|
|
1545
|
+
return oFormat.aDaysNarrow[iDay];
|
|
1546
|
+
} else {
|
|
1547
|
+
return oFormat.aDaysShort[iDay];
|
|
1548
|
+
}
|
|
1549
|
+
},
|
|
1550
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1551
|
+
var aDaysVariants = [oFormat.aDaysWide, oFormat.aDaysWideSt, oFormat.aDaysAbbrev, oFormat.aDaysAbbrevSt, oFormat.aDaysShort, oFormat.aDaysShortSt, oFormat.aDaysNarrow, oFormat.aDaysNarrowSt];
|
|
1552
|
+
for (var i = 0; i < aDaysVariants.length; i++) {
|
|
1553
|
+
var aVariants = aDaysVariants[i];
|
|
1554
|
+
var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
|
|
1555
|
+
if (oFound.index !== -1) {
|
|
1556
|
+
return {
|
|
1557
|
+
// gets translated to dayOfWeek where the day of week is relative to the week
|
|
1558
|
+
dayOfWeek: oFound.index,
|
|
1559
|
+
length: oFound.length
|
|
1560
|
+
};
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
}),
|
|
1565
|
+
"c": DateFormat._createPatternSymbol({
|
|
1566
|
+
name: "dayNameInWeekStandalone",
|
|
1567
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1568
|
+
var iDay = oDate.getUTCDay();
|
|
1569
|
+
if (oField.digits < 4) {
|
|
1570
|
+
return oFormat.aDaysAbbrevSt[iDay];
|
|
1571
|
+
} else if (oField.digits === 4) {
|
|
1572
|
+
return oFormat.aDaysWideSt[iDay];
|
|
1573
|
+
} else if (oField.digits === 5) {
|
|
1574
|
+
return oFormat.aDaysNarrowSt[iDay];
|
|
1575
|
+
} else {
|
|
1576
|
+
return oFormat.aDaysShortSt[iDay];
|
|
1577
|
+
}
|
|
1578
|
+
},
|
|
1579
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1580
|
+
var aDaysVariants = [oFormat.aDaysWide, oFormat.aDaysWideSt, oFormat.aDaysAbbrev, oFormat.aDaysAbbrevSt, oFormat.aDaysShort, oFormat.aDaysShortSt, oFormat.aDaysNarrow, oFormat.aDaysNarrowSt];
|
|
1581
|
+
for (var i = 0; i < aDaysVariants.length; i++) {
|
|
1582
|
+
var aVariants = aDaysVariants[i];
|
|
1583
|
+
var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
|
|
1584
|
+
if (oFound.index !== -1) {
|
|
1585
|
+
return {
|
|
1586
|
+
day: oFound.index,
|
|
1587
|
+
length: oFound.length
|
|
1588
|
+
};
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
}),
|
|
1593
|
+
// day number of week (depends on locale's first day of week)
|
|
1594
|
+
// e.g. Thursday
|
|
1595
|
+
// "de": 4 (firstDay: 1)
|
|
1596
|
+
// "en": 5 (firstDay: 0)
|
|
1597
|
+
// "ar": 6 (firstDay: 6)
|
|
1598
|
+
"u": DateFormat._createPatternSymbol({
|
|
1599
|
+
name: "dayNumberOfWeek",
|
|
1600
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1601
|
+
var iDay = oDate.getUTCDay();
|
|
1602
|
+
return oFormat._adaptDayOfWeek(iDay);
|
|
1603
|
+
},
|
|
1604
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1605
|
+
var sPart = oParseHelper.findNumbers(sValue, oPart.digits),
|
|
1606
|
+
bPartInvalid = oConfig.exactLength && sPart.length !== oPart.digits;
|
|
1607
|
+
return {
|
|
1608
|
+
dayNumberOfWeek: parseInt(sPart),
|
|
1609
|
+
length: sPart.length,
|
|
1610
|
+
valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat)
|
|
1611
|
+
};
|
|
1612
|
+
},
|
|
1613
|
+
isNumeric: true
|
|
1614
|
+
}),
|
|
1615
|
+
"a": DateFormat._createPatternSymbol({
|
|
1616
|
+
name: "amPmMarker",
|
|
1617
|
+
/**
|
|
1618
|
+
* Formats the day period.
|
|
1619
|
+
*
|
|
1620
|
+
* @param {Object<string, any>} oField
|
|
1621
|
+
* The date pattern field as parsed by {@link DateFormat#parseCldrDatePattern}
|
|
1622
|
+
* @param {number} oField.digits
|
|
1623
|
+
* The number of repetitions of the pattern symbol, e.g. <code>3</code> for "aaa"
|
|
1624
|
+
* @param {string} oField.symbol
|
|
1625
|
+
* The pattern symbol "a"
|
|
1626
|
+
* @param {string} oField.type
|
|
1627
|
+
* The symbol name "amPmMarker"
|
|
1628
|
+
* @param {sap.ui.core.date.UniversalDate} oDate
|
|
1629
|
+
* The date to format
|
|
1630
|
+
* @param {boolean} [bUTC]
|
|
1631
|
+
* Whether the UTC option is set; not used
|
|
1632
|
+
* @param {sap.ui.core.format.DateFormat} oFormat
|
|
1633
|
+
* The <code>DateFormat</code> instance
|
|
1634
|
+
* @returns {string}
|
|
1635
|
+
* The formatted day period, e.g. "AM" for symbol "a"
|
|
1636
|
+
*/
|
|
1637
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1638
|
+
var iDayPeriod = oDate.getUTCDayPeriod();
|
|
1639
|
+
if (oField.digits <= 3) {
|
|
1640
|
+
return oFormat.aDayPeriodsAbbrev[iDayPeriod];
|
|
1641
|
+
} else if (oField.digits === 4) {
|
|
1642
|
+
return oFormat.aDayPeriodsWide[iDayPeriod];
|
|
1643
|
+
} else {
|
|
1644
|
+
return oFormat.aDayPeriodsNarrow[iDayPeriod];
|
|
1645
|
+
}
|
|
1646
|
+
},
|
|
1647
|
+
/**
|
|
1648
|
+
* Parses the day period from a given input string.
|
|
1649
|
+
*
|
|
1650
|
+
* @param {string} sValue
|
|
1651
|
+
* The given input, e.g. "am 13:37"
|
|
1652
|
+
* @param {Object<string, any>} oPart
|
|
1653
|
+
* The date pattern field as parsed by {@link DateFormat#parseCldrDatePattern}
|
|
1654
|
+
* @param {number} oPart.digits
|
|
1655
|
+
* The number of repetitions of the pattern symbol, e.g. <code>3</code> for "aaa"
|
|
1656
|
+
* @param {string} oPart.symbol
|
|
1657
|
+
* The pattern symbol "a"
|
|
1658
|
+
* @param {string} oPart.type
|
|
1659
|
+
* The symbol name "amPmMarker"
|
|
1660
|
+
* @param {sap.ui.core.format.DateFormat} oFormat
|
|
1661
|
+
* The <code>DateFormat</code> instance
|
|
1662
|
+
* @param {Object<string, any>} [oConfig]
|
|
1663
|
+
* The configuration object for parsing the value
|
|
1664
|
+
* @param {object[]} [oConfig.formatArray]
|
|
1665
|
+
* The complete format array as parsed by {@link DateFormat#parseCldrDatePattern}
|
|
1666
|
+
* @param {object} [oConfig.dateValue]
|
|
1667
|
+
* The already parsed date fields
|
|
1668
|
+
* @param {number} [oConfig.index]
|
|
1669
|
+
* The index in the format array
|
|
1670
|
+
* @param {boolean} [oConfig.strict]
|
|
1671
|
+
* Whether to use the strict option
|
|
1672
|
+
* @param {string} [sTimezone]
|
|
1673
|
+
* The IANA timezone ID
|
|
1674
|
+
* @returns {{length : number, pm : boolean}|{}}
|
|
1675
|
+
* An object with the <code>length</code> of the match and the parsed <code>pm</code>
|
|
1676
|
+
* value; or an object with property valid <code>false</code> if it could not be
|
|
1677
|
+
* parsed correctly
|
|
1678
|
+
*/
|
|
1679
|
+
parse: function (sValue, oPart, oFormat, oConfig, sTimezone) {
|
|
1680
|
+
// process longer patterns first to find the longest match
|
|
1681
|
+
// wide > abbreviated > narrow
|
|
1682
|
+
var rAMPM,
|
|
1683
|
+
bAMPMAlternativeCase,
|
|
1684
|
+
oEntry,
|
|
1685
|
+
i,
|
|
1686
|
+
aMatch,
|
|
1687
|
+
aVariants,
|
|
1688
|
+
aDayPeriodsVariants = [oFormat.aDayPeriodsWide, oFormat.aDayPeriodsAbbrev, oFormat.aDayPeriodsNarrow];
|
|
1689
|
+
|
|
1690
|
+
// Support ASCII alternative writings for AM/PM (when the locale has am/pm in its
|
|
1691
|
+
// patterns), e.g. "am", "a.m.", "am.", "a. m." (and their case alternatives)
|
|
1692
|
+
// see: https://unicode.org/reports/tr35/tr35-dates.html#Parsing_Dates_Times
|
|
1693
|
+
rAMPM = /[aApP](?:\.)?[\x20\xA0]?[mM](?:\.)?/;
|
|
1694
|
+
aMatch = sValue.match(rAMPM);
|
|
1695
|
+
bAMPMAlternativeCase = aMatch && aMatch.index === 0;
|
|
1696
|
+
function removeSpacesAndDots(sValue) {
|
|
1697
|
+
// Remove normal and non-breaking spaces and remove dots
|
|
1698
|
+
return sValue.replace(/[\x20\xA0]/g, "").replace(/\./g, "");
|
|
1699
|
+
}
|
|
1700
|
+
if (bAMPMAlternativeCase) {
|
|
1701
|
+
sValue = removeSpacesAndDots(sValue);
|
|
1702
|
+
}
|
|
1703
|
+
for (i = 0; i < aDayPeriodsVariants.length; i += 1) {
|
|
1704
|
+
aVariants = aDayPeriodsVariants[i].map(sDayPeriod => {
|
|
1705
|
+
return DateFormat._normalize(sDayPeriod);
|
|
1706
|
+
});
|
|
1707
|
+
if (bAMPMAlternativeCase) {
|
|
1708
|
+
// check normalized match for alternative case of am/pm
|
|
1709
|
+
aVariants = aVariants.map(removeSpacesAndDots);
|
|
1710
|
+
}
|
|
1711
|
+
// check exact and case-insensitive match
|
|
1712
|
+
oEntry = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
|
|
1713
|
+
if (oEntry.index !== -1) {
|
|
1714
|
+
return {
|
|
1715
|
+
pm: oEntry.index === 1,
|
|
1716
|
+
// am/pm alternative may include an additional dot, e.g. "am."
|
|
1717
|
+
// therefore the length for the am/pm alternative is the length of the
|
|
1718
|
+
// match
|
|
1719
|
+
length: bAMPMAlternativeCase ? aMatch[0].length : oEntry.length
|
|
1720
|
+
};
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
return {
|
|
1724
|
+
valid: false
|
|
1725
|
+
};
|
|
1726
|
+
}
|
|
1727
|
+
}),
|
|
1728
|
+
"B": DateFormat._createPatternSymbol({
|
|
1729
|
+
name: "flexibleDayPeriod",
|
|
1730
|
+
/**
|
|
1731
|
+
* Formats the flexible day period.
|
|
1732
|
+
*
|
|
1733
|
+
* @param {Object<string, any>} oField
|
|
1734
|
+
* The date pattern field as parsed by {@link DateFormat#parseCldrDatePattern}
|
|
1735
|
+
* @param {int} oField.digits
|
|
1736
|
+
* The number of repetitions of the pattern symbol, e.g. <code>3</code> for "BBB"
|
|
1737
|
+
* @param {sap.ui.core.date.UniversalDate} oDate
|
|
1738
|
+
* The date object to format
|
|
1739
|
+
* @param {boolean} bUTC
|
|
1740
|
+
* Whether the UTC option is set; not used
|
|
1741
|
+
* @param {sap.ui.core.format.DateFormat} oFormat
|
|
1742
|
+
* The <code>DateFormat</code> instance
|
|
1743
|
+
* @returns {string}
|
|
1744
|
+
* The selected day period e.g. "in the afternoon" for the according style width
|
|
1745
|
+
* "abbreviated", "narrow" or "wide"
|
|
1746
|
+
*/
|
|
1747
|
+
format: function (oField, oDate, bUTC, oFormat) {
|
|
1748
|
+
// If no hours symbol is contained in the pattern, the stand-alone format must be
|
|
1749
|
+
// used. Only non-input skeleton symbols are used. The pattern symbols for hour can
|
|
1750
|
+
// be found under:
|
|
1751
|
+
// https://unicode.org/reports/tr35/tr35-dates.html#dfst-hour
|
|
1752
|
+
var bContainsHour = oFormat.aFormatArray.some(function (oFormatElement) {
|
|
1753
|
+
return "hHKk".includes(oFormatElement.symbol);
|
|
1754
|
+
}),
|
|
1755
|
+
sFlexibleDayPeriod = oFormat.oLocaleData.getFlexibleDayPeriodOfTime(oDate.getUTCHours(), oDate.getUTCMinutes());
|
|
1756
|
+
if (bContainsHour) {
|
|
1757
|
+
if (oField.digits <= 3) {
|
|
1758
|
+
return oFormat.oFlexibleDayPeriodsAbbrev[sFlexibleDayPeriod];
|
|
1759
|
+
}
|
|
1760
|
+
if (oField.digits === 4) {
|
|
1761
|
+
return oFormat.oFlexibleDayPeriodsWide[sFlexibleDayPeriod];
|
|
1762
|
+
}
|
|
1763
|
+
return oFormat.oFlexibleDayPeriodsNarrow[sFlexibleDayPeriod];
|
|
1764
|
+
}
|
|
1765
|
+
if (oField.digits <= 3) {
|
|
1766
|
+
return oFormat.oFlexibleDayPeriodsAbbrevSt[sFlexibleDayPeriod];
|
|
1767
|
+
}
|
|
1768
|
+
if (oField.digits === 4) {
|
|
1769
|
+
return oFormat.oFlexibleDayPeriodsWideSt[sFlexibleDayPeriod];
|
|
1770
|
+
}
|
|
1771
|
+
return oFormat.oFlexibleDayPeriodsNarrowSt[sFlexibleDayPeriod];
|
|
1772
|
+
},
|
|
1773
|
+
/**
|
|
1774
|
+
* Parses the flexible day period from a given input string.
|
|
1775
|
+
*
|
|
1776
|
+
* @param {string} sValue
|
|
1777
|
+
* The given input, e.g. "in the afternoon 01:37"
|
|
1778
|
+
* @param {Object<string, any>} oPart
|
|
1779
|
+
* The date pattern field as parsed by {@link DateFormat#parseCldrDatePattern}
|
|
1780
|
+
* @param {sap.ui.core.format.DateFormat} oFormat
|
|
1781
|
+
* The <code>DateFormat</code> instance
|
|
1782
|
+
* @param {object} oConfig
|
|
1783
|
+
* The configuration object for parsing the value
|
|
1784
|
+
* @returns {{flexDayPeriod: string, length: number}|{valid: boolean}}
|
|
1785
|
+
* An object with the parsed <code>flexDayPeriod</code> and the <code>length</code>
|
|
1786
|
+
* value of the match; otherwise, an object with property <code>valid</code>
|
|
1787
|
+
* <code>false</code> if it could not be parsed correctly or in case it is attempted
|
|
1788
|
+
* to parse a string with a stand-alone format
|
|
1789
|
+
*/
|
|
1790
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1791
|
+
var i,
|
|
1792
|
+
oFound,
|
|
1793
|
+
oVariant,
|
|
1794
|
+
bContainsHour = oFormat.aFormatArray.some(function (oFormatElement) {
|
|
1795
|
+
return "hHKk".includes(oFormatElement.symbol);
|
|
1796
|
+
}),
|
|
1797
|
+
// "aFlexibleDayPeriodVariants" is ordered from "wide" to "narrow" to find the
|
|
1798
|
+
// longest match
|
|
1799
|
+
aFlexibleDayPeriodVariants = [oFormat.oFlexibleDayPeriodsWide, oFormat.oFlexibleDayPeriodsAbbrev, oFormat.oFlexibleDayPeriodsNarrow];
|
|
1800
|
+
if (bContainsHour) {
|
|
1801
|
+
for (i = 0; i < aFlexibleDayPeriodVariants.length; i++) {
|
|
1802
|
+
oVariant = aFlexibleDayPeriodVariants[i];
|
|
1803
|
+
oFound = oParseHelper.findEntry(sValue, Object.values(oVariant), oFormat.oLocaleData.sCLDRLocaleId);
|
|
1804
|
+
if (oFound.index !== -1) {
|
|
1805
|
+
return {
|
|
1806
|
+
flexDayPeriod: Object.keys(oVariant)[oFound.index],
|
|
1807
|
+
length: oFound.length
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1812
|
+
return {
|
|
1813
|
+
valid: false
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
}),
|
|
1817
|
+
"H": DateFormat._createPatternSymbol({
|
|
1818
|
+
name: "hour0_23",
|
|
1819
|
+
format: function (oField, oDate) {
|
|
1820
|
+
var iHours = oDate.getUTCHours();
|
|
1821
|
+
return String(iHours).padStart(oField.digits, "0");
|
|
1822
|
+
},
|
|
1823
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1824
|
+
var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)),
|
|
1825
|
+
iHours = parseInt(sPart),
|
|
1826
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < 2,
|
|
1827
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1828
|
+
if (oConfig.strict && iHours > 23) {
|
|
1829
|
+
bValid = false;
|
|
1830
|
+
}
|
|
1831
|
+
return {
|
|
1832
|
+
hour: iHours,
|
|
1833
|
+
length: sPart.length,
|
|
1834
|
+
valid: bValid
|
|
1835
|
+
};
|
|
1836
|
+
},
|
|
1837
|
+
isNumeric: true
|
|
1838
|
+
}),
|
|
1839
|
+
"k": DateFormat._createPatternSymbol({
|
|
1840
|
+
name: "hour1_24",
|
|
1841
|
+
format: function (oField, oDate) {
|
|
1842
|
+
var iHours = oDate.getUTCHours();
|
|
1843
|
+
var sHours = iHours === 0 ? "24" : String(iHours);
|
|
1844
|
+
return sHours.padStart(oField.digits, "0");
|
|
1845
|
+
},
|
|
1846
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1847
|
+
var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)),
|
|
1848
|
+
iHours = parseInt(sPart),
|
|
1849
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < 2,
|
|
1850
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1851
|
+
if (iHours === 24) {
|
|
1852
|
+
iHours = 0;
|
|
1853
|
+
}
|
|
1854
|
+
if (oConfig.strict && iHours > 23) {
|
|
1855
|
+
bValid = false;
|
|
1856
|
+
}
|
|
1857
|
+
return {
|
|
1858
|
+
hour: iHours,
|
|
1859
|
+
length: sPart.length,
|
|
1860
|
+
valid: bValid
|
|
1861
|
+
};
|
|
1862
|
+
},
|
|
1863
|
+
isNumeric: true
|
|
1864
|
+
}),
|
|
1865
|
+
"K": DateFormat._createPatternSymbol({
|
|
1866
|
+
name: "hour0_11",
|
|
1867
|
+
format: function (oField, oDate) {
|
|
1868
|
+
var iHours = oDate.getUTCHours();
|
|
1869
|
+
var sHours = String(iHours > 11 ? iHours - 12 : iHours);
|
|
1870
|
+
return sHours.padStart(oField.digits, "0");
|
|
1871
|
+
},
|
|
1872
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1873
|
+
var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)),
|
|
1874
|
+
iHours = parseInt(sPart),
|
|
1875
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < 2,
|
|
1876
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1877
|
+
if (oConfig.strict && iHours > 11) {
|
|
1878
|
+
bValid = false;
|
|
1879
|
+
}
|
|
1880
|
+
return {
|
|
1881
|
+
hour: iHours,
|
|
1882
|
+
length: sPart.length,
|
|
1883
|
+
valid: bValid
|
|
1884
|
+
};
|
|
1885
|
+
},
|
|
1886
|
+
isNumeric: true
|
|
1887
|
+
}),
|
|
1888
|
+
"h": DateFormat._createPatternSymbol({
|
|
1889
|
+
name: "hour1_12",
|
|
1890
|
+
format: function (oField, oDate) {
|
|
1891
|
+
var iHours = oDate.getUTCHours();
|
|
1892
|
+
var sHours;
|
|
1893
|
+
if (iHours > 12) {
|
|
1894
|
+
sHours = String(iHours - 12);
|
|
1895
|
+
} else if (iHours === 0) {
|
|
1896
|
+
sHours = "12";
|
|
1897
|
+
} else {
|
|
1898
|
+
sHours = String(iHours);
|
|
1899
|
+
}
|
|
1900
|
+
return sHours.padStart(oField.digits, "0");
|
|
1901
|
+
},
|
|
1902
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1903
|
+
var bPM = oConfig.dateValue.pm,
|
|
1904
|
+
sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)),
|
|
1905
|
+
iHours = parseInt(sPart),
|
|
1906
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < 2,
|
|
1907
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1908
|
+
if (iHours === 12) {
|
|
1909
|
+
iHours = 0;
|
|
1910
|
+
// change the PM only when it's not yet parsed
|
|
1911
|
+
// 12:00 defaults to 12:00 PM
|
|
1912
|
+
bPM = bPM === undefined ? true : bPM;
|
|
1913
|
+
}
|
|
1914
|
+
if (oConfig.strict && iHours > 11) {
|
|
1915
|
+
bValid = false;
|
|
1916
|
+
}
|
|
1917
|
+
return {
|
|
1918
|
+
hour: iHours,
|
|
1919
|
+
length: sPart.length,
|
|
1920
|
+
pm: bPM,
|
|
1921
|
+
valid: bValid
|
|
1922
|
+
};
|
|
1923
|
+
},
|
|
1924
|
+
isNumeric: true
|
|
1925
|
+
}),
|
|
1926
|
+
"m": DateFormat._createPatternSymbol({
|
|
1927
|
+
name: "minute",
|
|
1928
|
+
format: function (oField, oDate) {
|
|
1929
|
+
var iMinutes = oDate.getUTCMinutes();
|
|
1930
|
+
return String(iMinutes).padStart(oField.digits, "0");
|
|
1931
|
+
},
|
|
1932
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1933
|
+
var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)),
|
|
1934
|
+
iMinutes = parseInt(sPart),
|
|
1935
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < 2,
|
|
1936
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1937
|
+
if (oConfig.strict && iMinutes > 59) {
|
|
1938
|
+
bValid = false;
|
|
1939
|
+
}
|
|
1940
|
+
return {
|
|
1941
|
+
length: sPart.length,
|
|
1942
|
+
minute: iMinutes,
|
|
1943
|
+
valid: bValid
|
|
1944
|
+
};
|
|
1945
|
+
},
|
|
1946
|
+
isNumeric: true
|
|
1947
|
+
}),
|
|
1948
|
+
"s": DateFormat._createPatternSymbol({
|
|
1949
|
+
name: "second",
|
|
1950
|
+
format: function (oField, oDate) {
|
|
1951
|
+
var iSeconds = oDate.getUTCSeconds();
|
|
1952
|
+
return String(iSeconds).padStart(oField.digits, "0");
|
|
1953
|
+
},
|
|
1954
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1955
|
+
var iExpectedDigits = Math.max(oPart.digits, 2),
|
|
1956
|
+
sPart = oParseHelper.findNumbers(sValue, iExpectedDigits),
|
|
1957
|
+
bPartInvalid = sPart === "" || oConfig.exactLength && sPart.length < iExpectedDigits,
|
|
1958
|
+
iSeconds = parseInt(sPart),
|
|
1959
|
+
bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
|
|
1960
|
+
if (oConfig.strict && iSeconds > 59) {
|
|
1961
|
+
bValid = false;
|
|
1962
|
+
}
|
|
1963
|
+
return {
|
|
1964
|
+
length: sPart.length,
|
|
1965
|
+
second: iSeconds,
|
|
1966
|
+
valid: bValid
|
|
1967
|
+
};
|
|
1968
|
+
},
|
|
1969
|
+
isNumeric: true
|
|
1970
|
+
}),
|
|
1971
|
+
"S": DateFormat._createPatternSymbol({
|
|
1972
|
+
name: "fractionalsecond",
|
|
1973
|
+
format: function (oField, oDate) {
|
|
1974
|
+
var iMilliseconds = oDate.getUTCMilliseconds();
|
|
1975
|
+
var sMilliseconds = String(iMilliseconds);
|
|
1976
|
+
var sFractionalseconds = sMilliseconds.padStart(3, "0");
|
|
1977
|
+
sFractionalseconds = sFractionalseconds.substr(0, oField.digits);
|
|
1978
|
+
sFractionalseconds = sFractionalseconds.padEnd(oField.digits, "0");
|
|
1979
|
+
return sFractionalseconds;
|
|
1980
|
+
},
|
|
1981
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
1982
|
+
var sPart = oParseHelper.findNumbers(sValue, oPart.digits),
|
|
1983
|
+
iLength = sPart.length,
|
|
1984
|
+
bPartInvalid = oConfig.exactLength && iLength < oPart.digits;
|
|
1985
|
+
sPart = sPart.substr(0, 3);
|
|
1986
|
+
sPart = sPart.padEnd(3, "0");
|
|
1987
|
+
var iMilliseconds = parseInt(sPart);
|
|
1988
|
+
return {
|
|
1989
|
+
length: iLength,
|
|
1990
|
+
millisecond: iMilliseconds,
|
|
1991
|
+
valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat)
|
|
1992
|
+
};
|
|
1993
|
+
},
|
|
1994
|
+
isNumeric: true
|
|
1995
|
+
}),
|
|
1996
|
+
"z": DateFormat._createPatternSymbol({
|
|
1997
|
+
name: "timezoneGeneral",
|
|
1998
|
+
format: function (oField, oDate, bUTC, oFormat, sTimezone) {
|
|
1999
|
+
//TODO getTimezoneLong and getTimezoneShort does not exist on Date object
|
|
2000
|
+
//-> this is a preparation for a future full timezone support (only used by unit test so far)
|
|
2001
|
+
if (oField.digits > 3 && oDate.getTimezoneLong && oDate.getTimezoneLong()) {
|
|
2002
|
+
return oDate.getTimezoneLong();
|
|
2003
|
+
} else if (oDate.getTimezoneShort && oDate.getTimezoneShort()) {
|
|
2004
|
+
return oDate.getTimezoneShort();
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
// valid for zzzz (fallback to OOOO)
|
|
2008
|
+
var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
|
|
2009
|
+
var sTimeZone = "GMT";
|
|
2010
|
+
var iTZOffset = Math.abs(iTimezoneOffset / 60);
|
|
2011
|
+
var bPositiveOffset = iTimezoneOffset > 0;
|
|
2012
|
+
var iHourOffset = Math.floor(iTZOffset / 60);
|
|
2013
|
+
var iMinuteOffset = Math.floor(iTZOffset % 60);
|
|
2014
|
+
if (!bUTC && iTZOffset !== 0) {
|
|
2015
|
+
sTimeZone += bPositiveOffset ? "-" : "+";
|
|
2016
|
+
sTimeZone += String(iHourOffset).padStart(2, "0");
|
|
2017
|
+
sTimeZone += ":";
|
|
2018
|
+
sTimeZone += String(iMinuteOffset).padStart(2, "0");
|
|
2019
|
+
} else {
|
|
2020
|
+
sTimeZone += "Z";
|
|
2021
|
+
}
|
|
2022
|
+
return sTimeZone;
|
|
2023
|
+
},
|
|
2024
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
2025
|
+
var iLength = 0;
|
|
2026
|
+
var iTZDiff;
|
|
2027
|
+
var oTZ = sValue.substring(0, 3);
|
|
2028
|
+
if (oTZ === "GMT" || oTZ === "UTC") {
|
|
2029
|
+
iLength = 3;
|
|
2030
|
+
} else if (sValue.substring(0, 2) === "UT") {
|
|
2031
|
+
iLength = 2;
|
|
2032
|
+
} else if (sValue.charAt(0) === "Z") {
|
|
2033
|
+
iLength = 1;
|
|
2034
|
+
iTZDiff = 0;
|
|
2035
|
+
} else {
|
|
2036
|
+
return {
|
|
2037
|
+
error: "cannot be parsed correctly by sap.ui.core.format.DateFormat: The given timezone is not supported!"
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
if (sValue.charAt(0) !== "Z") {
|
|
2041
|
+
var oParsedTZ = oParseHelper.parseTZ(sValue.substr(iLength), true);
|
|
2042
|
+
iLength += oParsedTZ.length;
|
|
2043
|
+
iTZDiff = oParsedTZ.tzDiff;
|
|
2044
|
+
}
|
|
2045
|
+
return {
|
|
2046
|
+
length: iLength,
|
|
2047
|
+
tzDiff: iTZDiff
|
|
2048
|
+
};
|
|
2049
|
+
}
|
|
2050
|
+
}),
|
|
2051
|
+
"Z": DateFormat._createPatternSymbol({
|
|
2052
|
+
name: "timezoneRFC822",
|
|
2053
|
+
format: function (oField, oDate, bUTC, oFormat, sTimezone) {
|
|
2054
|
+
var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
|
|
2055
|
+
var iTZOffset = Math.abs(iTimezoneOffset / 60);
|
|
2056
|
+
var bPositiveOffset = iTimezoneOffset > 0;
|
|
2057
|
+
var iHourOffset = Math.floor(iTZOffset / 60);
|
|
2058
|
+
var iMinuteOffset = Math.floor(iTZOffset % 60);
|
|
2059
|
+
var sTimeZone = "";
|
|
2060
|
+
|
|
2061
|
+
// valid for Z-ZZZ
|
|
2062
|
+
// per RFC822 a timezone always has 4 digits
|
|
2063
|
+
// UTC+0: "+0000"
|
|
2064
|
+
// UTC-7: "-0700"
|
|
2065
|
+
// UTC+2: "+0200"
|
|
2066
|
+
// https://tools.ietf.org/html/rfc822 paragraph 5.1
|
|
2067
|
+
if (!bUTC) {
|
|
2068
|
+
sTimeZone += bPositiveOffset ? "-" : "+";
|
|
2069
|
+
sTimeZone += String(iHourOffset).padStart(2, "0");
|
|
2070
|
+
sTimeZone += String(iMinuteOffset).padStart(2, "0");
|
|
2071
|
+
}
|
|
2072
|
+
return sTimeZone;
|
|
2073
|
+
},
|
|
2074
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
2075
|
+
return oParseHelper.parseTZ(sValue, false);
|
|
2076
|
+
}
|
|
2077
|
+
}),
|
|
2078
|
+
"X": DateFormat._createPatternSymbol({
|
|
2079
|
+
name: "timezoneISO8601",
|
|
2080
|
+
format: function (oField, oDate, bUTC, oFormat, sTimezone) {
|
|
2081
|
+
/*
|
|
2082
|
+
* Mountain Standard Time (MST, UTC-7)
|
|
2083
|
+
* X: "-07"
|
|
2084
|
+
* XX, XXXX: "-0700"
|
|
2085
|
+
* XXX, XXXXX: "-07:00"
|
|
2086
|
+
*/
|
|
2087
|
+
|
|
2088
|
+
/*
|
|
2089
|
+
* Central European Summer Time (CEST, UTC+2)
|
|
2090
|
+
* X: "+02"
|
|
2091
|
+
* XX, XXXX: "+0200"
|
|
2092
|
+
* XXX, XXXXX: "+02:00"
|
|
2093
|
+
*/
|
|
2094
|
+
|
|
2095
|
+
/*
|
|
2096
|
+
* Indian Standard Time (IST, UTC+5:30)
|
|
2097
|
+
* X: "+0530"
|
|
2098
|
+
* XX, XXXX: "+0530"
|
|
2099
|
+
* XXX, XXXXX: "+05:30"
|
|
2100
|
+
*/
|
|
2101
|
+
|
|
2102
|
+
/*
|
|
2103
|
+
* Greenwich Mean Time (GMT, UTC+0)
|
|
2104
|
+
* X: "Z"
|
|
2105
|
+
* XX, XXXX: "Z"
|
|
2106
|
+
* XXX, XXXXX: "Z"
|
|
2107
|
+
*/
|
|
2108
|
+
|
|
2109
|
+
// @see http://www.unicode.org/reports/tr35/tr35-dates.html#Time_Zone_Goals
|
|
2110
|
+
var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
|
|
2111
|
+
var iTZOffset = Math.abs(iTimezoneOffset / 60);
|
|
2112
|
+
var bPositiveOffset = iTimezoneOffset > 0;
|
|
2113
|
+
var iHourOffset = Math.floor(iTZOffset / 60);
|
|
2114
|
+
var iMinuteOffset = Math.floor(iTZOffset % 60);
|
|
2115
|
+
var sTimeZone = "";
|
|
2116
|
+
if (!bUTC && iTZOffset !== 0) {
|
|
2117
|
+
sTimeZone += bPositiveOffset ? "-" : "+";
|
|
2118
|
+
sTimeZone += String(iHourOffset).padStart(2, "0");
|
|
2119
|
+
if (oField.digits > 1 || iMinuteOffset > 0) {
|
|
2120
|
+
if (oField.digits === 3 || oField.digits === 5) {
|
|
2121
|
+
sTimeZone += ":";
|
|
2122
|
+
}
|
|
2123
|
+
sTimeZone += String(iMinuteOffset).padStart(2, "0");
|
|
2124
|
+
}
|
|
2125
|
+
} else {
|
|
2126
|
+
sTimeZone += "Z";
|
|
2127
|
+
}
|
|
2128
|
+
return sTimeZone;
|
|
2129
|
+
},
|
|
2130
|
+
parse: function (sValue, oPart, oFormat, oConfig) {
|
|
2131
|
+
if (sValue.charAt(0) === "Z") {
|
|
2132
|
+
return {
|
|
2133
|
+
length: 1,
|
|
2134
|
+
tzDiff: 0
|
|
2135
|
+
};
|
|
2136
|
+
} else {
|
|
2137
|
+
return oParseHelper.parseTZ(sValue, oPart.digits === 3 || oPart.digits === 5);
|
|
2138
|
+
}
|
|
2139
|
+
}
|
|
2140
|
+
}),
|
|
2141
|
+
"V": DateFormat._createPatternSymbol({
|
|
2142
|
+
name: "timezoneID",
|
|
2143
|
+
format: function (oField, oDate, bUTC, oFormat, sTimezone) {
|
|
2144
|
+
// Only VV is supported
|
|
2145
|
+
// The IANA time zone ID
|
|
2146
|
+
// e.g. America/New_York
|
|
2147
|
+
// @see http://www.unicode.org/reports/tr35/tr35-dates.html#Date_Format_Patterns
|
|
2148
|
+
if (!bUTC && oField.digits === 2) {
|
|
2149
|
+
// fallback for unknown but valid IANA time zone IDs (IANA is a living standard and the browser
|
|
2150
|
+
// might support more, while the CLDR data is fixed) such that the user can see, that there is no
|
|
2151
|
+
// translation
|
|
2152
|
+
return oFormat.oLocaleData.getTimezoneTranslations()[sTimezone] || sTimezone;
|
|
2153
|
+
}
|
|
2154
|
+
return "";
|
|
2155
|
+
},
|
|
2156
|
+
parse: function (sValue, oPart, oFormat, oConfig, sTimezone) {
|
|
2157
|
+
var oTimezoneParsed = {
|
|
2158
|
+
timezone: "",
|
|
2159
|
+
length: 0
|
|
2160
|
+
};
|
|
2161
|
+
|
|
2162
|
+
// VV - The long IANA time zone ID
|
|
2163
|
+
if (oPart.digits === 2) {
|
|
2164
|
+
var mTimezoneTranslations = oFormat.oLocaleData.getTimezoneTranslations();
|
|
2165
|
+
|
|
2166
|
+
// shortcut, first try the time zone parameter
|
|
2167
|
+
if (sValue === mTimezoneTranslations[sTimezone]) {
|
|
2168
|
+
return {
|
|
2169
|
+
timezone: sTimezone,
|
|
2170
|
+
length: sValue.length
|
|
2171
|
+
};
|
|
2172
|
+
}
|
|
2173
|
+
var aTimezoneTranslations = Object.values(mTimezoneTranslations);
|
|
2174
|
+
var oTimezoneResult = oParseHelper.findEntry(sValue, aTimezoneTranslations, oFormat.oLocaleData.sCLDRLocaleId);
|
|
2175
|
+
if (oTimezoneResult.index !== -1) {
|
|
2176
|
+
return {
|
|
2177
|
+
timezone: Object.keys(mTimezoneTranslations)[oTimezoneResult.index],
|
|
2178
|
+
length: oTimezoneResult.length
|
|
2179
|
+
};
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
// fallback for IANA time zone IDs
|
|
2183
|
+
var sCurrentValue = "";
|
|
2184
|
+
// find the longest valid time zone ID at the beginning of sValue
|
|
2185
|
+
for (var i = sValue.length; i > 0; i -= 1) {
|
|
2186
|
+
sCurrentValue = sValue.slice(0, i);
|
|
2187
|
+
if (TimezoneUtil.isValidTimezone(sCurrentValue)) {
|
|
2188
|
+
oTimezoneParsed.timezone = sCurrentValue;
|
|
2189
|
+
oTimezoneParsed.length = sCurrentValue.length;
|
|
2190
|
+
break;
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
return oTimezoneParsed;
|
|
2195
|
+
}
|
|
2196
|
+
})
|
|
2197
|
+
};
|
|
2198
|
+
DateFormat.prototype._format = function (oJSDate, bUTC, sTimezone) {
|
|
2199
|
+
if (this.oFormatOptions.relative) {
|
|
2200
|
+
var sRes = this.formatRelative(oJSDate, bUTC, this.oFormatOptions.relativeRange, sTimezone);
|
|
2201
|
+
if (sRes) {
|
|
2202
|
+
//Stop when relative formatting possible, else go on with standard formatting
|
|
2203
|
+
return sRes;
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
var sCalendarType = this.oFormatOptions.calendarType;
|
|
2207
|
+
var oDate = UniversalDate.getInstance(oJSDate, sCalendarType);
|
|
2208
|
+
var aBuffer = [],
|
|
2209
|
+
oPart,
|
|
2210
|
+
sResult,
|
|
2211
|
+
sSymbol;
|
|
2212
|
+
for (var i = 0; i < this.aFormatArray.length; i++) {
|
|
2213
|
+
oPart = this.aFormatArray[i];
|
|
2214
|
+
sSymbol = oPart.symbol || "";
|
|
2215
|
+
aBuffer.push(this.oSymbols[sSymbol].format(oPart, oDate, bUTC, this, sTimezone));
|
|
2216
|
+
}
|
|
2217
|
+
sResult = aBuffer.join("");
|
|
2218
|
+
if (Supportability.collectOriginInfo()) {
|
|
2219
|
+
// String object is created on purpose and must not be a string literal
|
|
2220
|
+
// eslint-disable-next-line no-new-wrappers
|
|
2221
|
+
sResult = new String(sResult);
|
|
2222
|
+
sResult.originInfo = {
|
|
2223
|
+
source: "Common Locale Data Repository",
|
|
2224
|
+
locale: this.oLocale.toString(),
|
|
2225
|
+
style: this.oFormatOptions.style,
|
|
2226
|
+
pattern: this.oFormatOptions.pattern
|
|
2227
|
+
};
|
|
2228
|
+
}
|
|
2229
|
+
return sResult;
|
|
2230
|
+
};
|
|
2231
|
+
|
|
2232
|
+
/**
|
|
2233
|
+
* Format a date according to the given format options.
|
|
2234
|
+
*
|
|
2235
|
+
* Uses the timezone from {@link sap.ui.core.Configuration#getTimezone}, which falls back to the
|
|
2236
|
+
* browser's local timezone to convert the given date.
|
|
2237
|
+
*
|
|
2238
|
+
* When using instances from getDateTimeWithTimezoneInstance, please see the corresponding documentation:
|
|
2239
|
+
* {@link sap.ui.core.format.DateFormat.DateTimeWithTimezone#format}.
|
|
2240
|
+
*
|
|
2241
|
+
* @example <caption>DateTime (assuming timezone "Europe/Berlin")</caption>
|
|
2242
|
+
* var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z");
|
|
2243
|
+
* DateFormat.getDateTimeInstance().format(oDate);
|
|
2244
|
+
* // output: "Dec 24, 2021, 2:37:00 PM"
|
|
2245
|
+
*
|
|
2246
|
+
* @param {Date|Date[]} vJSDate the value to format
|
|
2247
|
+
* @param {boolean} [bUTC=false] whether to use UTC
|
|
2248
|
+
* @return {string} the formatted output value. If an invalid date is given, an empty string is returned.
|
|
2249
|
+
* @public
|
|
2250
|
+
*/
|
|
2251
|
+
DateFormat.prototype.format = function (vJSDate, bUTC) {
|
|
2252
|
+
var sTimezone;
|
|
2253
|
+
if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
|
|
2254
|
+
// UTC and timezone are not supported at the same time, therefore set bUTC to false
|
|
2255
|
+
sTimezone = bUTC;
|
|
2256
|
+
bUTC = false;
|
|
2257
|
+
checkTimezoneParameterType(sTimezone);
|
|
2258
|
+
if (sTimezone && !TimezoneUtil.isValidTimezone(sTimezone)) {
|
|
2259
|
+
Log.error("The given timezone isn't valid.");
|
|
2260
|
+
return "";
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
var sCalendarType = this.oFormatOptions.calendarType,
|
|
2264
|
+
sResult;
|
|
2265
|
+
if (bUTC === undefined) {
|
|
2266
|
+
bUTC = this.oFormatOptions.UTC;
|
|
2267
|
+
}
|
|
2268
|
+
|
|
2269
|
+
// default the timezone to the local timezone to always enforce the conversion
|
|
2270
|
+
sTimezone = sTimezone || Configuration.getTimezone();
|
|
2271
|
+
if (Array.isArray(vJSDate)) {
|
|
2272
|
+
if (!this.oFormatOptions.interval) {
|
|
2273
|
+
Log.error("Non-interval DateFormat can't format more than one date instance.");
|
|
2274
|
+
return "";
|
|
2275
|
+
}
|
|
2276
|
+
if (vJSDate.length !== 2) {
|
|
2277
|
+
Log.error("Interval DateFormat can only format with 2 date instances but " + vJSDate.length + " is given.");
|
|
2278
|
+
return "";
|
|
2279
|
+
}
|
|
2280
|
+
vJSDate = vJSDate.map(function (oJSDate) {
|
|
2281
|
+
return convertToTimezone(oJSDate, sTimezone, bUTC);
|
|
2282
|
+
});
|
|
2283
|
+
if (this.oFormatOptions.singleIntervalValue) {
|
|
2284
|
+
if (vJSDate[0] === null) {
|
|
2285
|
+
Log.error("First date instance which is passed to the interval DateFormat shouldn't be null.");
|
|
2286
|
+
return "";
|
|
2287
|
+
}
|
|
2288
|
+
if (vJSDate[1] === null) {
|
|
2289
|
+
sResult = this._format(vJSDate[0], bUTC, sTimezone);
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
if (sResult === undefined) {
|
|
2293
|
+
if (!vJSDate.every(isValidDateObject)) {
|
|
2294
|
+
Log.error("At least one date instance which is passed to the interval DateFormat isn't valid.");
|
|
2295
|
+
return "";
|
|
2296
|
+
}
|
|
2297
|
+
sResult = this._formatInterval(vJSDate, bUTC);
|
|
2298
|
+
}
|
|
2299
|
+
} else {
|
|
2300
|
+
if (!isValidDateObject(vJSDate)) {
|
|
2301
|
+
// Although an invalid date was given, the DATETIME_WITH_TIMEZONE instance might
|
|
2302
|
+
// have a pattern with the timezone (VV) inside then the IANA timezone ID is returned
|
|
2303
|
+
if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE && this.oFormatOptions.pattern.includes("VV")) {
|
|
2304
|
+
return this.oLocaleData.getTimezoneTranslations()[sTimezone] || sTimezone;
|
|
2305
|
+
}
|
|
2306
|
+
Log.error("The given date instance isn't valid.");
|
|
2307
|
+
return "";
|
|
2308
|
+
}
|
|
2309
|
+
if (this.oFormatOptions.interval) {
|
|
2310
|
+
Log.error("Interval DateFormat expects an array with two dates for the first argument but only one date is given.");
|
|
2311
|
+
return "";
|
|
2312
|
+
}
|
|
2313
|
+
vJSDate = convertToTimezone(vJSDate, sTimezone, bUTC);
|
|
2314
|
+
sResult = this._format(vJSDate, bUTC, sTimezone);
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
// Support Japanese Gannen instead of Ichinen for first year of the era
|
|
2318
|
+
if (sCalendarType === CalendarType.Japanese && this.oLocale.getLanguage() === "ja") {
|
|
2319
|
+
sResult = sResult.replace(/(^|[^\d])1年/g, "$1元年");
|
|
2320
|
+
}
|
|
2321
|
+
return sResult;
|
|
2322
|
+
};
|
|
2323
|
+
|
|
2324
|
+
/**
|
|
2325
|
+
* Checks whether the interval to be formatted has to use the pattern of a custom interval delimiter.
|
|
2326
|
+
*
|
|
2327
|
+
* @param {object} oDiffFields
|
|
2328
|
+
* An object describing which date information is required for this instance's interval format,
|
|
2329
|
+
* for example <code>{"Day": true, "Minutes": true}</code>
|
|
2330
|
+
* @returns {boolean}
|
|
2331
|
+
* Whether to use the custom interval delimiter pattern
|
|
2332
|
+
*
|
|
2333
|
+
* @private
|
|
2334
|
+
*/
|
|
2335
|
+
DateFormat.prototype._useCustomIntervalDelimiter = function (oDiffFields) {
|
|
2336
|
+
var aTokens;
|
|
2337
|
+
if (!this.oFormatOptions.intervalDelimiter) {
|
|
2338
|
+
return false;
|
|
2339
|
+
}
|
|
2340
|
+
// If there are no differences in the date/time parts specified by "oFormatOptions.format", a single value is
|
|
2341
|
+
// formatted and there is no need to use the custom delimiter pattern.
|
|
2342
|
+
if (this.oFormatOptions.format) {
|
|
2343
|
+
aTokens = this.oLocaleData._parseSkeletonFormat(this.oFormatOptions.format);
|
|
2344
|
+
return aTokens.some(function (oToken) {
|
|
2345
|
+
return oDiffFields[oToken.group];
|
|
2346
|
+
});
|
|
2347
|
+
}
|
|
2348
|
+
return true;
|
|
2349
|
+
};
|
|
2350
|
+
DateFormat.prototype._formatInterval = function (aJSDates, bUTC) {
|
|
2351
|
+
var oDate,
|
|
2352
|
+
oPart,
|
|
2353
|
+
sPattern,
|
|
2354
|
+
sSymbol,
|
|
2355
|
+
aBuffer = [],
|
|
2356
|
+
sCalendarType = this.oFormatOptions.calendarType,
|
|
2357
|
+
aFormatArray = [],
|
|
2358
|
+
oFromDate = UniversalDate.getInstance(aJSDates[0], sCalendarType),
|
|
2359
|
+
oToDate = UniversalDate.getInstance(aJSDates[1], sCalendarType),
|
|
2360
|
+
oDiffFields = this._getDiffFields([oFromDate, oToDate]);
|
|
2361
|
+
if (!oDiffFields) {
|
|
2362
|
+
return this._format(aJSDates[0], bUTC);
|
|
2363
|
+
}
|
|
2364
|
+
if (this._useCustomIntervalDelimiter(oDiffFields)) {
|
|
2365
|
+
sPattern = this.intervalPatterns[0];
|
|
2366
|
+
} else if (this.oFormatOptions.format) {
|
|
2367
|
+
// when 'format' option is set, generate the pattern based on the greatest difference
|
|
2368
|
+
sPattern = this.oLocaleData.getCustomIntervalPattern(this.oFormatOptions.format, oDiffFields, sCalendarType);
|
|
2369
|
+
} else {
|
|
2370
|
+
sPattern = this.oLocaleData.getCombinedIntervalPattern(this.oFormatOptions.pattern, sCalendarType);
|
|
2371
|
+
}
|
|
2372
|
+
aFormatArray = this.parseCldrDatePattern(sPattern);
|
|
2373
|
+
oDate = oFromDate;
|
|
2374
|
+
for (var i = 0; i < aFormatArray.length; i++) {
|
|
2375
|
+
oPart = aFormatArray[i];
|
|
2376
|
+
sSymbol = oPart.symbol || "";
|
|
2377
|
+
if (oPart.repeat) {
|
|
2378
|
+
oDate = oToDate;
|
|
2379
|
+
}
|
|
2380
|
+
aBuffer.push(this.oSymbols[sSymbol].format(oPart, oDate, bUTC, this));
|
|
2381
|
+
}
|
|
2382
|
+
return aBuffer.join("");
|
|
2383
|
+
};
|
|
2384
|
+
var mFieldToGroup = {
|
|
2385
|
+
Era: "Era",
|
|
2386
|
+
FullYear: "Year",
|
|
2387
|
+
Quarter: "Quarter",
|
|
2388
|
+
Month: "Month",
|
|
2389
|
+
Week: "Week",
|
|
2390
|
+
Date: "Day",
|
|
2391
|
+
DayPeriod: "DayPeriod",
|
|
2392
|
+
Hours: "Hour",
|
|
2393
|
+
Minutes: "Minute",
|
|
2394
|
+
Seconds: "Second"
|
|
2395
|
+
};
|
|
2396
|
+
|
|
2397
|
+
/**
|
|
2398
|
+
* Returns an object containing the relevant date/time parts that differ in the two given dates.
|
|
2399
|
+
*
|
|
2400
|
+
* @param {sap.ui.core.date.UniversalDate[]} aDates
|
|
2401
|
+
* An array with two UniversalDate instances representing the start and the end date of the interval;
|
|
2402
|
+
* the dates are expected to be in UTC time zone
|
|
2403
|
+
* @returns {Object<string, boolean>|null}
|
|
2404
|
+
* An object containing the different date/time parts, or <code>null</code> if the dates are the same
|
|
2405
|
+
*
|
|
2406
|
+
* @private
|
|
2407
|
+
*/
|
|
2408
|
+
DateFormat.prototype._getDiffFields = function (aDates) {
|
|
2409
|
+
var bDiffFound = false,
|
|
2410
|
+
mDiff = {};
|
|
2411
|
+
this.aIntervalCompareFields.forEach(function (sField) {
|
|
2412
|
+
var sGetterPrefix = "getUTC",
|
|
2413
|
+
sMethodName = sGetterPrefix + sField,
|
|
2414
|
+
sFieldGroup = mFieldToGroup[sField],
|
|
2415
|
+
vFromValue = aDates[0][sMethodName].apply(aDates[0]),
|
|
2416
|
+
vToValue = aDates[1][sMethodName].apply(aDates[1]);
|
|
2417
|
+
if (!deepEqual(vFromValue, vToValue)) {
|
|
2418
|
+
bDiffFound = true;
|
|
2419
|
+
mDiff[sFieldGroup] = true;
|
|
2420
|
+
}
|
|
2421
|
+
});
|
|
2422
|
+
if (bDiffFound) {
|
|
2423
|
+
return mDiff;
|
|
2424
|
+
}
|
|
2425
|
+
return null;
|
|
2426
|
+
};
|
|
2427
|
+
DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict, sTimezone) {
|
|
2428
|
+
var sFlexibleDayPeriod,
|
|
2429
|
+
oNextPart,
|
|
2430
|
+
oPart,
|
|
2431
|
+
bPM,
|
|
2432
|
+
oPrevPart,
|
|
2433
|
+
oResult,
|
|
2434
|
+
sSubValue,
|
|
2435
|
+
oDateValue = {
|
|
2436
|
+
valid: true,
|
|
2437
|
+
lastTimezonePatternSymbol: ""
|
|
2438
|
+
},
|
|
2439
|
+
iIndex = 0,
|
|
2440
|
+
oParseConf = {
|
|
2441
|
+
formatArray: aFormatArray,
|
|
2442
|
+
dateValue: oDateValue,
|
|
2443
|
+
strict: bStrict
|
|
2444
|
+
},
|
|
2445
|
+
that = this;
|
|
2446
|
+
function getSymbol(oPart0) {
|
|
2447
|
+
return that.oSymbols[oPart0.symbol || ""];
|
|
2448
|
+
}
|
|
2449
|
+
function isNumeric(oPart0) {
|
|
2450
|
+
return !!oPart0 && getSymbol(oPart0).isNumeric(oPart0.digits);
|
|
2451
|
+
}
|
|
2452
|
+
for (var i = 0; i < aFormatArray.length; i++) {
|
|
2453
|
+
sSubValue = sValue.substr(iIndex);
|
|
2454
|
+
oPart = aFormatArray[i];
|
|
2455
|
+
oPrevPart = aFormatArray[i - 1];
|
|
2456
|
+
oNextPart = aFormatArray[i + 1];
|
|
2457
|
+
oParseConf.index = i;
|
|
2458
|
+
oParseConf.exactLength = isNumeric(oPart) && (isNumeric(oPrevPart) || isNumeric(oNextPart));
|
|
2459
|
+
oResult = getSymbol(oPart).parse(sSubValue, oPart, this, oParseConf, sTimezone) || {};
|
|
2460
|
+
// Remember the last required timezone difference which needs to be calculated (V pattern) or applied (x and z pattern)
|
|
2461
|
+
if (oResult.tzDiff !== undefined || oResult.timezone) {
|
|
2462
|
+
oResult.lastTimezonePatternSymbol = oPart.symbol;
|
|
2463
|
+
}
|
|
2464
|
+
oDateValue = extend(oDateValue, oResult);
|
|
2465
|
+
if (oResult.valid === false) {
|
|
2466
|
+
break;
|
|
2467
|
+
}
|
|
2468
|
+
iIndex += oResult.length || 0;
|
|
2469
|
+
}
|
|
2470
|
+
oDateValue.index = iIndex;
|
|
2471
|
+
bPM = oDateValue.pm;
|
|
2472
|
+
// "getFlexibleDayPeriodOfTime" is required if the given time is earlier than 12 pm because,
|
|
2473
|
+
// for a "h" pattern it can't distinguished whether e.g. 1 o'clock is meant to be AM or PM
|
|
2474
|
+
if (oDateValue.flexDayPeriod && oDateValue.hour * 60 + (oDateValue.minute || 0) < 720) {
|
|
2475
|
+
sFlexibleDayPeriod = this.oLocaleData.getFlexibleDayPeriodOfTime(oDateValue.hour + 12, oDateValue.minute || 0);
|
|
2476
|
+
bPM = oDateValue.flexDayPeriod === sFlexibleDayPeriod;
|
|
2477
|
+
}
|
|
2478
|
+
if (bPM) {
|
|
2479
|
+
oDateValue.hour += 12;
|
|
2480
|
+
}
|
|
2481
|
+
|
|
2482
|
+
// use dayOfWeek (E) as dayNumberOfWeek (u) if dayNumberOfWeek (u) is not present
|
|
2483
|
+
if (oDateValue.dayNumberOfWeek === undefined && oDateValue.dayOfWeek !== undefined) {
|
|
2484
|
+
oDateValue.dayNumberOfWeek = this._adaptDayOfWeek(oDateValue.dayOfWeek);
|
|
2485
|
+
}
|
|
2486
|
+
if (oDateValue.quarter !== undefined && oDateValue.month === undefined && oDateValue.day === undefined) {
|
|
2487
|
+
oDateValue.month = 3 * oDateValue.quarter;
|
|
2488
|
+
oDateValue.day = 1;
|
|
2489
|
+
}
|
|
2490
|
+
return oDateValue;
|
|
2491
|
+
};
|
|
2492
|
+
DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bStrict, sTimezone) {
|
|
2493
|
+
var aDateValues, iRepeat, oDateValue;
|
|
2494
|
+
|
|
2495
|
+
// Try out with all possible patterns until successfully parse has been done or the end of the array is reached
|
|
2496
|
+
this.intervalPatterns.some(function (sPattern) {
|
|
2497
|
+
var aFormatArray = this.parseCldrDatePattern(sPattern);
|
|
2498
|
+
iRepeat = undefined;
|
|
2499
|
+
|
|
2500
|
+
// loop through aFormatArray until we have found the repeated date symbol and get the index
|
|
2501
|
+
for (var i = 0; i < aFormatArray.length; i++) {
|
|
2502
|
+
if (aFormatArray[i].repeat) {
|
|
2503
|
+
iRepeat = i;
|
|
2504
|
+
break;
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
if (iRepeat === undefined) {
|
|
2508
|
+
// In case of standard date pattern, parse string as single date and put the same date twice into the aDateValues array
|
|
2509
|
+
oDateValue = this._parse(sValue, aFormatArray, bUTC, bStrict, sTimezone);
|
|
2510
|
+
|
|
2511
|
+
// If input value has not been completely parsed, mark it as invalid
|
|
2512
|
+
if (oDateValue.index === 0 || oDateValue.index < sValue.length) {
|
|
2513
|
+
oDateValue.valid = false;
|
|
2514
|
+
}
|
|
2515
|
+
if (oDateValue.valid === false) {
|
|
2516
|
+
return;
|
|
2517
|
+
}
|
|
2518
|
+
aDateValues = [oDateValue, oDateValue];
|
|
2519
|
+
return true;
|
|
2520
|
+
} else {
|
|
2521
|
+
aDateValues = [];
|
|
2522
|
+
|
|
2523
|
+
// Call _parse function with start 0 and end index of repeated symbol
|
|
2524
|
+
oDateValue = this._parse(sValue, aFormatArray.slice(0, iRepeat), bUTC, bStrict, sTimezone);
|
|
2525
|
+
if (oDateValue.valid === false) {
|
|
2526
|
+
return;
|
|
2527
|
+
}
|
|
2528
|
+
aDateValues.push(oDateValue);
|
|
2529
|
+
var iLength = oDateValue.index;
|
|
2530
|
+
|
|
2531
|
+
// Call _parse function with start iRepeat and end of array
|
|
2532
|
+
oDateValue = this._parse(sValue.substring(iLength), aFormatArray.slice(iRepeat), bUTC, bStrict, sTimezone);
|
|
2533
|
+
|
|
2534
|
+
// If input value has not been completely parsed, mark it as invalid
|
|
2535
|
+
if (oDateValue.index === 0 || oDateValue.index + iLength < sValue.length) {
|
|
2536
|
+
oDateValue.valid = false;
|
|
2537
|
+
}
|
|
2538
|
+
if (oDateValue.valid === false) {
|
|
2539
|
+
return;
|
|
2540
|
+
}
|
|
2541
|
+
aDateValues.push(oDateValue);
|
|
2542
|
+
return true;
|
|
2543
|
+
}
|
|
2544
|
+
}.bind(this));
|
|
2545
|
+
return aDateValues;
|
|
2546
|
+
};
|
|
2547
|
+
|
|
2548
|
+
/**
|
|
2549
|
+
* Retrieves the parameter for the calendar week configuration from the DateFormat's format
|
|
2550
|
+
* options
|
|
2551
|
+
*
|
|
2552
|
+
* @param {{firstDayOfWeek: int, minimalDaysInFirstWeek: int, calendarWeekNumbering: sap.ui.core.date.CalendarWeekNumbering}} oFormatOptions
|
|
2553
|
+
* The format options with which the DateFormat instance was created
|
|
2554
|
+
* @returns {sap.ui.core.date.CalendarWeekNumbering|{firstDayOfWeek: int, minimalDaysInFirstWeek: int}|undefined}
|
|
2555
|
+
* The parameter for the calendar week configuration
|
|
2556
|
+
*/
|
|
2557
|
+
function getCalendarWeekParameter(oFormatOptions) {
|
|
2558
|
+
if (oFormatOptions.calendarWeekNumbering) {
|
|
2559
|
+
return oFormatOptions.calendarWeekNumbering;
|
|
2560
|
+
// either both are provided or none (checked in DateFormat.createInstance)
|
|
2561
|
+
} else if (oFormatOptions.firstDayOfWeek !== undefined && oFormatOptions.minimalDaysInFirstWeek !== undefined) {
|
|
2562
|
+
return {
|
|
2563
|
+
firstDayOfWeek: oFormatOptions.firstDayOfWeek,
|
|
2564
|
+
minimalDaysInFirstWeek: oFormatOptions.minimalDaysInFirstWeek
|
|
2565
|
+
};
|
|
2566
|
+
}
|
|
2567
|
+
return undefined;
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
/**
|
|
2571
|
+
* Converts a given date to the given timezone if bUTC is false
|
|
2572
|
+
*
|
|
2573
|
+
* @param {Date} oJSDate The date which should be converted
|
|
2574
|
+
* @param {string} sTimezone target timezone
|
|
2575
|
+
* @param {boolean} bUTC whether it is utc
|
|
2576
|
+
* @returns {Date} the converted date
|
|
2577
|
+
*/
|
|
2578
|
+
var convertToTimezone = function (oJSDate, sTimezone, bUTC) {
|
|
2579
|
+
// Convert to timezone if provided and a valid date is supplied
|
|
2580
|
+
if (!bUTC && isValidDateObject(oJSDate)) {
|
|
2581
|
+
// convert given date to a date in the target timezone
|
|
2582
|
+
return TimezoneUtil.convertToTimezone(oJSDate, sTimezone);
|
|
2583
|
+
}
|
|
2584
|
+
return oJSDate;
|
|
2585
|
+
};
|
|
2586
|
+
|
|
2587
|
+
// recreate javascript date object from the given oDateValues.
|
|
2588
|
+
// In case of oDateValue.valid == false, null value will be returned
|
|
2589
|
+
var fnCreateDate = function (oDateValue, sCalendarType, bUTC, bStrict, sTimezone, oFormatOptions, oLocale) {
|
|
2590
|
+
if (!oDateValue.valid) {
|
|
2591
|
+
return null;
|
|
2592
|
+
}
|
|
2593
|
+
var oDate,
|
|
2594
|
+
iYear = typeof oDateValue.year === "number" ? oDateValue.year : 1970;
|
|
2595
|
+
|
|
2596
|
+
// no need to use UI5Date.getInstance as only the UTC timestamp is used
|
|
2597
|
+
oDate = UniversalDate.getInstance(new Date(0), sCalendarType);
|
|
2598
|
+
oDate.setUTCEra(oDateValue.era || UniversalDate.getCurrentEra(sCalendarType));
|
|
2599
|
+
// Set parsed year, month and day in one call to avoid calculation issues when converting the calendar specific
|
|
2600
|
+
// date into a Gregorian date.
|
|
2601
|
+
oDate.setUTCFullYear(iYear, oDateValue.month || 0, oDateValue.day || 1);
|
|
2602
|
+
oDate.setUTCHours(oDateValue.hour || 0);
|
|
2603
|
+
oDate.setUTCMinutes(oDateValue.minute || 0);
|
|
2604
|
+
oDate.setUTCSeconds(oDateValue.second || 0);
|
|
2605
|
+
oDate.setUTCMilliseconds(oDateValue.millisecond || 0);
|
|
2606
|
+
if (bStrict && (oDateValue.day || 1) !== oDate.getUTCDate()) {
|
|
2607
|
+
// check if valid date given - if invalid, day is not the same (31.Apr -> 1.May)
|
|
2608
|
+
return null;
|
|
2609
|
+
}
|
|
2610
|
+
if (oDateValue.week !== undefined && (oDateValue.month === undefined || oDateValue.day === undefined)) {
|
|
2611
|
+
//check that the week is only set if the day/month has not been set, because day/month have higher precedence than week
|
|
2612
|
+
oDate.setUTCWeek({
|
|
2613
|
+
year: oDateValue.weekYear || oDateValue.year,
|
|
2614
|
+
week: oDateValue.week
|
|
2615
|
+
}, oLocale, getCalendarWeekParameter(oFormatOptions));
|
|
2616
|
+
|
|
2617
|
+
// add the dayNumberOfWeek to the current day
|
|
2618
|
+
if (oDateValue.dayNumberOfWeek !== undefined) {
|
|
2619
|
+
oDate.setUTCDate(oDate.getUTCDate() + oDateValue.dayNumberOfWeek - 1);
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
oDate = oDate.getJSDate();
|
|
2623
|
+
|
|
2624
|
+
// Set the tzDiff based on the timezone difference
|
|
2625
|
+
if (!bUTC && (oDateValue.lastTimezonePatternSymbol === "V" && oDateValue.timezone || oDateValue.tzDiff === undefined)) {
|
|
2626
|
+
// The last parsed timezone pattern will be considered. If this is the "V" pattern for the IANA timezone ID, it needs
|
|
2627
|
+
// to be calculated here. The tzDiff cannot be determined in the parse method because we need the parsed parts to calculate it.
|
|
2628
|
+
if (oDateValue.timezone) {
|
|
2629
|
+
sTimezone = oDateValue.timezone;
|
|
2630
|
+
}
|
|
2631
|
+
if (sTimezone) {
|
|
2632
|
+
oDateValue.tzDiff = TimezoneUtil.calculateOffset(oDate, sTimezone);
|
|
2633
|
+
}
|
|
2634
|
+
}
|
|
2635
|
+
if (oDateValue.tzDiff) {
|
|
2636
|
+
// tzDiff is in seconds for a higher precision (historical timezone might have differences in seconds)
|
|
2637
|
+
// e.g. UI5Date.getInstance("1730-01-01T00:00:00Z")
|
|
2638
|
+
// is in Berlin: Sun Jan 01 1730 00:53:28 GMT+0053 (Central European Standard Time)
|
|
2639
|
+
oDate.setUTCSeconds(oDate.getUTCSeconds() + oDateValue.tzDiff);
|
|
2640
|
+
}
|
|
2641
|
+
return oDate;
|
|
2642
|
+
};
|
|
2643
|
+
|
|
2644
|
+
// Copy the properties of object2 into object1 without
|
|
2645
|
+
// overwriting the existing properties in object1
|
|
2646
|
+
function mergeWithoutOverwrite(object1, object2) {
|
|
2647
|
+
if (object1 === object2) {
|
|
2648
|
+
return object1;
|
|
2649
|
+
}
|
|
2650
|
+
var oMergedObject = {};
|
|
2651
|
+
|
|
2652
|
+
// Clone object1
|
|
2653
|
+
Object.keys(object1).forEach(function (sKey) {
|
|
2654
|
+
oMergedObject[sKey] = object1[sKey];
|
|
2655
|
+
});
|
|
2656
|
+
|
|
2657
|
+
// merge
|
|
2658
|
+
Object.keys(object2).forEach(function (sKey) {
|
|
2659
|
+
if (!oMergedObject.hasOwnProperty(sKey)) {
|
|
2660
|
+
oMergedObject[sKey] = object2[sKey];
|
|
2661
|
+
}
|
|
2662
|
+
});
|
|
2663
|
+
return oMergedObject;
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2666
|
+
// Checks if the given start date is before the end date.
|
|
2667
|
+
function isValidDateRange(oStartDate, oEndDate) {
|
|
2668
|
+
if (oStartDate.getTime() > oEndDate.getTime()) {
|
|
2669
|
+
return false;
|
|
2670
|
+
}
|
|
2671
|
+
return true;
|
|
2672
|
+
}
|
|
2673
|
+
|
|
2674
|
+
// the expectation is that a valid Date has a getTime function which returns a valid number
|
|
2675
|
+
function isValidDateObject(oDate) {
|
|
2676
|
+
return oDate && typeof oDate.getTime === "function" && !isNaN(oDate.getTime());
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
/**
|
|
2680
|
+
* Parse a string which is formatted according to the given format options.
|
|
2681
|
+
*
|
|
2682
|
+
* Uses the timezone from {@link sap.ui.core.Configuration#getTimezone}, which falls back to the
|
|
2683
|
+
* browser's local timezone to convert the given date.
|
|
2684
|
+
*
|
|
2685
|
+
* When using instances from getDateTimeWithTimezoneInstance, please see the corresponding documentation:
|
|
2686
|
+
* {@link sap.ui.core.format.DateFormat.DateTimeWithTimezone#parse}.
|
|
2687
|
+
*
|
|
2688
|
+
* @example <caption>DateTime (assuming timezone "Europe/Berlin")</caption>
|
|
2689
|
+
* var oDate = UI5Date.getInstance("2021-12-24T13:37:00Z");
|
|
2690
|
+
* DateFormat.getDateTimeInstance().parse("Dec 24, 2021, 2:37:00 PM");
|
|
2691
|
+
* // output: oDate
|
|
2692
|
+
*
|
|
2693
|
+
* @param {string} sValue the string containing a formatted date/time value
|
|
2694
|
+
* @param {boolean} [bUTC] whether to use UTC
|
|
2695
|
+
* @param {boolean} [bStrict] whether to use strict value check
|
|
2696
|
+
* @return {Date|Date[]|module:sap/ui/core/date/UI5Date|module:sap/ui/core/date/UI5Date[]} the parsed value(s)
|
|
2697
|
+
* @public
|
|
2698
|
+
*/
|
|
2699
|
+
DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
|
|
2700
|
+
// in order to convert a datetime to a timezone both the date and the time part are required.
|
|
2701
|
+
// If only one is present it cannot be guaranteed that the parsed result is correct, due to
|
|
2702
|
+
// daylight saving time which might shift hours and the timezone difference which might shift
|
|
2703
|
+
// days. For now only the date and time can be parsed using a timezone.
|
|
2704
|
+
var bShowDate = this.oFormatOptions.showDate === undefined || this.oFormatOptions.showDate;
|
|
2705
|
+
var bShowTime = this.oFormatOptions.showTime === undefined || this.oFormatOptions.showTime;
|
|
2706
|
+
if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE && (bShowDate && !bShowTime || !bShowDate && bShowTime)) {
|
|
2707
|
+
throw new TypeError("The input can only be parsed back to date if both date and time are supplied.");
|
|
2708
|
+
}
|
|
2709
|
+
var sTimezone;
|
|
2710
|
+
if (bUTC === undefined && this.type !== mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
|
|
2711
|
+
bUTC = this.oFormatOptions.UTC;
|
|
2712
|
+
}
|
|
2713
|
+
// preserve UTC parameter for fallback instances (must inherit format option UTC from parent)
|
|
2714
|
+
var bUTCInputParameter = bUTC;
|
|
2715
|
+
if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
|
|
2716
|
+
// UTC and timezone are not supported at the same time, therefore set bUTC to false
|
|
2717
|
+
sTimezone = bUTC;
|
|
2718
|
+
bUTC = false;
|
|
2719
|
+
checkTimezoneParameterType(sTimezone);
|
|
2720
|
+
if (sTimezone && !TimezoneUtil.isValidTimezone(sTimezone)) {
|
|
2721
|
+
Log.error("The given timezone isn't valid.");
|
|
2722
|
+
return null;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
sValue = sValue == null ? "" : String(sValue).trim();
|
|
2726
|
+
// normalize input by removing all RTL special characters and replacing all special spaces
|
|
2727
|
+
// by a standard space (\u0020)
|
|
2728
|
+
sValue = DateFormat._normalize(sValue);
|
|
2729
|
+
var oDateValue;
|
|
2730
|
+
var sCalendarType = this.oFormatOptions.calendarType;
|
|
2731
|
+
|
|
2732
|
+
// default the timezone to the local timezone to always enforce the conversion
|
|
2733
|
+
sTimezone = sTimezone || Configuration.getTimezone();
|
|
2734
|
+
if (bStrict === undefined) {
|
|
2735
|
+
bStrict = this.oFormatOptions.strictParsing;
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2738
|
+
// Support Japanese Gannen instead of Ichinen for first year of the era
|
|
2739
|
+
if (sCalendarType === CalendarType.Japanese && this.oLocale.getLanguage() === "ja") {
|
|
2740
|
+
sValue = sValue.replace(/元年/g, "1年");
|
|
2741
|
+
}
|
|
2742
|
+
if (!this.oFormatOptions.interval) {
|
|
2743
|
+
var oJSDate = this.parseRelative(sValue, bUTC);
|
|
2744
|
+
if (oJSDate) {
|
|
2745
|
+
//Stop when relative parsing possible, else go on with standard parsing
|
|
2746
|
+
return oJSDate;
|
|
2747
|
+
}
|
|
2748
|
+
oDateValue = this._parse(sValue, this.aFormatArray, bUTC, bStrict, sTimezone);
|
|
2749
|
+
|
|
2750
|
+
// If input value has not been completely parsed, mark it as invalid
|
|
2751
|
+
if (oDateValue.index === 0 || oDateValue.index < sValue.length) {
|
|
2752
|
+
oDateValue.valid = false;
|
|
2753
|
+
}
|
|
2754
|
+
oJSDate = fnCreateDate(oDateValue, sCalendarType, bUTC, bStrict, sTimezone, this.oFormatOptions, this.oLocale);
|
|
2755
|
+
if (oJSDate) {
|
|
2756
|
+
if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
|
|
2757
|
+
var bShowTimezone = this.oFormatOptions.showTimezone === undefined || this.oFormatOptions.showTimezone;
|
|
2758
|
+
// fill fields according to showDate, showTime and showTimezone options and parsed values
|
|
2759
|
+
if (!bShowTimezone && bShowDate && bShowTime) {
|
|
2760
|
+
return [oJSDate, undefined];
|
|
2761
|
+
} else if (bShowTimezone && !bShowDate && !bShowTime) {
|
|
2762
|
+
return [undefined, oDateValue.timezone];
|
|
2763
|
+
}
|
|
2764
|
+
return [oJSDate, oDateValue.timezone || undefined];
|
|
2765
|
+
}
|
|
2766
|
+
return oJSDate;
|
|
2767
|
+
}
|
|
2768
|
+
} else {
|
|
2769
|
+
var aDateValues = this._parseInterval(sValue, sCalendarType, bUTC, bStrict, sTimezone);
|
|
2770
|
+
var oJSDate1, oJSDate2;
|
|
2771
|
+
if (aDateValues && aDateValues.length === 2) {
|
|
2772
|
+
var oDateValue1 = mergeWithoutOverwrite(aDateValues[0], aDateValues[1]);
|
|
2773
|
+
var oDateValue2 = mergeWithoutOverwrite(aDateValues[1], aDateValues[0]);
|
|
2774
|
+
oJSDate1 = fnCreateDate(oDateValue1, sCalendarType, bUTC, bStrict, sTimezone, this.oFormatOptions, this.oLocale);
|
|
2775
|
+
oJSDate2 = fnCreateDate(oDateValue2, sCalendarType, bUTC, bStrict, sTimezone, this.oFormatOptions, this.oLocale);
|
|
2776
|
+
if (oJSDate1 && oJSDate2) {
|
|
2777
|
+
if (this.oFormatOptions.singleIntervalValue && oJSDate1.getTime() === oJSDate2.getTime()) {
|
|
2778
|
+
return [oJSDate1, null];
|
|
2779
|
+
}
|
|
2780
|
+
var bValid = isValidDateRange(oJSDate1, oJSDate2);
|
|
2781
|
+
if (bStrict && !bValid) {
|
|
2782
|
+
Log.error("StrictParsing: Invalid date range. The given end date is before the start date.");
|
|
2783
|
+
return [null, null];
|
|
2784
|
+
}
|
|
2785
|
+
return [oJSDate1, oJSDate2];
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
if (this.aFallbackFormats) {
|
|
2790
|
+
var vDate;
|
|
2791
|
+
this.aFallbackFormats.every(function (oFallbackFormat) {
|
|
2792
|
+
vDate = oFallbackFormat.parse(sValue, bUTCInputParameter, bStrict);
|
|
2793
|
+
if (Array.isArray(vDate)) {
|
|
2794
|
+
if (oFallbackFormat.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
|
|
2795
|
+
return false;
|
|
2796
|
+
}
|
|
2797
|
+
return !(vDate[0] && vDate[1]);
|
|
2798
|
+
} else {
|
|
2799
|
+
return !vDate;
|
|
2800
|
+
}
|
|
2801
|
+
});
|
|
2802
|
+
return vDate;
|
|
2803
|
+
}
|
|
2804
|
+
if (!this.oFormatOptions.interval) {
|
|
2805
|
+
return null;
|
|
2806
|
+
} else {
|
|
2807
|
+
return [null, null];
|
|
2808
|
+
}
|
|
2809
|
+
};
|
|
2810
|
+
|
|
2811
|
+
/**
|
|
2812
|
+
* Parse the date pattern string and create a format array from it, which can be
|
|
2813
|
+
* used for parsing and formatting the date
|
|
2814
|
+
*
|
|
2815
|
+
* @param {string} sPattern the CLDR date pattern string
|
|
2816
|
+
* @returns {Array} format array
|
|
2817
|
+
*/
|
|
2818
|
+
DateFormat.prototype.parseCldrDatePattern = function (sPattern) {
|
|
2819
|
+
if (mCldrDatePattern[sPattern]) {
|
|
2820
|
+
return mCldrDatePattern[sPattern];
|
|
2821
|
+
}
|
|
2822
|
+
var aFormatArray = [],
|
|
2823
|
+
i,
|
|
2824
|
+
bQuoted = false,
|
|
2825
|
+
oCurrentObject = null,
|
|
2826
|
+
sState = "",
|
|
2827
|
+
sNewState = "",
|
|
2828
|
+
mAppeared = {},
|
|
2829
|
+
bIntervalStartFound = false;
|
|
2830
|
+
for (i = 0; i < sPattern.length; i++) {
|
|
2831
|
+
var sCurChar = sPattern.charAt(i),
|
|
2832
|
+
sNextChar,
|
|
2833
|
+
sPrevChar,
|
|
2834
|
+
sPrevPrevChar;
|
|
2835
|
+
if (bQuoted) {
|
|
2836
|
+
if (sCurChar === "'") {
|
|
2837
|
+
sPrevChar = sPattern.charAt(i - 1);
|
|
2838
|
+
sPrevPrevChar = sPattern.charAt(i - 2);
|
|
2839
|
+
sNextChar = sPattern.charAt(i + 1);
|
|
2840
|
+
// handle abc''def correctly
|
|
2841
|
+
if (sPrevChar === "'" && sPrevPrevChar !== "'") {
|
|
2842
|
+
bQuoted = false;
|
|
2843
|
+
} else if (sNextChar === "'") {
|
|
2844
|
+
// handle 'abc''def' correctly
|
|
2845
|
+
|
|
2846
|
+
i += 1;
|
|
2847
|
+
} else {
|
|
2848
|
+
// normal quote 'abcdef'
|
|
2849
|
+
bQuoted = false;
|
|
2850
|
+
continue;
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
if (sState === "text") {
|
|
2854
|
+
oCurrentObject.value += sCurChar;
|
|
2855
|
+
} else {
|
|
2856
|
+
oCurrentObject = {
|
|
2857
|
+
type: "text",
|
|
2858
|
+
value: sCurChar
|
|
2859
|
+
};
|
|
2860
|
+
aFormatArray.push(oCurrentObject);
|
|
2861
|
+
sState = "text";
|
|
2862
|
+
}
|
|
2863
|
+
} else {
|
|
2864
|
+
if (sCurChar === "'") {
|
|
2865
|
+
bQuoted = true;
|
|
2866
|
+
} else if (this.oSymbols[sCurChar]) {
|
|
2867
|
+
sNewState = this.oSymbols[sCurChar].name;
|
|
2868
|
+
if (sState === sNewState) {
|
|
2869
|
+
oCurrentObject.digits++;
|
|
2870
|
+
} else {
|
|
2871
|
+
oCurrentObject = {
|
|
2872
|
+
type: sNewState,
|
|
2873
|
+
symbol: sCurChar,
|
|
2874
|
+
digits: 1
|
|
2875
|
+
};
|
|
2876
|
+
aFormatArray.push(oCurrentObject);
|
|
2877
|
+
sState = sNewState;
|
|
2878
|
+
if (!bIntervalStartFound) {
|
|
2879
|
+
if (mAppeared[sNewState]) {
|
|
2880
|
+
oCurrentObject.repeat = true;
|
|
2881
|
+
bIntervalStartFound = true;
|
|
2882
|
+
} else {
|
|
2883
|
+
mAppeared[sNewState] = true;
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
} else {
|
|
2888
|
+
if (sState === "text") {
|
|
2889
|
+
oCurrentObject.value += sCurChar;
|
|
2890
|
+
} else {
|
|
2891
|
+
oCurrentObject = {
|
|
2892
|
+
type: "text",
|
|
2893
|
+
value: sCurChar
|
|
2894
|
+
};
|
|
2895
|
+
aFormatArray.push(oCurrentObject);
|
|
2896
|
+
sState = "text";
|
|
2897
|
+
}
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
}
|
|
2901
|
+
mCldrDatePattern[sPattern] = aFormatArray;
|
|
2902
|
+
return aFormatArray;
|
|
2903
|
+
};
|
|
2904
|
+
|
|
2905
|
+
/**
|
|
2906
|
+
* Parse a date string relative to the current date.
|
|
2907
|
+
*
|
|
2908
|
+
* @param {string} sValue the string containing a formatted date/time value
|
|
2909
|
+
* @param {boolean} [bUTC] whether to use UTC, if no timezone is contained
|
|
2910
|
+
* @returns {Date|null} the parsed value or <code>null</code> if relative parsing not possible
|
|
2911
|
+
* @private
|
|
2912
|
+
*/
|
|
2913
|
+
DateFormat.prototype.parseRelative = function (sValue, bUTC) {
|
|
2914
|
+
var aPatterns, oEntry, rPattern, oResult, iValue;
|
|
2915
|
+
if (!sValue) {
|
|
2916
|
+
return null;
|
|
2917
|
+
}
|
|
2918
|
+
aPatterns = this.oLocaleData.getRelativePatterns(this.aRelativeParseScales, this.oFormatOptions.relativeStyle);
|
|
2919
|
+
for (var i = 0; i < aPatterns.length; i++) {
|
|
2920
|
+
oEntry = aPatterns[i];
|
|
2921
|
+
rPattern = new RegExp("^\\s*" + oEntry.pattern.replace(/\{0\}/, "(\\d+)") + "\\s*$", "i");
|
|
2922
|
+
oResult = rPattern.exec(sValue);
|
|
2923
|
+
if (oResult) {
|
|
2924
|
+
if (oEntry.value !== undefined) {
|
|
2925
|
+
return computeRelativeDate(oEntry.value, oEntry.scale);
|
|
2926
|
+
} else {
|
|
2927
|
+
iValue = parseInt(oResult[1]);
|
|
2928
|
+
return computeRelativeDate(iValue * oEntry.sign, oEntry.scale);
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
}
|
|
2932
|
+
function computeRelativeDate(iDiff, sScale) {
|
|
2933
|
+
var oResult = UI5Date.getInstance();
|
|
2934
|
+
if (bUTC) {
|
|
2935
|
+
// date part and time part have to be set individually
|
|
2936
|
+
oResult.setUTCFullYear(oResult.getFullYear(), oResult.getMonth(), oResult.getDate());
|
|
2937
|
+
oResult.setUTCHours(oResult.getHours(), oResult.getMinutes(), oResult.getSeconds(), oResult.getMilliseconds());
|
|
2938
|
+
// eslint-disable-next-line default-case
|
|
2939
|
+
switch (sScale) {
|
|
2940
|
+
case "second":
|
|
2941
|
+
oResult.setUTCSeconds(oResult.getUTCSeconds() + iDiff);
|
|
2942
|
+
break;
|
|
2943
|
+
case "minute":
|
|
2944
|
+
oResult.setUTCMinutes(oResult.getUTCMinutes() + iDiff);
|
|
2945
|
+
break;
|
|
2946
|
+
case "hour":
|
|
2947
|
+
oResult.setUTCHours(oResult.getUTCHours() + iDiff);
|
|
2948
|
+
break;
|
|
2949
|
+
case "day":
|
|
2950
|
+
oResult.setUTCDate(oResult.getUTCDate() + iDiff);
|
|
2951
|
+
break;
|
|
2952
|
+
case "week":
|
|
2953
|
+
oResult.setUTCDate(oResult.getUTCDate() + iDiff * 7);
|
|
2954
|
+
break;
|
|
2955
|
+
case "month":
|
|
2956
|
+
oResult.setUTCMonth(oResult.getUTCMonth() + iDiff);
|
|
2957
|
+
break;
|
|
2958
|
+
case "quarter":
|
|
2959
|
+
oResult.setUTCMonth(oResult.getUTCMonth() + iDiff * 3);
|
|
2960
|
+
break;
|
|
2961
|
+
case "year":
|
|
2962
|
+
oResult.setUTCFullYear(oResult.getUTCFullYear() + iDiff);
|
|
2963
|
+
break;
|
|
2964
|
+
}
|
|
2965
|
+
} else {
|
|
2966
|
+
// eslint-disable-next-line default-case
|
|
2967
|
+
switch (sScale) {
|
|
2968
|
+
case "second":
|
|
2969
|
+
oResult.setSeconds(oResult.getSeconds() + iDiff);
|
|
2970
|
+
break;
|
|
2971
|
+
case "minute":
|
|
2972
|
+
oResult.setMinutes(oResult.getMinutes() + iDiff);
|
|
2973
|
+
break;
|
|
2974
|
+
case "hour":
|
|
2975
|
+
oResult.setHours(oResult.getHours() + iDiff);
|
|
2976
|
+
break;
|
|
2977
|
+
case "day":
|
|
2978
|
+
oResult.setDate(oResult.getDate() + iDiff);
|
|
2979
|
+
break;
|
|
2980
|
+
case "week":
|
|
2981
|
+
oResult.setDate(oResult.getDate() + iDiff * 7);
|
|
2982
|
+
break;
|
|
2983
|
+
case "month":
|
|
2984
|
+
oResult.setMonth(oResult.getMonth() + iDiff);
|
|
2985
|
+
break;
|
|
2986
|
+
case "quarter":
|
|
2987
|
+
oResult.setMonth(oResult.getMonth() + iDiff * 3);
|
|
2988
|
+
break;
|
|
2989
|
+
case "year":
|
|
2990
|
+
oResult.setFullYear(oResult.getFullYear() + iDiff);
|
|
2991
|
+
break;
|
|
2992
|
+
}
|
|
2993
|
+
}
|
|
2994
|
+
return oResult;
|
|
2995
|
+
}
|
|
2996
|
+
};
|
|
2997
|
+
|
|
2998
|
+
/**
|
|
2999
|
+
* Format a date relative to the current date.
|
|
3000
|
+
*
|
|
3001
|
+
* @param {Date} oJSDate the value to format
|
|
3002
|
+
* @param {boolean} bUTC whether to use UTC
|
|
3003
|
+
* @param {number[]} aRange scale ranges
|
|
3004
|
+
* @param {string} sTimezone the IANA timezone ID
|
|
3005
|
+
* @returns {string|null} the formatted output value or <code>null</code> if relative formatting is not possible
|
|
3006
|
+
* @private
|
|
3007
|
+
*/
|
|
3008
|
+
DateFormat.prototype.formatRelative = function (oJSDate, bUTC, aRange, sTimezone) {
|
|
3009
|
+
var oDateUTC,
|
|
3010
|
+
iDiff,
|
|
3011
|
+
iDiffSeconds,
|
|
3012
|
+
sPattern,
|
|
3013
|
+
// no need to use UI5Date.getInstance as only the UTC timestamp is used
|
|
3014
|
+
oToday = convertToTimezone(new Date(), sTimezone),
|
|
3015
|
+
sScale = this.oFormatOptions.relativeScale || "day";
|
|
3016
|
+
iDiffSeconds = (oJSDate.getTime() - oToday.getTime()) / 1000;
|
|
3017
|
+
if (this.oFormatOptions.relativeScale === "auto") {
|
|
3018
|
+
sScale = this._getScale(iDiffSeconds, this.aRelativeScales);
|
|
3019
|
+
sScale = fixScaleForMonths(oJSDate, oToday, sScale, iDiffSeconds);
|
|
3020
|
+
}
|
|
3021
|
+
if (!aRange) {
|
|
3022
|
+
aRange = this._mRanges[sScale];
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
// For dates normalize to UTC to avoid issues with summer-/wintertime
|
|
3026
|
+
if (sScale === "year" || sScale === "month" || sScale === "day") {
|
|
3027
|
+
// no need to use UI5Date.getInstance as only the UTC timestamp is used
|
|
3028
|
+
oToday = new Date(Date.UTC(oToday.getUTCFullYear(), oToday.getUTCMonth(), oToday.getUTCDate()));
|
|
3029
|
+
|
|
3030
|
+
// no need to use UI5Date.getInstance as only the UTC timestamp is used
|
|
3031
|
+
oDateUTC = new Date(0);
|
|
3032
|
+
|
|
3033
|
+
// The Date.UTC function doesn't accept years before 1900 (converts years before 100 into 1900 + years).
|
|
3034
|
+
// Using setUTCFullYear to workaround this issue.
|
|
3035
|
+
oDateUTC.setUTCFullYear(oJSDate.getUTCFullYear(), oJSDate.getUTCMonth(), oJSDate.getUTCDate());
|
|
3036
|
+
oJSDate = oDateUTC;
|
|
3037
|
+
}
|
|
3038
|
+
iDiff = this._getDifference(sScale, [oToday, oJSDate]);
|
|
3039
|
+
if (this.oFormatOptions.relativeScale !== "auto" && (iDiff < aRange[0] || iDiff > aRange[1])) {
|
|
3040
|
+
//Relative parsing only in range +/- x days
|
|
3041
|
+
return null;
|
|
3042
|
+
}
|
|
3043
|
+
sPattern = this.oLocaleData.getRelativePattern(sScale, iDiff, iDiffSeconds > 0, this.oFormatOptions.relativeStyle);
|
|
3044
|
+
return formatMessage(sPattern, [Math.abs(iDiff)]);
|
|
3045
|
+
};
|
|
3046
|
+
DateFormat.prototype._mRanges = {
|
|
3047
|
+
second: [-60, 60],
|
|
3048
|
+
minute: [-60, 60],
|
|
3049
|
+
hour: [-24, 24],
|
|
3050
|
+
day: [-6, 6],
|
|
3051
|
+
week: [-4, 4],
|
|
3052
|
+
month: [-12, 12],
|
|
3053
|
+
year: [-10, 10]
|
|
3054
|
+
};
|
|
3055
|
+
DateFormat.prototype._mScales = {
|
|
3056
|
+
second: 1,
|
|
3057
|
+
// 1
|
|
3058
|
+
minute: 60,
|
|
3059
|
+
// 60
|
|
3060
|
+
hour: 3600,
|
|
3061
|
+
// 60*60
|
|
3062
|
+
day: 86400,
|
|
3063
|
+
// 60*60*24 1 day
|
|
3064
|
+
week: 604800,
|
|
3065
|
+
// 60*60*24*7 7 days
|
|
3066
|
+
month: 2592000,
|
|
3067
|
+
// 60*60*24*30 30 days
|
|
3068
|
+
quarter: 7776000,
|
|
3069
|
+
// 60*60*24*30*3 90 days
|
|
3070
|
+
year: 31536000 // 60*60*24*365 365 days
|
|
3071
|
+
};
|
|
3072
|
+
DateFormat.prototype._getScale = function (iDiffSeconds, aScales) {
|
|
3073
|
+
// Determines the correct time scale
|
|
3074
|
+
var sScale, sTestScale;
|
|
3075
|
+
iDiffSeconds = Math.abs(iDiffSeconds);
|
|
3076
|
+
for (var i = 0; i < aScales.length; i++) {
|
|
3077
|
+
sTestScale = aScales[i];
|
|
3078
|
+
if (iDiffSeconds >= this._mScales[sTestScale]) {
|
|
3079
|
+
sScale = sTestScale;
|
|
3080
|
+
break;
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
if (!sScale) {
|
|
3084
|
+
sScale = aScales[aScales.length - 1];
|
|
3085
|
+
}
|
|
3086
|
+
return sScale;
|
|
3087
|
+
};
|
|
3088
|
+
|
|
3089
|
+
// Fixes the scale for months/weeks
|
|
3090
|
+
// when involved months do not have 30 days
|
|
3091
|
+
function fixScaleForMonths(oJSDate, oToday, sScale, iDiffSeconds) {
|
|
3092
|
+
var iMonthDiff = Math.abs(oJSDate.getUTCMonth() - oToday.getUTCMonth());
|
|
3093
|
+
if (sScale === "week" && iMonthDiff === 2) {
|
|
3094
|
+
// 2 months diff
|
|
3095
|
+
// e.g. March 1st - Jan 31st
|
|
3096
|
+
return "month";
|
|
3097
|
+
} else if (sScale === "week" && iMonthDiff === 1) {
|
|
3098
|
+
// same day but different month
|
|
3099
|
+
// e.g. March 1st - Feb 1st
|
|
3100
|
+
if (oJSDate.getUTCDate() === oToday.getUTCDate()
|
|
3101
|
+
// future date
|
|
3102
|
+
// e.g. Feb 14th - 15. Mar 15th (29/30 days diff) => 1 month
|
|
3103
|
+
|| iDiffSeconds < 0 && oJSDate.getUTCDate() < oToday.getUTCDate()
|
|
3104
|
+
// past date
|
|
3105
|
+
// e.g. Mar 15th - Feb 14th (29/30 days diff) => 1 month
|
|
3106
|
+
|| iDiffSeconds > 0 && oJSDate.getUTCDate() > oToday.getUTCDate()) {
|
|
3107
|
+
return "month";
|
|
3108
|
+
}
|
|
3109
|
+
} else if (sScale === "month" && iMonthDiff === 1) {
|
|
3110
|
+
// future date
|
|
3111
|
+
// e.g. Mar 14th - Apr 13th (30 days diff)
|
|
3112
|
+
if (iDiffSeconds > 0 && oJSDate.getUTCDate() < oToday.getUTCDate()
|
|
3113
|
+
// past date
|
|
3114
|
+
// Feb 14th - Jan 15th (30 days diff)
|
|
3115
|
+
|| iDiffSeconds < 0 && oJSDate.getUTCDate() > oToday.getUTCDate()) {
|
|
3116
|
+
return "week";
|
|
3117
|
+
}
|
|
3118
|
+
}
|
|
3119
|
+
return sScale;
|
|
3120
|
+
}
|
|
3121
|
+
|
|
3122
|
+
/**
|
|
3123
|
+
* Modifies the Date and sets the values with a higher index to <code>0</code>
|
|
3124
|
+
*
|
|
3125
|
+
* @param {Date} oDate input date
|
|
3126
|
+
* @param {number} iStartIndex index of the value to set to <code>0</code>. Higher indices will also be set to <code>0</code>.
|
|
3127
|
+
* 0: FullYear
|
|
3128
|
+
* 1: Month
|
|
3129
|
+
* 2: Date
|
|
3130
|
+
* 3: Hours
|
|
3131
|
+
* 4: Minutes
|
|
3132
|
+
* 5: Seconds
|
|
3133
|
+
* 6: Milliseconds
|
|
3134
|
+
* e.g. iStartIndex <code>4</code> will set Minutes, Seconds and Milliseconds to <code>0</code>
|
|
3135
|
+
* @returns {Date} copy of the date with the modified values
|
|
3136
|
+
*/
|
|
3137
|
+
function cutDateFields(oDate, iStartIndex) {
|
|
3138
|
+
var sMethodName,
|
|
3139
|
+
aFields = ["FullYear", "Month", "Date", "Hours", "Minutes", "Seconds", "Milliseconds"],
|
|
3140
|
+
// no need to use UI5Date.getInstance as only the UTC timestamp is used
|
|
3141
|
+
oDateCopy = new Date(oDate.getTime());
|
|
3142
|
+
for (var i = iStartIndex; i < aFields.length; i++) {
|
|
3143
|
+
sMethodName = "setUTC" + aFields[iStartIndex];
|
|
3144
|
+
oDateCopy[sMethodName].apply(oDateCopy, [0]);
|
|
3145
|
+
}
|
|
3146
|
+
return oDateCopy;
|
|
3147
|
+
}
|
|
3148
|
+
var mRelativeDiffs = {
|
|
3149
|
+
year: function (oFromDate, oToDate) {
|
|
3150
|
+
return oToDate.getUTCFullYear() - oFromDate.getUTCFullYear();
|
|
3151
|
+
},
|
|
3152
|
+
month: function (oFromDate, oToDate) {
|
|
3153
|
+
return oToDate.getUTCMonth() - oFromDate.getUTCMonth() + this.year(oFromDate, oToDate) * 12;
|
|
3154
|
+
},
|
|
3155
|
+
week: function (oFromDate, oToDate, oFormat) {
|
|
3156
|
+
var iFromDay = oFormat._adaptDayOfWeek(oFromDate.getUTCDay());
|
|
3157
|
+
var iToDay = oFormat._adaptDayOfWeek(oToDate.getUTCDay());
|
|
3158
|
+
oFromDate = cutDateFields(oFromDate, 3);
|
|
3159
|
+
oToDate = cutDateFields(oToDate, 3);
|
|
3160
|
+
return (oToDate.getTime() - oFromDate.getTime() - (iToDay - iFromDay) * oFormat._mScales.day * 1000) / (oFormat._mScales.week * 1000);
|
|
3161
|
+
},
|
|
3162
|
+
day: function (oFromDate, oToDate, oFormat) {
|
|
3163
|
+
oFromDate = cutDateFields(oFromDate, 3);
|
|
3164
|
+
oToDate = cutDateFields(oToDate, 3);
|
|
3165
|
+
return (oToDate.getTime() - oFromDate.getTime()) / (oFormat._mScales.day * 1000);
|
|
3166
|
+
},
|
|
3167
|
+
hour: function (oFromDate, oToDate, oFormat) {
|
|
3168
|
+
oFromDate = cutDateFields(oFromDate, 4);
|
|
3169
|
+
oToDate = cutDateFields(oToDate, 4);
|
|
3170
|
+
return (oToDate.getTime() - oFromDate.getTime()) / (oFormat._mScales.hour * 1000);
|
|
3171
|
+
},
|
|
3172
|
+
minute: function (oFromDate, oToDate, oFormat) {
|
|
3173
|
+
oFromDate = cutDateFields(oFromDate, 5);
|
|
3174
|
+
oToDate = cutDateFields(oToDate, 5);
|
|
3175
|
+
return (oToDate.getTime() - oFromDate.getTime()) / (oFormat._mScales.minute * 1000);
|
|
3176
|
+
},
|
|
3177
|
+
second: function (oFromDate, oToDate, oFormat) {
|
|
3178
|
+
oFromDate = cutDateFields(oFromDate, 6);
|
|
3179
|
+
oToDate = cutDateFields(oToDate, 6);
|
|
3180
|
+
return (oToDate.getTime() - oFromDate.getTime()) / (oFormat._mScales.second * 1000);
|
|
3181
|
+
}
|
|
3182
|
+
};
|
|
3183
|
+
DateFormat.prototype._adaptDayOfWeek = function (iDayOfWeek) {
|
|
3184
|
+
// day of week depends on the format locale
|
|
3185
|
+
// the DateFormat's locale is independent
|
|
3186
|
+
var vCalendarWeekParameter = getCalendarWeekParameter(this.oFormatOptions),
|
|
3187
|
+
iFirstDayOfWeek;
|
|
3188
|
+
if (typeof vCalendarWeekParameter === "object") {
|
|
3189
|
+
iFirstDayOfWeek = vCalendarWeekParameter.firstDayOfWeek;
|
|
3190
|
+
} else {
|
|
3191
|
+
iFirstDayOfWeek = CalendarUtils.getWeekConfigurationValues(vCalendarWeekParameter, this.oLocale).firstDayOfWeek;
|
|
3192
|
+
}
|
|
3193
|
+
var iDayNumberOfWeek = iDayOfWeek - (iFirstDayOfWeek - 1);
|
|
3194
|
+
if (iDayNumberOfWeek <= 0) {
|
|
3195
|
+
iDayNumberOfWeek += 7;
|
|
3196
|
+
}
|
|
3197
|
+
return iDayNumberOfWeek;
|
|
3198
|
+
};
|
|
3199
|
+
DateFormat.prototype._getDifference = function (sScale, aDates) {
|
|
3200
|
+
var oFromDate = aDates[0];
|
|
3201
|
+
var oToDate = aDates[1];
|
|
3202
|
+
return Math.round(mRelativeDiffs[sScale](oFromDate, oToDate, this));
|
|
3203
|
+
};
|
|
3204
|
+
DateFormat.prototype.getAllowedCharacters = function (aFormatArray) {
|
|
3205
|
+
if (this.oFormatOptions.relative) {
|
|
3206
|
+
return ""; //Allow all
|
|
3207
|
+
}
|
|
3208
|
+
var sAllowedCharacters = "";
|
|
3209
|
+
var bNumbers = false;
|
|
3210
|
+
var bAll = false;
|
|
3211
|
+
var oPart;
|
|
3212
|
+
for (var i = 0; i < aFormatArray.length; i++) {
|
|
3213
|
+
oPart = aFormatArray[i];
|
|
3214
|
+
switch (oPart.type) {
|
|
3215
|
+
case "text":
|
|
3216
|
+
if (sAllowedCharacters.indexOf(oPart.value) < 0) {
|
|
3217
|
+
sAllowedCharacters += oPart.value;
|
|
3218
|
+
}
|
|
3219
|
+
break;
|
|
3220
|
+
case "day":
|
|
3221
|
+
case "year":
|
|
3222
|
+
case "weekYear":
|
|
3223
|
+
case "dayNumberOfWeek":
|
|
3224
|
+
case "weekInYear":
|
|
3225
|
+
case "hour0_23":
|
|
3226
|
+
case "hour1_24":
|
|
3227
|
+
case "hour0_11":
|
|
3228
|
+
case "hour1_12":
|
|
3229
|
+
case "minute":
|
|
3230
|
+
case "second":
|
|
3231
|
+
case "fractionalsecond":
|
|
3232
|
+
if (!bNumbers) {
|
|
3233
|
+
sAllowedCharacters += "0123456789";
|
|
3234
|
+
bNumbers = true;
|
|
3235
|
+
}
|
|
3236
|
+
break;
|
|
3237
|
+
case "month":
|
|
3238
|
+
case "monthStandalone":
|
|
3239
|
+
if (oPart.digits < 3) {
|
|
3240
|
+
if (!bNumbers) {
|
|
3241
|
+
sAllowedCharacters += "0123456789";
|
|
3242
|
+
bNumbers = true;
|
|
3243
|
+
}
|
|
3244
|
+
} else {
|
|
3245
|
+
bAll = true;
|
|
3246
|
+
}
|
|
3247
|
+
break;
|
|
3248
|
+
default:
|
|
3249
|
+
bAll = true;
|
|
3250
|
+
break;
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
if (bAll) {
|
|
3254
|
+
sAllowedCharacters = "";
|
|
3255
|
+
}
|
|
3256
|
+
return sAllowedCharacters;
|
|
3257
|
+
};
|
|
3258
|
+
|
|
3259
|
+
/**
|
|
3260
|
+
* Returns a language-dependent placeholder text according to this instance's format options, for example
|
|
3261
|
+
* "e.g. 12/31/2023".
|
|
3262
|
+
*
|
|
3263
|
+
* @returns {string} The language-dependent placeholder text
|
|
3264
|
+
*
|
|
3265
|
+
* @private
|
|
3266
|
+
* @ui5-restricted sap.m
|
|
3267
|
+
*/
|
|
3268
|
+
DateFormat.prototype.getPlaceholderText = function () {
|
|
3269
|
+
var oResourceBundle = Core.getLibraryResourceBundle();
|
|
3270
|
+
return oResourceBundle.getText("date.placeholder", [this.format.apply(this, this.getSampleValue())]);
|
|
3271
|
+
};
|
|
3272
|
+
|
|
3273
|
+
/**
|
|
3274
|
+
* Returns a sample date value.
|
|
3275
|
+
*
|
|
3276
|
+
* @returns {array}
|
|
3277
|
+
* A sample date value as an array of parameter values as expected by {@link #format}
|
|
3278
|
+
*
|
|
3279
|
+
* @private
|
|
3280
|
+
*/
|
|
3281
|
+
DateFormat.prototype.getSampleValue = function () {
|
|
3282
|
+
var oDate,
|
|
3283
|
+
iFullYear = UI5Date.getInstance().getFullYear(),
|
|
3284
|
+
bUTC = this.oFormatOptions.UTC;
|
|
3285
|
+
function getDate(iYear, iMonth, iDay, iHours, iMinutes, iSeconds, iMilliseconds) {
|
|
3286
|
+
return bUTC ? UI5Date.getInstance(Date.UTC(iYear, iMonth, iDay, iHours, iMinutes, iSeconds, iMilliseconds)) : UI5Date.getInstance(iYear, iMonth, iDay, iHours, iMinutes, iSeconds, iMilliseconds);
|
|
3287
|
+
}
|
|
3288
|
+
oDate = getDate(iFullYear, 11, 31, 23, 59, 58, 123);
|
|
3289
|
+
if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
|
|
3290
|
+
return [oDate, Configuration.getTimezone()];
|
|
3291
|
+
}
|
|
3292
|
+
if (this.oFormatOptions.interval) {
|
|
3293
|
+
return [[getDate(iFullYear, 11, 22, 9, 12, 34, 567), oDate]];
|
|
3294
|
+
}
|
|
3295
|
+
return [oDate];
|
|
3296
|
+
};
|
|
3297
|
+
const rAllRTLCharacters = /[\u200e\u200f\u202a\u202b\u202c]/g;
|
|
3298
|
+
const rAllSpaces = /\s/g;
|
|
3299
|
+
|
|
3300
|
+
/**
|
|
3301
|
+
* Normalizes the given string by removing RTL characters and replacing special space characters
|
|
3302
|
+
* by the standard ASCII space (\u0020).
|
|
3303
|
+
*
|
|
3304
|
+
* @param {string} sValue The value to be normalized
|
|
3305
|
+
* @return {string} The normalized value
|
|
3306
|
+
*/
|
|
3307
|
+
DateFormat._normalize = function (sValue) {
|
|
3308
|
+
return sValue.replace(rAllRTLCharacters, "").replace(rAllSpaces, " ");
|
|
3309
|
+
};
|
|
3310
|
+
export default DateFormat;
|