@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.
Files changed (236) hide show
  1. package/.eslintignore +6 -0
  2. package/.eslintrc.cjs +3 -0
  3. package/.npsrc.json +3 -0
  4. package/CHANGELOG.md +2261 -0
  5. package/LICENSE.txt +201 -0
  6. package/README.md +51 -0
  7. package/dist/.tsbuildinfo +1 -0
  8. package/dist/Assets-fetch.d.ts +1 -0
  9. package/dist/Assets-fetch.js +3 -0
  10. package/dist/Assets-fetch.js.map +1 -0
  11. package/dist/Assets-node.d.ts +11 -0
  12. package/dist/Assets-node.js +12 -0
  13. package/dist/Assets-node.js.map +1 -0
  14. package/dist/Assets.d.ts +1 -0
  15. package/dist/Assets.js +3 -0
  16. package/dist/Assets.js.map +1 -0
  17. package/dist/CalendarUtils.d.ts +3 -0
  18. package/dist/CalendarUtils.js +6 -0
  19. package/dist/CalendarUtils.js.map +1 -0
  20. package/dist/DateFormat.d.ts +5 -0
  21. package/dist/DateFormat.js +7 -0
  22. package/dist/DateFormat.js.map +1 -0
  23. package/dist/LocaleData.d.ts +5 -0
  24. package/dist/LocaleData.js +7 -0
  25. package/dist/LocaleData.js.map +1 -0
  26. package/dist/NumberFormat.d.ts +5 -0
  27. package/dist/NumberFormat.js +7 -0
  28. package/dist/NumberFormat.js.map +1 -0
  29. package/dist/dates/CalendarDate.d.ts +42 -0
  30. package/dist/dates/CalendarDate.js +193 -0
  31. package/dist/dates/CalendarDate.js.map +1 -0
  32. package/dist/dates/ExtremeDates.d.ts +5 -0
  33. package/dist/dates/ExtremeDates.js +29 -0
  34. package/dist/dates/ExtremeDates.js.map +1 -0
  35. package/dist/dates/UI5Date.d.ts +5 -0
  36. package/dist/dates/UI5Date.js +7 -0
  37. package/dist/dates/UI5Date.js.map +1 -0
  38. package/dist/dates/UniversalDate.d.ts +47 -0
  39. package/dist/dates/UniversalDate.js +5 -0
  40. package/dist/dates/UniversalDate.js.map +1 -0
  41. package/dist/dates/convertMonthNumbersToMonthNames.d.ts +16 -0
  42. package/dist/dates/convertMonthNumbersToMonthNames.js +30 -0
  43. package/dist/dates/convertMonthNumbersToMonthNames.js.map +1 -0
  44. package/dist/dates/getDaysInMonth.d.ts +3 -0
  45. package/dist/dates/getDaysInMonth.js +10 -0
  46. package/dist/dates/getDaysInMonth.js.map +1 -0
  47. package/dist/dates/getRoundedTimestamp.d.ts +7 -0
  48. package/dist/dates/getRoundedTimestamp.js +15 -0
  49. package/dist/dates/getRoundedTimestamp.js.map +1 -0
  50. package/dist/dates/getTodayUTCTimestamp.d.ts +7 -0
  51. package/dist/dates/getTodayUTCTimestamp.js +9 -0
  52. package/dist/dates/getTodayUTCTimestamp.js.map +1 -0
  53. package/dist/dates/modifyDateBy.d.ts +14 -0
  54. package/dist/dates/modifyDateBy.js +55 -0
  55. package/dist/dates/modifyDateBy.js.map +1 -0
  56. package/dist/dates/transformDateToSecondaryType.d.ts +7 -0
  57. package/dist/dates/transformDateToSecondaryType.js +18 -0
  58. package/dist/dates/transformDateToSecondaryType.js.map +1 -0
  59. package/dist/features/calendar/Buddhist.d.ts +1 -0
  60. package/dist/features/calendar/Buddhist.js +2 -0
  61. package/dist/features/calendar/Buddhist.js.map +1 -0
  62. package/dist/features/calendar/Gregorian.d.ts +1 -0
  63. package/dist/features/calendar/Gregorian.js +2 -0
  64. package/dist/features/calendar/Gregorian.js.map +1 -0
  65. package/dist/features/calendar/Islamic.d.ts +1 -0
  66. package/dist/features/calendar/Islamic.js +2 -0
  67. package/dist/features/calendar/Islamic.js.map +1 -0
  68. package/dist/features/calendar/Japanese.d.ts +1 -0
  69. package/dist/features/calendar/Japanese.js +2 -0
  70. package/dist/features/calendar/Japanese.js.map +1 -0
  71. package/dist/features/calendar/Persian.d.ts +1 -0
  72. package/dist/features/calendar/Persian.js +2 -0
  73. package/dist/features/calendar/Persian.js.map +1 -0
  74. package/dist/generated/assets/cldr/Unicode-Data-Files-LICENSE.txt +27 -0
  75. package/dist/generated/assets/cldr/ar.json +7087 -0
  76. package/dist/generated/assets/cldr/ar_EG.json +7087 -0
  77. package/dist/generated/assets/cldr/ar_SA.json +7086 -0
  78. package/dist/generated/assets/cldr/bg.json +5981 -0
  79. package/dist/generated/assets/cldr/ca.json +6083 -0
  80. package/dist/generated/assets/cldr/cnr.json +6169 -0
  81. package/dist/generated/assets/cldr/cs.json +6709 -0
  82. package/dist/generated/assets/cldr/cy.json +6932 -0
  83. package/dist/generated/assets/cldr/da.json +5927 -0
  84. package/dist/generated/assets/cldr/de.json +6048 -0
  85. package/dist/generated/assets/cldr/de_AT.json +6049 -0
  86. package/dist/generated/assets/cldr/de_CH.json +6047 -0
  87. package/dist/generated/assets/cldr/el.json +5832 -0
  88. package/dist/generated/assets/cldr/el_CY.json +5832 -0
  89. package/dist/generated/assets/cldr/en.json +6044 -0
  90. package/dist/generated/assets/cldr/en_AU.json +6084 -0
  91. package/dist/generated/assets/cldr/en_GB.json +6075 -0
  92. package/dist/generated/assets/cldr/en_HK.json +6084 -0
  93. package/dist/generated/assets/cldr/en_IE.json +6075 -0
  94. package/dist/generated/assets/cldr/en_IN.json +6080 -0
  95. package/dist/generated/assets/cldr/en_NZ.json +6075 -0
  96. package/dist/generated/assets/cldr/en_PG.json +6076 -0
  97. package/dist/generated/assets/cldr/en_SG.json +6080 -0
  98. package/dist/generated/assets/cldr/en_ZA.json +6076 -0
  99. package/dist/generated/assets/cldr/es.json +6103 -0
  100. package/dist/generated/assets/cldr/es_AR.json +6106 -0
  101. package/dist/generated/assets/cldr/es_BO.json +6105 -0
  102. package/dist/generated/assets/cldr/es_CL.json +5998 -0
  103. package/dist/generated/assets/cldr/es_CO.json +5998 -0
  104. package/dist/generated/assets/cldr/es_MX.json +6107 -0
  105. package/dist/generated/assets/cldr/es_PE.json +5889 -0
  106. package/dist/generated/assets/cldr/es_UY.json +5891 -0
  107. package/dist/generated/assets/cldr/es_VE.json +5890 -0
  108. package/dist/generated/assets/cldr/et.json +6027 -0
  109. package/dist/generated/assets/cldr/fa.json +5950 -0
  110. package/dist/generated/assets/cldr/fi.json +6195 -0
  111. package/dist/generated/assets/cldr/fr.json +5997 -0
  112. package/dist/generated/assets/cldr/fr_BE.json +5997 -0
  113. package/dist/generated/assets/cldr/fr_CA.json +5991 -0
  114. package/dist/generated/assets/cldr/fr_CH.json +6015 -0
  115. package/dist/generated/assets/cldr/fr_LU.json +5997 -0
  116. package/dist/generated/assets/cldr/he.json +6541 -0
  117. package/dist/generated/assets/cldr/hi.json +5859 -0
  118. package/dist/generated/assets/cldr/hr.json +6196 -0
  119. package/dist/generated/assets/cldr/hu.json +5945 -0
  120. package/dist/generated/assets/cldr/id.json +5730 -0
  121. package/dist/generated/assets/cldr/it.json +5986 -0
  122. package/dist/generated/assets/cldr/it_CH.json +5986 -0
  123. package/dist/generated/assets/cldr/ja.json +5889 -0
  124. package/dist/generated/assets/cldr/kk.json +5939 -0
  125. package/dist/generated/assets/cldr/ko.json +5770 -0
  126. package/dist/generated/assets/cldr/lt.json +6578 -0
  127. package/dist/generated/assets/cldr/lv.json +6114 -0
  128. package/dist/generated/assets/cldr/mk.json +6045 -0
  129. package/dist/generated/assets/cldr/ms.json +5564 -0
  130. package/dist/generated/assets/cldr/nb.json +6035 -0
  131. package/dist/generated/assets/cldr/nl.json +6202 -0
  132. package/dist/generated/assets/cldr/nl_BE.json +6202 -0
  133. package/dist/generated/assets/cldr/pl.json +6589 -0
  134. package/dist/generated/assets/cldr/pt.json +6115 -0
  135. package/dist/generated/assets/cldr/pt_PT.json +6180 -0
  136. package/dist/generated/assets/cldr/ro.json +6200 -0
  137. package/dist/generated/assets/cldr/ru.json +6503 -0
  138. package/dist/generated/assets/cldr/ru_UA.json +6503 -0
  139. package/dist/generated/assets/cldr/sk.json +6432 -0
  140. package/dist/generated/assets/cldr/sl.json +6444 -0
  141. package/dist/generated/assets/cldr/sr.json +6241 -0
  142. package/dist/generated/assets/cldr/sr_Latn.json +6226 -0
  143. package/dist/generated/assets/cldr/sv.json +6076 -0
  144. package/dist/generated/assets/cldr/th.json +5875 -0
  145. package/dist/generated/assets/cldr/tr.json +6094 -0
  146. package/dist/generated/assets/cldr/uk.json +6454 -0
  147. package/dist/generated/assets/cldr/vi.json +5669 -0
  148. package/dist/generated/assets/cldr/zh_CN.json +5717 -0
  149. package/dist/generated/assets/cldr/zh_HK.json +5726 -0
  150. package/dist/generated/assets/cldr/zh_SG.json +5726 -0
  151. package/dist/generated/assets/cldr/zh_TW.json +5793 -0
  152. package/dist/generated/json-imports/LocaleData-fetch.d.ts +1 -0
  153. package/dist/generated/json-imports/LocaleData-fetch.js +93 -0
  154. package/dist/generated/json-imports/LocaleData-fetch.js.map +1 -0
  155. package/dist/generated/json-imports/LocaleData-node.d.ts +1 -0
  156. package/dist/generated/json-imports/LocaleData-node.js +93 -0
  157. package/dist/generated/json-imports/LocaleData-node.js.map +1 -0
  158. package/dist/generated/json-imports/LocaleData.d.ts +1 -0
  159. package/dist/generated/json-imports/LocaleData.js +93 -0
  160. package/dist/generated/json-imports/LocaleData.js.map +1 -0
  161. package/dist/getCachedLocaleDataInstance.d.ts +4 -0
  162. package/dist/getCachedLocaleDataInstance.js +10 -0
  163. package/dist/getCachedLocaleDataInstance.js.map +1 -0
  164. package/dist/locale/getLocaleData.d.ts +11 -0
  165. package/dist/locale/getLocaleData.js +23 -0
  166. package/dist/locale/getLocaleData.js.map +1 -0
  167. package/dist/sap/base/Event.js +59 -0
  168. package/dist/sap/base/Eventing.js +146 -0
  169. package/dist/sap/base/Log.js +3 -0
  170. package/dist/sap/base/assert.js +34 -0
  171. package/dist/sap/base/config/MemoryConfigurationProvider.js +20 -0
  172. package/dist/sap/base/config.js +17 -0
  173. package/dist/sap/base/i18n/Formatting.d.ts +8 -0
  174. package/dist/sap/base/i18n/Formatting.js +11 -0
  175. package/dist/sap/base/i18n/Formatting.js.map +1 -0
  176. package/dist/sap/base/i18n/LanguageTag.js +173 -0
  177. package/dist/sap/base/i18n/Localization.d.ts +4 -0
  178. package/dist/sap/base/i18n/Localization.js +12 -0
  179. package/dist/sap/base/i18n/Localization.js.map +1 -0
  180. package/dist/sap/base/i18n/date/CalendarType.js +43 -0
  181. package/dist/sap/base/i18n/date/CalendarWeekNumbering.js +105 -0
  182. package/dist/sap/base/i18n/date/TimezoneUtils.js +319 -0
  183. package/dist/sap/base/strings/camelize.js +30 -0
  184. package/dist/sap/base/strings/formatMessage.js +93 -0
  185. package/dist/sap/base/util/LoaderExtensions.d.ts +4 -0
  186. package/dist/sap/base/util/LoaderExtensions.js +14 -0
  187. package/dist/sap/base/util/LoaderExtensions.js.map +1 -0
  188. package/dist/sap/base/util/ObjectPath.d.ts +4 -0
  189. package/dist/sap/base/util/ObjectPath.js +6 -0
  190. package/dist/sap/base/util/ObjectPath.js.map +1 -0
  191. package/dist/sap/base/util/Version.js +157 -0
  192. package/dist/sap/base/util/_merge.js +89 -0
  193. package/dist/sap/base/util/array/uniqueSort.js +41 -0
  194. package/dist/sap/base/util/deepClone.js +102 -0
  195. package/dist/sap/base/util/deepEqual.js +83 -0
  196. package/dist/sap/base/util/extend.js +61 -0
  197. package/dist/sap/base/util/isEmptyObject.js +34 -0
  198. package/dist/sap/base/util/isPlainObject.js +52 -0
  199. package/dist/sap/base/util/now.js +28 -0
  200. package/dist/sap/base/util/resolveReference.js +3 -0
  201. package/dist/sap/base/util/uid.js +27 -0
  202. package/dist/sap/ui/base/DataType.js +657 -0
  203. package/dist/sap/ui/base/Interface.js +72 -0
  204. package/dist/sap/ui/base/Metadata.js +483 -0
  205. package/dist/sap/ui/base/Object.js +300 -0
  206. package/dist/sap/ui/core/CalendarType.js +24 -0
  207. package/dist/sap/ui/core/Configuration.d.ts +17 -0
  208. package/dist/sap/ui/core/Configuration.js +23 -0
  209. package/dist/sap/ui/core/Configuration.js.map +1 -0
  210. package/dist/sap/ui/core/Core.d.ts +25 -0
  211. package/dist/sap/ui/core/Core.js +13 -0
  212. package/dist/sap/ui/core/Core.js.map +1 -0
  213. package/dist/sap/ui/core/FormatSettings.d.ts +9 -0
  214. package/dist/sap/ui/core/FormatSettings.js +12 -0
  215. package/dist/sap/ui/core/FormatSettings.js.map +1 -0
  216. package/dist/sap/ui/core/Locale.js +194 -0
  217. package/dist/sap/ui/core/LocaleData.js +2717 -0
  218. package/dist/sap/ui/core/Supportability.js +5 -0
  219. package/dist/sap/ui/core/Theming.js +539 -0
  220. package/dist/sap/ui/core/date/Buddhist.js +196 -0
  221. package/dist/sap/ui/core/date/CalendarUtils.js +65 -0
  222. package/dist/sap/ui/core/date/CalendarWeekNumbering.js +30 -0
  223. package/dist/sap/ui/core/date/Gregorian.js +32 -0
  224. package/dist/sap/ui/core/date/Islamic.js +367 -0
  225. package/dist/sap/ui/core/date/Japanese.js +257 -0
  226. package/dist/sap/ui/core/date/Persian.js +394 -0
  227. package/dist/sap/ui/core/date/UI5Date.js +991 -0
  228. package/dist/sap/ui/core/date/UniversalDate.js +1324 -0
  229. package/dist/sap/ui/core/date/_Calendars.js +22 -0
  230. package/dist/sap/ui/core/format/DateFormat.js +3310 -0
  231. package/dist/sap/ui/core/format/NumberFormat.js +2835 -0
  232. package/dist/sap/ui/core/format/TimezoneUtil.js +24 -0
  233. package/package-scripts.cjs +35 -0
  234. package/package.json +46 -0
  235. package/tsconfig.json +24 -0
  236. 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;