@ui5/webcomponents-localization 0.0.0-bef62af04 → 0.0.0-c0e494b02

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 (193) hide show
  1. package/.eslintignore +1 -1
  2. package/.npsrc.json +3 -0
  3. package/CHANGELOG.md +420 -0
  4. package/README.md +36 -6
  5. package/{src/Assets-static.js → dist/Assets-static.d.ts} +0 -1
  6. package/dist/Assets-static.js +1 -0
  7. package/dist/Assets-static.js.map +1 -0
  8. package/dist/Assets.d.ts +1 -0
  9. package/dist/Assets.js +1 -0
  10. package/dist/Assets.js.map +1 -0
  11. package/dist/DateFormat.d.ts +6 -0
  12. package/dist/DateFormat.js +6 -2
  13. package/dist/DateFormat.js.map +1 -0
  14. package/dist/LocaleData.d.ts +6 -0
  15. package/dist/LocaleData.js +6 -2
  16. package/dist/LocaleData.js.map +1 -0
  17. package/dist/dates/CalendarDate.d.ts +43 -0
  18. package/dist/dates/CalendarDate.js +171 -201
  19. package/dist/dates/CalendarDate.js.map +1 -0
  20. package/dist/dates/ExtremeDates.d.ts +5 -0
  21. package/dist/dates/ExtremeDates.js +25 -35
  22. package/dist/dates/ExtremeDates.js.map +1 -0
  23. package/dist/dates/UI5Date.d.ts +6 -0
  24. package/dist/dates/UI5Date.js +7 -0
  25. package/dist/dates/UI5Date.js.map +1 -0
  26. package/dist/dates/UniversalDate.d.ts +47 -0
  27. package/dist/dates/UniversalDate.js +5 -0
  28. package/dist/dates/UniversalDate.js.map +1 -0
  29. package/dist/dates/calculateWeekNumber.d.ts +5 -0
  30. package/dist/dates/calculateWeekNumber.js +42 -48
  31. package/dist/dates/calculateWeekNumber.js.map +1 -0
  32. package/dist/dates/convertMonthNumbersToMonthNames.d.ts +16 -0
  33. package/dist/dates/convertMonthNumbersToMonthNames.js +30 -0
  34. package/dist/dates/convertMonthNumbersToMonthNames.js.map +1 -0
  35. package/dist/dates/getDaysInMonth.d.ts +3 -0
  36. package/dist/dates/getDaysInMonth.js +10 -0
  37. package/dist/dates/getDaysInMonth.js.map +1 -0
  38. package/dist/dates/getRoundedTimestamp.d.ts +7 -0
  39. package/dist/dates/getRoundedTimestamp.js +10 -9
  40. package/dist/dates/getRoundedTimestamp.js.map +1 -0
  41. package/dist/dates/getTodayUTCTimestamp.d.ts +7 -0
  42. package/dist/dates/getTodayUTCTimestamp.js +3 -3
  43. package/dist/dates/getTodayUTCTimestamp.js.map +1 -0
  44. package/dist/dates/modifyDateBy.d.ts +13 -0
  45. package/dist/dates/modifyDateBy.js +27 -29
  46. package/dist/dates/modifyDateBy.js.map +1 -0
  47. package/dist/dates/transformDateToSecondaryType.d.ts +7 -0
  48. package/dist/dates/transformDateToSecondaryType.js +18 -0
  49. package/dist/dates/transformDateToSecondaryType.js.map +1 -0
  50. package/dist/features/calendar/Buddhist.js +1 -0
  51. package/dist/features/calendar/Buddhist.js.map +1 -0
  52. package/dist/features/calendar/Gregorian.js +1 -0
  53. package/dist/features/calendar/Gregorian.js.map +1 -0
  54. package/dist/features/calendar/Islamic.js +1 -0
  55. package/dist/features/calendar/Islamic.js.map +1 -0
  56. package/dist/features/calendar/Japanese.js +1 -0
  57. package/dist/features/calendar/Japanese.js.map +1 -0
  58. package/dist/features/calendar/Persian.js +1 -0
  59. package/dist/features/calendar/Persian.js.map +1 -0
  60. package/dist/generated/assets/cldr/ar.json +5531 -5906
  61. package/dist/generated/assets/cldr/ar_EG.json +5531 -5906
  62. package/dist/generated/assets/cldr/ar_SA.json +5530 -5906
  63. package/dist/generated/assets/cldr/bg.json +4452 -4979
  64. package/dist/generated/assets/cldr/ca.json +4440 -4996
  65. package/dist/generated/assets/cldr/cs.json +4960 -5498
  66. package/dist/generated/assets/cldr/cy.json +5211 -5884
  67. package/dist/generated/assets/cldr/da.json +4308 -4888
  68. package/dist/generated/assets/cldr/de.json +4313 -4916
  69. package/dist/generated/assets/cldr/de_AT.json +4314 -4917
  70. package/dist/generated/assets/cldr/de_CH.json +4312 -4915
  71. package/dist/generated/assets/cldr/el.json +4281 -4883
  72. package/dist/generated/assets/cldr/el_CY.json +4281 -4883
  73. package/dist/generated/assets/cldr/en.json +4316 -4970
  74. package/dist/generated/assets/cldr/en_AU.json +4319 -4962
  75. package/dist/generated/assets/cldr/en_GB.json +4329 -4971
  76. package/dist/generated/assets/cldr/en_HK.json +4337 -4977
  77. package/dist/generated/assets/cldr/en_IE.json +4328 -4971
  78. package/dist/generated/assets/cldr/en_IN.json +4333 -4972
  79. package/dist/generated/assets/cldr/en_NZ.json +4328 -4971
  80. package/dist/generated/assets/cldr/en_PG.json +4329 -4972
  81. package/dist/generated/assets/cldr/en_SG.json +4333 -4973
  82. package/dist/generated/assets/cldr/en_ZA.json +4329 -4972
  83. package/dist/generated/assets/cldr/es.json +4331 -4912
  84. package/dist/generated/assets/cldr/es_AR.json +4334 -4914
  85. package/dist/generated/assets/cldr/es_BO.json +4333 -4913
  86. package/dist/generated/assets/cldr/es_CL.json +4334 -4914
  87. package/dist/generated/assets/cldr/es_CO.json +4333 -4913
  88. package/dist/generated/assets/cldr/es_MX.json +4335 -4915
  89. package/dist/generated/assets/cldr/es_PE.json +4333 -4913
  90. package/dist/generated/assets/cldr/es_UY.json +4335 -4915
  91. package/dist/generated/assets/cldr/es_VE.json +4334 -4914
  92. package/dist/generated/assets/cldr/et.json +4340 -4967
  93. package/dist/generated/assets/cldr/fa.json +4367 -4883
  94. package/dist/generated/assets/cldr/fi.json +4463 -5008
  95. package/dist/generated/assets/cldr/fr.json +4357 -4979
  96. package/dist/generated/assets/cldr/fr_BE.json +4357 -4979
  97. package/dist/generated/assets/cldr/fr_CA.json +4351 -4973
  98. package/dist/generated/assets/cldr/fr_CH.json +4375 -4997
  99. package/dist/generated/assets/cldr/fr_LU.json +4357 -4979
  100. package/dist/generated/assets/cldr/he.json +4869 -5378
  101. package/dist/generated/assets/cldr/hi.json +4295 -4829
  102. package/dist/generated/assets/cldr/hr.json +4583 -4919
  103. package/dist/generated/assets/cldr/hu.json +4364 -4856
  104. package/dist/generated/assets/cldr/id.json +4060 -4658
  105. package/dist/generated/assets/cldr/it.json +4299 -4950
  106. package/dist/generated/assets/cldr/it_CH.json +4299 -4950
  107. package/dist/generated/assets/cldr/ja.json +4211 -4830
  108. package/dist/generated/assets/cldr/kk.json +4339 -4725
  109. package/dist/generated/assets/cldr/ko.json +4189 -4738
  110. package/dist/generated/assets/cldr/lt.json +4850 -5481
  111. package/dist/generated/assets/cldr/lv.json +4587 -5112
  112. package/dist/generated/assets/cldr/ms.json +4021 -4515
  113. package/dist/generated/assets/cldr/nb.json +4335 -4977
  114. package/dist/generated/assets/cldr/nl.json +4294 -4884
  115. package/dist/generated/assets/cldr/nl_BE.json +4294 -4884
  116. package/dist/generated/assets/cldr/pl.json +4667 -5176
  117. package/dist/generated/assets/cldr/pt.json +4235 -4805
  118. package/dist/generated/assets/cldr/pt_PT.json +4372 -4940
  119. package/dist/generated/assets/cldr/ro.json +4563 -5090
  120. package/dist/generated/assets/cldr/ru.json +4909 -5407
  121. package/dist/generated/assets/cldr/ru_UA.json +4909 -5407
  122. package/dist/generated/assets/cldr/sk.json +4939 -5370
  123. package/dist/generated/assets/cldr/sl.json +4910 -5340
  124. package/dist/generated/assets/cldr/sr.json +4585 -5126
  125. package/dist/generated/assets/cldr/sr_Latn.json +4574 -5127
  126. package/dist/generated/assets/cldr/sv.json +4362 -5011
  127. package/dist/generated/assets/cldr/th.json +4214 -4797
  128. package/dist/generated/assets/cldr/tr.json +4400 -4979
  129. package/dist/generated/assets/cldr/uk.json +4858 -5353
  130. package/dist/generated/assets/cldr/vi.json +4070 -4673
  131. package/dist/generated/assets/cldr/zh_CN.json +4100 -4632
  132. package/dist/generated/assets/cldr/zh_HK.json +4108 -4640
  133. package/dist/generated/assets/cldr/zh_SG.json +4108 -4640
  134. package/dist/generated/assets/cldr/zh_TW.json +4131 -4728
  135. package/dist/generated/json-imports/LocaleData-static.js +2 -1
  136. package/dist/generated/json-imports/LocaleData.js +2 -1
  137. package/dist/getCachedLocaleDataInstance.d.ts +4 -0
  138. package/dist/getCachedLocaleDataInstance.js +6 -9
  139. package/dist/getCachedLocaleDataInstance.js.map +1 -0
  140. package/dist/locale/getLocaleData.d.ts +11 -0
  141. package/dist/locale/getLocaleData.js +13 -17
  142. package/dist/locale/getLocaleData.js.map +1 -0
  143. package/dist/sap/base/Log.js +28 -37
  144. package/dist/sap/base/assert.js +5 -10
  145. package/dist/sap/base/util/LoaderExtensions.d.ts +4 -0
  146. package/dist/sap/base/util/LoaderExtensions.js +9 -12
  147. package/dist/sap/base/util/LoaderExtensions.js.map +1 -0
  148. package/dist/sap/base/util/deepEqual.js +1 -5
  149. package/dist/sap/ui/base/Object.js +26 -2
  150. package/dist/sap/ui/core/Configuration.d.ts +17 -0
  151. package/dist/sap/ui/core/Configuration.js +21 -0
  152. package/dist/sap/ui/core/Configuration.js.map +1 -0
  153. package/dist/sap/ui/core/Core.d.ts +26 -0
  154. package/dist/sap/ui/core/Core.js +7 -32
  155. package/dist/sap/ui/core/Core.js.map +1 -0
  156. package/dist/sap/ui/core/FormatSettings.d.ts +10 -0
  157. package/dist/sap/ui/core/FormatSettings.js +14 -0
  158. package/dist/sap/ui/core/FormatSettings.js.map +1 -0
  159. package/dist/sap/ui/core/Locale.js +15 -0
  160. package/dist/sap/ui/core/LocaleData.js +182 -1522
  161. package/dist/sap/ui/core/date/Buddhist.js +0 -6
  162. package/dist/sap/ui/core/date/CalendarUtils.js +36 -0
  163. package/dist/sap/ui/core/date/CalendarWeekNumbering.js +7 -0
  164. package/dist/sap/ui/core/date/Islamic.js +3 -3
  165. package/dist/sap/ui/core/date/Japanese.js +4 -4
  166. package/dist/sap/ui/core/date/UI5Date.js +305 -0
  167. package/dist/sap/ui/core/date/UniversalDate.js +84 -26
  168. package/dist/sap/ui/core/format/DateFormat.js +787 -474
  169. package/dist/sap/ui/core/format/TimezoneUtil.js +89 -0
  170. package/{package-scripts.js → package-scripts.cjs} +10 -13
  171. package/package.json +8 -14
  172. package/tsconfig.json +14 -0
  173. package/used-modules.txt +5 -1
  174. package/hash.txt +0 -1
  175. package/src/Assets.js +0 -2
  176. package/src/DateFormat.js +0 -3
  177. package/src/LocaleData.js +0 -3
  178. package/src/dates/CalendarDate.js +0 -223
  179. package/src/dates/ExtremeDates.js +0 -39
  180. package/src/dates/calculateWeekNumber.js +0 -51
  181. package/src/dates/getRoundedTimestamp.js +0 -14
  182. package/src/dates/getTodayUTCTimestamp.js +0 -9
  183. package/src/dates/modifyDateBy.js +0 -42
  184. package/src/getCachedLocaleDataInstance.js +0 -13
  185. package/src/locale/getLocaleData.js +0 -27
  186. package/src/sap/base/util/LoaderExtensions.js +0 -17
  187. package/src/sap/ui/core/Core.js +0 -38
  188. /package/{config/.eslintrc.js → .eslintrc.cjs} +0 -0
  189. /package/{src/features/calendar/Buddhist.js → dist/features/calendar/Buddhist.d.ts} +0 -0
  190. /package/{src/features/calendar/Gregorian.js → dist/features/calendar/Gregorian.d.ts} +0 -0
  191. /package/{src/features/calendar/Islamic.js → dist/features/calendar/Islamic.d.ts} +0 -0
  192. /package/{src/features/calendar/Japanese.js → dist/features/calendar/Japanese.d.ts} +0 -0
  193. /package/{src/features/calendar/Persian.js → dist/features/calendar/Persian.d.ts} +0 -0
@@ -1,17 +1,33 @@
1
- import Core from '../Core.js';
2
1
  import CalendarType from '../CalendarType.js';
3
2
  import Locale from '../Locale.js';
4
3
  import LocaleData from '../LocaleData.js';
4
+ import UI5Date from '../date/UI5Date.js';
5
5
  import UniversalDate from '../date/UniversalDate.js';
6
+ import CalendarUtils from '../date/CalendarUtils.js';
7
+ import CalendarWeekNumbering from '../date/CalendarWeekNumbering.js';
8
+ import TimezoneUtil from './TimezoneUtil.js';
6
9
  import deepEqual from '../../../base/util/deepEqual.js';
7
10
  import formatMessage from '../../../base/strings/formatMessage.js';
8
11
  import Log from '../../../base/Log.js';
9
12
  import extend from '../../../base/util/extend.js';
13
+ import Configuration from '../Configuration.js';
10
14
  var DateFormat = function () {
11
15
  throw new Error();
12
16
  };
17
+ var mDateFormatTypes = {
18
+ DATE: 'date',
19
+ TIME: 'time',
20
+ DATETIME: 'datetime',
21
+ DATETIME_WITH_TIMEZONE: 'datetimeWithTimezone'
22
+ };
13
23
  var mCldrDatePattern = {};
24
+ var checkTimezoneParameterType = function (sTimezone) {
25
+ if (typeof sTimezone !== 'string' && !(sTimezone instanceof String) && sTimezone != null) {
26
+ throw new TypeError('The given timezone must be a string.');
27
+ }
28
+ };
14
29
  DateFormat.oDateInfo = {
30
+ type: mDateFormatTypes.DATE,
15
31
  oDefaultFormatOptions: {
16
32
  style: 'medium',
17
33
  relativeScale: 'day',
@@ -64,6 +80,7 @@ DateFormat.oDateInfo = {
64
80
  ]
65
81
  };
66
82
  DateFormat.oDateTimeInfo = {
83
+ type: mDateFormatTypes.DATETIME,
67
84
  oDefaultFormatOptions: {
68
85
  style: 'medium',
69
86
  relativeScale: 'auto',
@@ -126,7 +143,41 @@ DateFormat.oDateTimeInfo = {
126
143
  'Seconds'
127
144
  ]
128
145
  };
146
+ DateFormat._getDateTimeWithTimezoneInfo = function (oFormatOptions) {
147
+ var bShowDate = oFormatOptions.showDate === undefined || oFormatOptions.showDate;
148
+ var bShowTime = oFormatOptions.showTime === undefined || oFormatOptions.showTime;
149
+ var bShowTimezone = oFormatOptions.showTimezone === undefined || oFormatOptions.showTimezone;
150
+ var oBaselineType = DateFormat.oDateTimeInfo;
151
+ if (bShowDate && !bShowTime) {
152
+ oBaselineType = DateFormat.oDateInfo;
153
+ } else if (!bShowDate && bShowTime) {
154
+ oBaselineType = DateFormat.oTimeInfo;
155
+ }
156
+ return Object.assign({}, oBaselineType, {
157
+ type: mDateFormatTypes.DATETIME_WITH_TIMEZONE,
158
+ getTimezonePattern: function (sPattern) {
159
+ if (!bShowDate && !bShowTime && bShowTimezone) {
160
+ return 'VV';
161
+ } else if (!bShowTimezone) {
162
+ return sPattern;
163
+ } else {
164
+ return sPattern + ' VV';
165
+ }
166
+ },
167
+ getPattern: function (oLocaleData, sStyle, sCalendarType) {
168
+ if (!bShowDate && !bShowTime && bShowTimezone) {
169
+ return 'VV';
170
+ }
171
+ if (!bShowTimezone) {
172
+ return oBaselineType.getPattern(oLocaleData, sStyle, sCalendarType);
173
+ }
174
+ var sPattern = oBaselineType.getPattern(oLocaleData, sStyle, sCalendarType);
175
+ return oLocaleData.applyTimezonePattern(sPattern);
176
+ }
177
+ });
178
+ };
129
179
  DateFormat.oTimeInfo = {
180
+ type: mDateFormatTypes.TIME,
130
181
  oDefaultFormatOptions: {
131
182
  style: 'medium',
132
183
  relativeScale: 'auto',
@@ -179,6 +230,27 @@ DateFormat.getDateInstance = function (oFormatOptions, oLocale) {
179
230
  DateFormat.getDateTimeInstance = function (oFormatOptions, oLocale) {
180
231
  return this.createInstance(oFormatOptions, oLocale, this.oDateTimeInfo);
181
232
  };
233
+ DateFormat.getDateTimeWithTimezoneInstance = function (oFormatOptions, oLocale) {
234
+ if (oFormatOptions && !(oFormatOptions instanceof Locale)) {
235
+ oFormatOptions = Object.assign({}, oFormatOptions);
236
+ if (typeof oFormatOptions.showTimezone === 'string') {
237
+ var sShowTimezone = oFormatOptions.showTimezone;
238
+ if (oFormatOptions.showDate === undefined && oFormatOptions.showTime === undefined) {
239
+ if (sShowTimezone === 'Hide') {
240
+ oFormatOptions.showTimezone = false;
241
+ } else if (sShowTimezone === 'Only') {
242
+ oFormatOptions.showDate = false;
243
+ oFormatOptions.showTime = false;
244
+ }
245
+ }
246
+ oFormatOptions.showTimezone = sShowTimezone !== 'Hide';
247
+ }
248
+ if (oFormatOptions.showDate === false && oFormatOptions.showTime === false && oFormatOptions.showTimezone === false) {
249
+ throw new TypeError('Invalid Configuration. One of the following format options must be true: showDate, showTime or showTimezone.');
250
+ }
251
+ }
252
+ return this.createInstance(oFormatOptions, oLocale, DateFormat._getDateTimeWithTimezoneInfo(oFormatOptions || {}));
253
+ };
182
254
  DateFormat.getTimeInstance = function (oFormatOptions, oLocale) {
183
255
  return this.createInstance(oFormatOptions, oLocale, this.oTimeInfo);
184
256
  };
@@ -187,20 +259,37 @@ function createIntervalPatternWithNormalConnector(oFormat) {
187
259
  sPattern = sPattern.replace(/[^\{\}01 ]/, '-');
188
260
  return sPattern.replace(/\{(0|1)\}/g, oFormat.oFormatOptions.pattern);
189
261
  }
190
- DateFormat.createInstance = function (oFormatOptions, oLocale, oInfo) {
191
- var oFormat = Object.create(this.prototype);
262
+ DateFormat.createInstance = function (oFormatOptions, oLocale, oInfo, bIsFallback) {
263
+ var aFallbackFormatOptions, oFormat, sPattern;
264
+ oFormat = Object.create(this.prototype);
192
265
  if (oFormatOptions instanceof Locale) {
193
266
  oLocale = oFormatOptions;
194
267
  oFormatOptions = undefined;
195
268
  }
196
269
  if (!oLocale) {
197
- oLocale = Core.getConfiguration().getFormatSettings().getFormatLocale();
270
+ oLocale = Configuration.getFormatSettings().getFormatLocale();
198
271
  }
199
272
  oFormat.oLocale = oLocale;
200
273
  oFormat.oLocaleData = LocaleData.getInstance(oLocale);
201
274
  oFormat.oFormatOptions = extend({}, oInfo.oDefaultFormatOptions, oFormatOptions);
275
+ if (oInfo.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
276
+ oFormat.oFormatOptions.interval = false;
277
+ oFormat.oFormatOptions.singleIntervalValue = false;
278
+ oFormat.oFormatOptions.UTC = false;
279
+ } else {
280
+ oFormat.oFormatOptions.showTimezone = undefined;
281
+ oFormat.oFormatOptions.showDate = undefined;
282
+ oFormat.oFormatOptions.showTime = undefined;
283
+ }
284
+ oFormat.type = oInfo.type;
202
285
  if (!oFormat.oFormatOptions.calendarType) {
203
- oFormat.oFormatOptions.calendarType = Core.getConfiguration().getCalendarType();
286
+ oFormat.oFormatOptions.calendarType = Configuration.getCalendarType();
287
+ }
288
+ if (oFormat.oFormatOptions.firstDayOfWeek === undefined && oFormat.oFormatOptions.minimalDaysInFirstWeek !== undefined || oFormat.oFormatOptions.firstDayOfWeek !== undefined && oFormat.oFormatOptions.minimalDaysInFirstWeek === undefined) {
289
+ throw new TypeError('Format options firstDayOfWeek and minimalDaysInFirstWeek need both to be set, but only one was provided.');
290
+ }
291
+ if (oFormat.oFormatOptions.calendarWeekNumbering && !Object.values(CalendarWeekNumbering).includes(oFormat.oFormatOptions.calendarWeekNumbering)) {
292
+ throw new TypeError('Illegal format option calendarWeekNumbering: \'' + oFormat.oFormatOptions.calendarWeekNumbering + '\'');
204
293
  }
205
294
  if (!oFormat.oFormatOptions.pattern) {
206
295
  if (oFormat.oFormatOptions.format) {
@@ -225,30 +314,27 @@ DateFormat.createInstance = function (oFormatOptions, oLocale, oInfo) {
225
314
  var sCommonConnectorPattern = createIntervalPatternWithNormalConnector(oFormat);
226
315
  oFormat.intervalPatterns.push(sCommonConnectorPattern);
227
316
  }
228
- if (!oFormat.oFormatOptions.fallback) {
229
- if (!oInfo.oFallbackFormats) {
230
- oInfo.oFallbackFormats = {};
317
+ if (!bIsFallback) {
318
+ aFallbackFormatOptions = oInfo.aFallbackFormatOptions;
319
+ if (oInfo.bShortFallbackFormatOptions) {
320
+ sPattern = oInfo.getPattern(oFormat.oLocaleData, 'short');
321
+ aFallbackFormatOptions = aFallbackFormatOptions.concat(DateFormat._createFallbackOptionsWithoutDelimiter(sPattern));
231
322
  }
232
- var sLocale = oLocale.toString(), sCalendarType = oFormat.oFormatOptions.calendarType, sKey = sLocale + '-' + sCalendarType, sPattern, aFallbackFormatOptions;
233
323
  if (oFormat.oFormatOptions.pattern && oInfo.bPatternFallbackWithoutDelimiter) {
234
- sKey = sKey + '-' + oFormat.oFormatOptions.pattern;
235
- }
236
- if (oFormat.oFormatOptions.interval) {
237
- sKey = sKey + '-' + 'interval';
324
+ aFallbackFormatOptions = DateFormat._createFallbackOptionsWithoutDelimiter(oFormat.oFormatOptions.pattern).concat(aFallbackFormatOptions);
238
325
  }
239
- var oFallbackFormats = oInfo.oFallbackFormats[sKey] ? Object.assign({}, oInfo.oFallbackFormats[sKey]) : undefined;
240
- if (!oFallbackFormats) {
241
- aFallbackFormatOptions = oInfo.aFallbackFormatOptions;
242
- if (oInfo.bShortFallbackFormatOptions) {
243
- sPattern = oInfo.getPattern(oFormat.oLocaleData, 'short');
244
- aFallbackFormatOptions = aFallbackFormatOptions.concat(DateFormat._createFallbackOptionsWithoutDelimiter(sPattern));
245
- }
246
- if (oFormat.oFormatOptions.pattern && oInfo.bPatternFallbackWithoutDelimiter) {
247
- aFallbackFormatOptions = DateFormat._createFallbackOptionsWithoutDelimiter(oFormat.oFormatOptions.pattern).concat(aFallbackFormatOptions);
326
+ aFallbackFormatOptions = aFallbackFormatOptions.reduce(function (aFallbacks, oOptions) {
327
+ var aKeys = Object.keys(oOptions), bDuplicate = aFallbacks.some(function (oOptions0) {
328
+ return Object.keys(oOptions0).length === aKeys.length && aKeys.every(function (sKey) {
329
+ return oOptions0[sKey] === oOptions[sKey];
330
+ });
331
+ });
332
+ if (!bDuplicate) {
333
+ aFallbacks.push(oOptions);
248
334
  }
249
- oFallbackFormats = DateFormat._createFallbackFormat(aFallbackFormatOptions, sCalendarType, oLocale, oInfo, oFormat.oFormatOptions.interval);
250
- }
251
- oFormat.aFallbackFormats = oFallbackFormats;
335
+ return aFallbacks;
336
+ }, []);
337
+ oFormat.aFallbackFormats = DateFormat._createFallbackFormat(aFallbackFormatOptions, oFormat.oFormatOptions.calendarType, oLocale, oInfo, oFormat.oFormatOptions);
252
338
  }
253
339
  oFormat.oRequiredParts = oInfo.oRequiredParts;
254
340
  oFormat.aRelativeScales = oInfo.aRelativeScales;
@@ -282,21 +368,32 @@ DateFormat.prototype.init = function () {
282
368
  this.aErasNarrow = this.oLocaleData.getEras('narrow', sCalendarType);
283
369
  this.aErasAbbrev = this.oLocaleData.getEras('abbreviated', sCalendarType);
284
370
  this.aErasWide = this.oLocaleData.getEras('wide', sCalendarType);
285
- this.aDayPeriods = this.oLocaleData.getDayPeriods('abbreviated', sCalendarType);
371
+ this.aDayPeriodsAbbrev = this.oLocaleData.getDayPeriods('abbreviated', sCalendarType);
372
+ this.aDayPeriodsNarrow = this.oLocaleData.getDayPeriods('narrow', sCalendarType);
373
+ this.aDayPeriodsWide = this.oLocaleData.getDayPeriods('wide', sCalendarType);
374
+ this.oFlexibleDayPeriodsAbbrev = this.oLocaleData.getFlexibleDayPeriods('abbreviated', sCalendarType);
375
+ this.oFlexibleDayPeriodsNarrow = this.oLocaleData.getFlexibleDayPeriods('narrow', sCalendarType);
376
+ this.oFlexibleDayPeriodsWide = this.oLocaleData.getFlexibleDayPeriods('wide', sCalendarType);
377
+ this.oFlexibleDayPeriodsAbbrevSt = this.oLocaleData.getFlexibleDayPeriodsStandAlone('abbreviated', sCalendarType);
378
+ this.oFlexibleDayPeriodsNarrowSt = this.oLocaleData.getFlexibleDayPeriodsStandAlone('narrow', sCalendarType);
379
+ this.oFlexibleDayPeriodsWideSt = this.oLocaleData.getFlexibleDayPeriodsStandAlone('wide', sCalendarType);
286
380
  this.aFormatArray = this.parseCldrDatePattern(this.oFormatOptions.pattern);
287
381
  this.sAllowedCharacters = this.getAllowedCharacters(this.aFormatArray);
288
382
  };
289
- DateFormat._createFallbackFormat = function (aFallbackFormatOptions, sCalendarType, oLocale, oInfo, bInterval) {
383
+ DateFormat._createFallbackFormat = function (aFallbackFormatOptions, sCalendarType, oLocale, oInfo, oParentFormatOptions) {
290
384
  return aFallbackFormatOptions.map(function (oOptions) {
291
385
  var oFormatOptions = Object.assign({}, oOptions);
292
- if (bInterval) {
386
+ oFormatOptions.showDate = oParentFormatOptions.showDate;
387
+ oFormatOptions.showTime = oParentFormatOptions.showTime;
388
+ oFormatOptions.showTimezone = oParentFormatOptions.showTimezone;
389
+ if (typeof oInfo.getTimezonePattern === 'function' && oFormatOptions.pattern) {
390
+ oFormatOptions.pattern = oInfo.getTimezonePattern(oFormatOptions.pattern);
391
+ }
392
+ if (oParentFormatOptions.interval) {
293
393
  oFormatOptions.interval = true;
294
394
  }
295
395
  oFormatOptions.calendarType = sCalendarType;
296
- oFormatOptions.fallback = true;
297
- var oFallbackFormat = DateFormat.createInstance(oFormatOptions, oLocale, oInfo);
298
- oFallbackFormat.bIsFallback = true;
299
- return oFallbackFormat;
396
+ return DateFormat.createInstance(oFormatOptions, oLocale, oInfo, true);
300
397
  });
301
398
  };
302
399
  DateFormat._createFallbackOptionsWithoutDelimiter = function (sBasePattern) {
@@ -332,27 +429,39 @@ var oParseHelper = {
332
429
  while (iLength < iMaxLength && this.isNumber(sValue.charCodeAt(iLength))) {
333
430
  iLength++;
334
431
  }
335
- if (typeof sValue !== 'string') {
336
- sValue = sValue.toString();
337
- }
338
432
  return sValue.substr(0, iLength);
339
433
  },
340
- findEntry: function (sValue, aList) {
434
+ startsWithIgnoreCase: function (sValue, sSubstring, sLocale) {
435
+ if (sValue.startsWith(sSubstring)) {
436
+ return true;
437
+ }
438
+ try {
439
+ var sSubToLocaleUpperCase = sSubstring.toLocaleUpperCase(sLocale);
440
+ var sValueUpperCase = sValue.toLocaleUpperCase(sLocale);
441
+ if (sSubToLocaleUpperCase.length !== sSubstring.length || sValueUpperCase.length !== sValue.length) {
442
+ return false;
443
+ }
444
+ return sValueUpperCase.startsWith(sSubToLocaleUpperCase);
445
+ } catch (e) {
446
+ return false;
447
+ }
448
+ },
449
+ findEntry: function (sValue, aList, sLocale) {
341
450
  var iFoundIndex = -1, iMatchedLength = 0;
342
451
  for (var j = 0; j < aList.length; j++) {
343
- if (aList[j] && aList[j].length > iMatchedLength && sValue.indexOf(aList[j]) === 0) {
452
+ if (aList[j] && aList[j].length > iMatchedLength && this.startsWithIgnoreCase(sValue, aList[j], sLocale)) {
344
453
  iFoundIndex = j;
345
454
  iMatchedLength = aList[j].length;
346
455
  }
347
456
  }
348
457
  return {
349
458
  index: iFoundIndex,
350
- value: iFoundIndex === -1 ? null : aList[iFoundIndex]
459
+ length: iMatchedLength
351
460
  };
352
461
  },
353
462
  parseTZ: function (sValue, bColonSeparated) {
354
463
  var iLength = 0;
355
- var iTZFactor = sValue.charAt(0) == '+' ? -1 : 1;
464
+ var iTZFactor = sValue.charAt(0) === '+' ? -1 : 1;
356
465
  var sPart;
357
466
  iLength++;
358
467
  sPart = this.findNumbers(sValue.substr(iLength), 2);
@@ -369,19 +478,35 @@ var oParseHelper = {
369
478
  }
370
479
  return {
371
480
  length: iLength,
372
- tzDiff: (iTZDiff + 60 * iTZDiffHour) * iTZFactor
481
+ tzDiff: (iTZDiff + 60 * iTZDiffHour) * 60 * iTZFactor
373
482
  };
374
483
  },
375
- checkValid: function (sType, bPartInvalid, oFormat) {
376
- if (sType in oFormat.oRequiredParts && bPartInvalid) {
484
+ checkValid: function (sSymbolName, bPartInvalid, oFormat) {
485
+ if (sSymbolName in oFormat.oRequiredParts && bPartInvalid) {
377
486
  return false;
378
487
  }
488
+ return true;
379
489
  }
380
490
  };
491
+ DateFormat._createPatternSymbol = function (mParameters) {
492
+ var fnIsNumeric = typeof mParameters.isNumeric === 'function' && mParameters.isNumeric || function () {
493
+ return mParameters.isNumeric || false;
494
+ };
495
+ return {
496
+ name: mParameters.name,
497
+ format: mParameters.format || function () {
498
+ return '';
499
+ },
500
+ parse: mParameters.parse || function () {
501
+ return {};
502
+ },
503
+ isNumeric: fnIsNumeric
504
+ };
505
+ };
381
506
  DateFormat.prototype.oSymbols = {
382
- '': {
507
+ '': DateFormat._createPatternSymbol({
383
508
  name: 'text',
384
- format: function (oField, oDate, bUTC, oFormat) {
509
+ format: function (oField, oDate) {
385
510
  return oField.value;
386
511
  },
387
512
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -421,11 +546,11 @@ DateFormat.prototype.oSymbols = {
421
546
  return { valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat) };
422
547
  }
423
548
  }
424
- },
425
- 'G': {
549
+ }),
550
+ 'G': DateFormat._createPatternSymbol({
426
551
  name: 'era',
427
552
  format: function (oField, oDate, bUTC, oFormat) {
428
- var iEra = bUTC ? oDate.getUTCEra() : oDate.getEra();
553
+ var iEra = oDate.getUTCEra();
429
554
  if (oField.digits <= 3) {
430
555
  return oFormat.aErasAbbrev[iEra];
431
556
  } else if (oField.digits === 4) {
@@ -442,11 +567,11 @@ DateFormat.prototype.oSymbols = {
442
567
  ];
443
568
  for (var i = 0; i < aErasVariants.length; i++) {
444
569
  var aVariants = aErasVariants[i];
445
- var oFound = oParseHelper.findEntry(sValue, aVariants);
570
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
446
571
  if (oFound.index !== -1) {
447
572
  return {
448
573
  era: oFound.index,
449
- length: oFound.value.length
574
+ length: oFound.length
450
575
  };
451
576
  }
452
577
  }
@@ -455,34 +580,35 @@ DateFormat.prototype.oSymbols = {
455
580
  valid: oParseHelper.checkValid(oPart.type, true, oFormat)
456
581
  };
457
582
  }
458
- },
459
- 'y': {
583
+ }),
584
+ 'y': DateFormat._createPatternSymbol({
460
585
  name: 'year',
461
586
  format: function (oField, oDate, bUTC, oFormat) {
462
- var iYear = bUTC ? oDate.getUTCFullYear() : oDate.getFullYear();
587
+ var iYear = oDate.getUTCFullYear();
463
588
  var sYear = String(iYear);
464
589
  var sCalendarType = oFormat.oFormatOptions.calendarType;
465
- if (oField.digits == 2 && sYear.length > 2) {
590
+ if (oField.digits === 2 && sYear.length > 2) {
466
591
  sYear = sYear.substr(sYear.length - 2);
467
592
  }
468
- if (sCalendarType != CalendarType.Japanese && oField.digits == 1 && iYear < 100) {
593
+ if (sCalendarType !== CalendarType.Japanese && oField.digits === 1 && iYear < 100) {
469
594
  sYear = sYear.padStart(4, '0');
470
595
  }
471
596
  return sYear.padStart(oField.digits, '0');
472
597
  },
473
598
  parse: function (sValue, oPart, oFormat, oConfig) {
474
- var sCalendarType = oFormat.oFormatOptions.calendarType;
475
- var sPart;
476
- if (oPart.digits == 1) {
477
- sPart = oParseHelper.findNumbers(sValue, 4);
478
- } else if (oPart.digits == 2) {
479
- sPart = oParseHelper.findNumbers(sValue, 2);
599
+ var iExpectedDigits, sPart, bPartInvalid, sCalendarType = oFormat.oFormatOptions.calendarType;
600
+ if (oPart.digits === 1) {
601
+ iExpectedDigits = 4;
602
+ } else if (oPart.digits === 2) {
603
+ iExpectedDigits = 2;
480
604
  } else {
481
- sPart = oParseHelper.findNumbers(sValue, oPart.digits);
605
+ iExpectedDigits = oPart.digits;
482
606
  }
607
+ sPart = oParseHelper.findNumbers(sValue, iExpectedDigits);
608
+ bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length !== iExpectedDigits;
483
609
  var iYear = parseInt(sPart);
484
- if (sCalendarType != CalendarType.Japanese && sPart.length <= 2) {
485
- var oCurrentDate = UniversalDate.getInstance(new Date(), sCalendarType), iCurrentYear = oCurrentDate.getFullYear(), iCurrentCentury = Math.floor(iCurrentYear / 100), iYearDiff = iCurrentCentury * 100 + iYear - iCurrentYear;
610
+ if (sCalendarType !== CalendarType.Japanese && sPart.length <= 2) {
611
+ var oCurrentDate = UniversalDate.getInstance(UI5Date.getInstance(), sCalendarType), iCurrentYear = oCurrentDate.getUTCFullYear(), iCurrentCentury = Math.floor(iCurrentYear / 100), iYearDiff = iCurrentCentury * 100 + iYear - iCurrentYear;
486
612
  if (iYearDiff < -70) {
487
613
  iYear += (iCurrentCentury + 1) * 100;
488
614
  } else if (iYearDiff < 30) {
@@ -493,40 +619,42 @@ DateFormat.prototype.oSymbols = {
493
619
  }
494
620
  return {
495
621
  length: sPart.length,
496
- valid: oParseHelper.checkValid(oPart.type, sPart === '', oFormat),
622
+ valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat),
497
623
  year: iYear
498
624
  };
499
- }
500
- },
501
- 'Y': {
625
+ },
626
+ isNumeric: true
627
+ }),
628
+ 'Y': DateFormat._createPatternSymbol({
502
629
  name: 'weekYear',
503
630
  format: function (oField, oDate, bUTC, oFormat) {
504
- var oWeek = bUTC ? oDate.getUTCWeek() : oDate.getWeek();
631
+ var oWeek = oDate.getUTCWeek(oFormat.oLocale, getCalendarWeekParameter(oFormat.oFormatOptions));
505
632
  var iWeekYear = oWeek.year;
506
633
  var sWeekYear = String(iWeekYear);
507
634
  var sCalendarType = oFormat.oFormatOptions.calendarType;
508
- if (oField.digits == 2 && sWeekYear.length > 2) {
635
+ if (oField.digits === 2 && sWeekYear.length > 2) {
509
636
  sWeekYear = sWeekYear.substr(sWeekYear.length - 2);
510
637
  }
511
- if (sCalendarType != CalendarType.Japanese && oField.digits == 1 && iWeekYear < 100) {
638
+ if (sCalendarType !== CalendarType.Japanese && oField.digits === 1 && iWeekYear < 100) {
512
639
  sWeekYear = sWeekYear.padStart(4, '0');
513
640
  }
514
641
  return sWeekYear.padStart(oField.digits, '0');
515
642
  },
516
643
  parse: function (sValue, oPart, oFormat, oConfig) {
517
- var sCalendarType = oFormat.oFormatOptions.calendarType;
518
- var sPart;
519
- if (oPart.digits == 1) {
520
- sPart = oParseHelper.findNumbers(sValue, 4);
521
- } else if (oPart.digits == 2) {
522
- sPart = oParseHelper.findNumbers(sValue, 2);
644
+ var iExpectedDigits, sPart, bPartInvalid, sCalendarType = oFormat.oFormatOptions.calendarType;
645
+ if (oPart.digits === 1) {
646
+ iExpectedDigits = 4;
647
+ } else if (oPart.digits === 2) {
648
+ iExpectedDigits = 2;
523
649
  } else {
524
- sPart = oParseHelper.findNumbers(sValue, oPart.digits);
650
+ iExpectedDigits = oPart.digits;
525
651
  }
652
+ sPart = oParseHelper.findNumbers(sValue, iExpectedDigits);
653
+ bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length !== iExpectedDigits;
526
654
  var iYear = parseInt(sPart);
527
- var iWeekYear;
528
- if (sCalendarType != CalendarType.Japanese && sPart.length <= 2) {
529
- var oCurrentDate = UniversalDate.getInstance(new Date(), sCalendarType), iCurrentYear = oCurrentDate.getFullYear(), iCurrentCentury = Math.floor(iCurrentYear / 100), iYearDiff = iCurrentCentury * 100 + iWeekYear - iCurrentYear;
655
+ var iWeekYear = iYear;
656
+ if (sCalendarType !== CalendarType.Japanese && sPart.length <= 2) {
657
+ var oCurrentDate = UniversalDate.getInstance(UI5Date.getInstance(), sCalendarType), iCurrentYear = oCurrentDate.getUTCFullYear(), iCurrentCentury = Math.floor(iCurrentYear / 100), iYearDiff = iCurrentCentury * 100 + iWeekYear - iCurrentYear;
530
658
  if (iYearDiff < -70) {
531
659
  iWeekYear += (iCurrentCentury + 1) * 100;
532
660
  } else if (iYearDiff < 30) {
@@ -537,19 +665,20 @@ DateFormat.prototype.oSymbols = {
537
665
  }
538
666
  return {
539
667
  length: sPart.length,
540
- valid: oParseHelper.checkValid(oPart.type, sPart === '', oFormat),
668
+ valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat),
541
669
  year: iYear,
542
670
  weekYear: iWeekYear
543
671
  };
544
- }
545
- },
546
- 'M': {
672
+ },
673
+ isNumeric: true
674
+ }),
675
+ 'M': DateFormat._createPatternSymbol({
547
676
  name: 'month',
548
677
  format: function (oField, oDate, bUTC, oFormat) {
549
- var iMonth = bUTC ? oDate.getUTCMonth() : oDate.getMonth();
550
- if (oField.digits == 3) {
678
+ var iMonth = oDate.getUTCMonth();
679
+ if (oField.digits === 3) {
551
680
  return oFormat.aMonthsAbbrev[iMonth];
552
- } else if (oField.digits == 4) {
681
+ } else if (oField.digits === 4) {
553
682
  return oFormat.aMonthsWide[iMonth];
554
683
  } else if (oField.digits > 4) {
555
684
  return oFormat.aMonthsNarrow[iMonth];
@@ -558,20 +687,18 @@ DateFormat.prototype.oSymbols = {
558
687
  }
559
688
  },
560
689
  parse: function (sValue, oPart, oFormat, oConfig) {
561
- var aMonthsVariants = [
562
- oFormat.aMonthsWide,
563
- oFormat.aMonthsWideSt,
564
- oFormat.aMonthsAbbrev,
565
- oFormat.aMonthsAbbrevSt,
566
- oFormat.aMonthsNarrow,
567
- oFormat.aMonthsNarrowSt
568
- ];
569
- var bValid;
570
- var iMonth;
571
- var sPart;
690
+ var iMonth, sPart, bPartInvalid, bValid, aMonthsVariants = [
691
+ oFormat.aMonthsWide,
692
+ oFormat.aMonthsWideSt,
693
+ oFormat.aMonthsAbbrev,
694
+ oFormat.aMonthsAbbrevSt,
695
+ oFormat.aMonthsNarrow,
696
+ oFormat.aMonthsNarrowSt
697
+ ];
572
698
  if (oPart.digits < 3) {
573
699
  sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
574
- bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
700
+ bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < 2;
701
+ bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
575
702
  iMonth = parseInt(sPart) - 1;
576
703
  if (oConfig.strict && (iMonth > 11 || iMonth < 0)) {
577
704
  bValid = false;
@@ -579,11 +706,11 @@ DateFormat.prototype.oSymbols = {
579
706
  } else {
580
707
  for (var i = 0; i < aMonthsVariants.length; i++) {
581
708
  var aVariants = aMonthsVariants[i];
582
- var oFound = oParseHelper.findEntry(sValue, aVariants);
709
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
583
710
  if (oFound.index !== -1) {
584
711
  return {
585
712
  month: oFound.index,
586
- length: oFound.value.length
713
+ length: oFound.length
587
714
  };
588
715
  }
589
716
  }
@@ -594,15 +721,18 @@ DateFormat.prototype.oSymbols = {
594
721
  length: sPart ? sPart.length : 0,
595
722
  valid: bValid
596
723
  };
724
+ },
725
+ isNumeric: function (iDigits) {
726
+ return iDigits < 3;
597
727
  }
598
- },
599
- 'L': {
728
+ }),
729
+ 'L': DateFormat._createPatternSymbol({
600
730
  name: 'monthStandalone',
601
731
  format: function (oField, oDate, bUTC, oFormat) {
602
- var iMonth = bUTC ? oDate.getUTCMonth() : oDate.getMonth();
603
- if (oField.digits == 3) {
732
+ var iMonth = oDate.getUTCMonth();
733
+ if (oField.digits === 3) {
604
734
  return oFormat.aMonthsAbbrevSt[iMonth];
605
- } else if (oField.digits == 4) {
735
+ } else if (oField.digits === 4) {
606
736
  return oFormat.aMonthsWideSt[iMonth];
607
737
  } else if (oField.digits > 4) {
608
738
  return oFormat.aMonthsNarrowSt[iMonth];
@@ -611,20 +741,18 @@ DateFormat.prototype.oSymbols = {
611
741
  }
612
742
  },
613
743
  parse: function (sValue, oPart, oFormat, oConfig) {
614
- var aMonthsVariants = [
615
- oFormat.aMonthsWide,
616
- oFormat.aMonthsWideSt,
617
- oFormat.aMonthsAbbrev,
618
- oFormat.aMonthsAbbrevSt,
619
- oFormat.aMonthsNarrow,
620
- oFormat.aMonthsNarrowSt
621
- ];
622
- var bValid;
623
- var iMonth;
624
- var sPart;
744
+ var iMonth, sPart, bPartInvalid, bValid, aMonthsVariants = [
745
+ oFormat.aMonthsWide,
746
+ oFormat.aMonthsWideSt,
747
+ oFormat.aMonthsAbbrev,
748
+ oFormat.aMonthsAbbrevSt,
749
+ oFormat.aMonthsNarrow,
750
+ oFormat.aMonthsNarrowSt
751
+ ];
625
752
  if (oPart.digits < 3) {
626
753
  sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
627
- bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
754
+ bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < 2;
755
+ bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
628
756
  iMonth = parseInt(sPart) - 1;
629
757
  if (oConfig.strict && (iMonth > 11 || iMonth < 0)) {
630
758
  bValid = false;
@@ -632,11 +760,11 @@ DateFormat.prototype.oSymbols = {
632
760
  } else {
633
761
  for (var i = 0; i < aMonthsVariants.length; i++) {
634
762
  var aVariants = aMonthsVariants[i];
635
- var oFound = oParseHelper.findEntry(sValue, aVariants);
763
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
636
764
  if (oFound.index !== -1) {
637
765
  return {
638
766
  month: oFound.index,
639
- length: oFound.value.length
767
+ length: oFound.length
640
768
  };
641
769
  }
642
770
  }
@@ -647,12 +775,15 @@ DateFormat.prototype.oSymbols = {
647
775
  length: sPart ? sPart.length : 0,
648
776
  valid: bValid
649
777
  };
778
+ },
779
+ isNumeric: function (iDigits) {
780
+ return iDigits < 3;
650
781
  }
651
- },
652
- 'w': {
782
+ }),
783
+ 'w': DateFormat._createPatternSymbol({
653
784
  name: 'weekInYear',
654
785
  format: function (oField, oDate, bUTC, oFormat) {
655
- var oWeek = bUTC ? oDate.getUTCWeek() : oDate.getWeek();
786
+ var oWeek = oDate.getUTCWeek(oFormat.oLocale, getCalendarWeekParameter(oFormat.oFormatOptions));
656
787
  var iWeek = oWeek.week;
657
788
  var sWeek = String(iWeek + 1);
658
789
  if (oField.digits < 3) {
@@ -663,22 +794,20 @@ DateFormat.prototype.oSymbols = {
663
794
  return sWeek;
664
795
  },
665
796
  parse: function (sValue, oPart, oFormat, oConfig) {
666
- var bValid;
667
- var sPart;
668
- var iWeek;
669
- var iLength = 0;
797
+ var sPart, bPartInvalid, bValid, iWeek, iLength = 0;
670
798
  if (oPart.digits < 3) {
671
799
  sPart = oParseHelper.findNumbers(sValue, 2);
672
800
  iLength = sPart.length;
673
801
  iWeek = parseInt(sPart) - 1;
674
- bValid = oParseHelper.checkValid(oPart.type, !sPart, oFormat);
802
+ bPartInvalid = !sPart || oConfig.exactLength && iLength < 2;
803
+ bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
675
804
  } else {
676
805
  sPart = oFormat.oLocaleData.getCalendarWeek(oPart.digits === 3 ? 'narrow' : 'wide');
677
- sPart = sPart.replace('{0}', '[0-9]+');
806
+ sPart = sPart.replace('{0}', '([0-9]+)');
678
807
  var rWeekNumber = new RegExp(sPart), oResult = rWeekNumber.exec(sValue);
679
808
  if (oResult) {
680
809
  iLength = oResult[0].length;
681
- iWeek = parseInt(oResult[0]) - 1;
810
+ iWeek = parseInt(oResult[oResult.length - 1]) - 1;
682
811
  } else {
683
812
  bValid = oParseHelper.checkValid(oPart.type, true, oFormat);
684
813
  }
@@ -688,35 +817,21 @@ DateFormat.prototype.oSymbols = {
688
817
  valid: bValid,
689
818
  week: iWeek
690
819
  };
691
- }
692
- },
693
- 'W': {
694
- name: 'weekInMonth',
695
- format: function (oField, oDate, bUTC, oFormat) {
696
- return '';
697
820
  },
698
- parse: function () {
699
- return {};
821
+ isNumeric: function (iDigits) {
822
+ return iDigits < 3;
700
823
  }
701
- },
702
- 'D': {
703
- name: 'dayInYear',
704
- format: function (oField, oDate, bUTC, oFormat) {
705
- },
706
- parse: function () {
707
- return {};
708
- }
709
- },
710
- 'd': {
824
+ }),
825
+ 'W': DateFormat._createPatternSymbol({ name: 'weekInMonth' }),
826
+ 'D': DateFormat._createPatternSymbol({ name: 'dayInYear' }),
827
+ 'd': DateFormat._createPatternSymbol({
711
828
  name: 'day',
712
- format: function (oField, oDate, bUTC, oFormat) {
713
- var iDate = bUTC ? oDate.getUTCDate() : oDate.getDate();
829
+ format: function (oField, oDate) {
830
+ var iDate = oDate.getUTCDate();
714
831
  return String(iDate).padStart(oField.digits, '0');
715
832
  },
716
833
  parse: function (sValue, oPart, oFormat, oConfig) {
717
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
718
- var bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
719
- var iDay = parseInt(sPart);
834
+ var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)), bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < 2, bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat), iDay = parseInt(sPart);
720
835
  if (oConfig.strict && (iDay > 31 || iDay < 1)) {
721
836
  bValid = false;
722
837
  }
@@ -725,15 +840,16 @@ DateFormat.prototype.oSymbols = {
725
840
  length: sPart.length,
726
841
  valid: bValid
727
842
  };
728
- }
729
- },
730
- 'Q': {
843
+ },
844
+ isNumeric: true
845
+ }),
846
+ 'Q': DateFormat._createPatternSymbol({
731
847
  name: 'quarter',
732
848
  format: function (oField, oDate, bUTC, oFormat) {
733
- var iQuarter = bUTC ? oDate.getUTCQuarter() : oDate.getQuarter();
734
- if (oField.digits == 3) {
849
+ var iQuarter = oDate.getUTCQuarter();
850
+ if (oField.digits === 3) {
735
851
  return oFormat.aQuartersAbbrev[iQuarter];
736
- } else if (oField.digits == 4) {
852
+ } else if (oField.digits === 4) {
737
853
  return oFormat.aQuartersWide[iQuarter];
738
854
  } else if (oField.digits > 4) {
739
855
  return oFormat.aQuartersNarrow[iQuarter];
@@ -742,9 +858,7 @@ DateFormat.prototype.oSymbols = {
742
858
  }
743
859
  },
744
860
  parse: function (sValue, oPart, oFormat, oConfig) {
745
- var bValid;
746
- var iQuarter;
747
- var sPart;
861
+ var sPart, bPartInvalid, iQuarter, bValid;
748
862
  var aQuartersVariants = [
749
863
  oFormat.aQuartersWide,
750
864
  oFormat.aQuartersWideSt,
@@ -755,7 +869,8 @@ DateFormat.prototype.oSymbols = {
755
869
  ];
756
870
  if (oPart.digits < 3) {
757
871
  sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
758
- bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
872
+ bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < 2;
873
+ bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
759
874
  iQuarter = parseInt(sPart) - 1;
760
875
  if (oConfig.strict && iQuarter > 3) {
761
876
  bValid = false;
@@ -763,11 +878,11 @@ DateFormat.prototype.oSymbols = {
763
878
  } else {
764
879
  for (var i = 0; i < aQuartersVariants.length; i++) {
765
880
  var aVariants = aQuartersVariants[i];
766
- var oFound = oParseHelper.findEntry(sValue, aVariants);
881
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
767
882
  if (oFound.index !== -1) {
768
883
  return {
769
884
  quarter: oFound.index,
770
- length: oFound.value.length
885
+ length: oFound.length
771
886
  };
772
887
  }
773
888
  }
@@ -778,15 +893,18 @@ DateFormat.prototype.oSymbols = {
778
893
  quarter: iQuarter,
779
894
  valid: bValid
780
895
  };
896
+ },
897
+ isNumeric: function (iDigits) {
898
+ return iDigits < 3;
781
899
  }
782
- },
783
- 'q': {
900
+ }),
901
+ 'q': DateFormat._createPatternSymbol({
784
902
  name: 'quarterStandalone',
785
903
  format: function (oField, oDate, bUTC, oFormat) {
786
- var iQuarter = bUTC ? oDate.getUTCQuarter() : oDate.getQuarter();
787
- if (oField.digits == 3) {
904
+ var iQuarter = oDate.getUTCQuarter();
905
+ if (oField.digits === 3) {
788
906
  return oFormat.aQuartersAbbrevSt[iQuarter];
789
- } else if (oField.digits == 4) {
907
+ } else if (oField.digits === 4) {
790
908
  return oFormat.aQuartersWideSt[iQuarter];
791
909
  } else if (oField.digits > 4) {
792
910
  return oFormat.aQuartersNarrowSt[iQuarter];
@@ -795,9 +913,7 @@ DateFormat.prototype.oSymbols = {
795
913
  }
796
914
  },
797
915
  parse: function (sValue, oPart, oFormat, oConfig) {
798
- var bValid;
799
- var iQuarter;
800
- var sPart;
916
+ var sPart, bPartInvalid, iQuarter, bValid;
801
917
  var aQuartersVariants = [
802
918
  oFormat.aQuartersWide,
803
919
  oFormat.aQuartersWideSt,
@@ -808,7 +924,8 @@ DateFormat.prototype.oSymbols = {
808
924
  ];
809
925
  if (oPart.digits < 3) {
810
926
  sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
811
- bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
927
+ bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < 2;
928
+ bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
812
929
  iQuarter = parseInt(sPart) - 1;
813
930
  if (oConfig.strict && iQuarter > 3) {
814
931
  bValid = false;
@@ -816,11 +933,11 @@ DateFormat.prototype.oSymbols = {
816
933
  } else {
817
934
  for (var i = 0; i < aQuartersVariants.length; i++) {
818
935
  var aVariants = aQuartersVariants[i];
819
- var oFound = oParseHelper.findEntry(sValue, aVariants);
936
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
820
937
  if (oFound.index !== -1) {
821
938
  return {
822
939
  quarter: oFound.index,
823
- length: oFound.value.length
940
+ length: oFound.length
824
941
  };
825
942
  }
826
943
  }
@@ -831,26 +948,21 @@ DateFormat.prototype.oSymbols = {
831
948
  quarter: iQuarter,
832
949
  valid: bValid
833
950
  };
834
- }
835
- },
836
- 'F': {
837
- name: 'dayOfWeekInMonth',
838
- format: function (oField, oDate, bUTC, oFormat) {
839
- return '';
840
951
  },
841
- parse: function () {
842
- return {};
952
+ isNumeric: function (iDigits) {
953
+ return iDigits < 3;
843
954
  }
844
- },
845
- 'E': {
955
+ }),
956
+ 'F': DateFormat._createPatternSymbol({ name: 'dayOfWeekInMonth' }),
957
+ 'E': DateFormat._createPatternSymbol({
846
958
  name: 'dayNameInWeek',
847
959
  format: function (oField, oDate, bUTC, oFormat) {
848
- var iDay = bUTC ? oDate.getUTCDay() : oDate.getDay();
960
+ var iDay = oDate.getUTCDay();
849
961
  if (oField.digits < 4) {
850
962
  return oFormat.aDaysAbbrev[iDay];
851
- } else if (oField.digits == 4) {
963
+ } else if (oField.digits === 4) {
852
964
  return oFormat.aDaysWide[iDay];
853
- } else if (oField.digits == 5) {
965
+ } else if (oField.digits === 5) {
854
966
  return oFormat.aDaysNarrow[iDay];
855
967
  } else {
856
968
  return oFormat.aDaysShort[iDay];
@@ -869,25 +981,25 @@ DateFormat.prototype.oSymbols = {
869
981
  ];
870
982
  for (var i = 0; i < aDaysVariants.length; i++) {
871
983
  var aVariants = aDaysVariants[i];
872
- var oFound = oParseHelper.findEntry(sValue, aVariants);
984
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
873
985
  if (oFound.index !== -1) {
874
986
  return {
875
987
  dayOfWeek: oFound.index,
876
- length: oFound.value.length
988
+ length: oFound.length
877
989
  };
878
990
  }
879
991
  }
880
992
  }
881
- },
882
- 'c': {
993
+ }),
994
+ 'c': DateFormat._createPatternSymbol({
883
995
  name: 'dayNameInWeekStandalone',
884
996
  format: function (oField, oDate, bUTC, oFormat) {
885
- var iDay = bUTC ? oDate.getUTCDay() : oDate.getDay();
997
+ var iDay = oDate.getUTCDay();
886
998
  if (oField.digits < 4) {
887
999
  return oFormat.aDaysAbbrevSt[iDay];
888
- } else if (oField.digits == 4) {
1000
+ } else if (oField.digits === 4) {
889
1001
  return oFormat.aDaysWideSt[iDay];
890
- } else if (oField.digits == 5) {
1002
+ } else if (oField.digits === 5) {
891
1003
  return oFormat.aDaysNarrowSt[iDay];
892
1004
  } else {
893
1005
  return oFormat.aDaysShortSt[iDay];
@@ -906,72 +1018,129 @@ DateFormat.prototype.oSymbols = {
906
1018
  ];
907
1019
  for (var i = 0; i < aDaysVariants.length; i++) {
908
1020
  var aVariants = aDaysVariants[i];
909
- var oFound = oParseHelper.findEntry(sValue, aVariants);
1021
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
910
1022
  if (oFound.index !== -1) {
911
1023
  return {
912
1024
  day: oFound.index,
913
- length: oFound.value.length
1025
+ length: oFound.length
914
1026
  };
915
1027
  }
916
1028
  }
917
1029
  }
918
- },
919
- 'u': {
1030
+ }),
1031
+ 'u': DateFormat._createPatternSymbol({
920
1032
  name: 'dayNumberOfWeek',
921
1033
  format: function (oField, oDate, bUTC, oFormat) {
922
- var iDay = bUTC ? oDate.getUTCDay() : oDate.getDay();
1034
+ var iDay = oDate.getUTCDay();
923
1035
  return oFormat._adaptDayOfWeek(iDay);
924
1036
  },
925
1037
  parse: function (sValue, oPart, oFormat, oConfig) {
926
- var sPart = oParseHelper.findNumbers(sValue, oPart.digits);
1038
+ var sPart = oParseHelper.findNumbers(sValue, oPart.digits), bPartInvalid = oConfig.exactLength && sPart.length !== oPart.digits;
927
1039
  return {
928
1040
  dayNumberOfWeek: parseInt(sPart),
929
- length: sPart.length
1041
+ length: sPart.length,
1042
+ valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat)
930
1043
  };
931
- }
932
- },
933
- 'a': {
1044
+ },
1045
+ isNumeric: true
1046
+ }),
1047
+ 'a': DateFormat._createPatternSymbol({
934
1048
  name: 'amPmMarker',
935
1049
  format: function (oField, oDate, bUTC, oFormat) {
936
- var iDayPeriod = bUTC ? oDate.getUTCDayPeriod() : oDate.getDayPeriod();
937
- return oFormat.aDayPeriods[iDayPeriod];
1050
+ var iDayPeriod = oDate.getUTCDayPeriod();
1051
+ if (oField.digits <= 3) {
1052
+ return oFormat.aDayPeriodsAbbrev[iDayPeriod];
1053
+ } else if (oField.digits === 4) {
1054
+ return oFormat.aDayPeriodsWide[iDayPeriod];
1055
+ } else {
1056
+ return oFormat.aDayPeriodsNarrow[iDayPeriod];
1057
+ }
1058
+ },
1059
+ parse: function (sValue, oPart, oFormat, oConfig, sTimezone) {
1060
+ var rAMPM, bAMPMAlternativeCase, oEntry, i, aMatch, normalize, aVariants, aDayPeriodsVariants = [
1061
+ oFormat.aDayPeriodsWide,
1062
+ oFormat.aDayPeriodsAbbrev,
1063
+ oFormat.aDayPeriodsNarrow
1064
+ ];
1065
+ rAMPM = /[aApP](?:\.)?[\x20\xA0]?[mM](?:\.)?/;
1066
+ aMatch = sValue.match(rAMPM);
1067
+ bAMPMAlternativeCase = aMatch && aMatch.index === 0;
1068
+ function normalize(sValue) {
1069
+ return sValue.replace(/[\x20\xA0]/g, '').replace(/\./g, '');
1070
+ }
1071
+ if (bAMPMAlternativeCase) {
1072
+ sValue = normalize(sValue);
1073
+ }
1074
+ for (i = 0; i < aDayPeriodsVariants.length; i += 1) {
1075
+ aVariants = aDayPeriodsVariants[i];
1076
+ if (bAMPMAlternativeCase) {
1077
+ aVariants = aVariants.map(normalize);
1078
+ }
1079
+ oEntry = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
1080
+ if (oEntry.index !== -1) {
1081
+ return {
1082
+ pm: oEntry.index === 1,
1083
+ length: bAMPMAlternativeCase ? aMatch[0].length : oEntry.length
1084
+ };
1085
+ }
1086
+ }
1087
+ return { valid: false };
1088
+ }
1089
+ }),
1090
+ 'B': DateFormat._createPatternSymbol({
1091
+ name: 'flexibleDayPeriod',
1092
+ format: function (oField, oDate, bUTC, oFormat) {
1093
+ var bContainsHour = oFormat.aFormatArray.some(function (oFormatElement) {
1094
+ return 'hHKk'.includes(oFormatElement.symbol);
1095
+ }), sFlexibleDayPeriod = oFormat.oLocaleData.getFlexibleDayPeriodOfTime(oDate.getUTCHours(), oDate.getUTCMinutes());
1096
+ if (bContainsHour) {
1097
+ if (oField.digits <= 3) {
1098
+ return oFormat.oFlexibleDayPeriodsAbbrev[sFlexibleDayPeriod];
1099
+ }
1100
+ if (oField.digits === 4) {
1101
+ return oFormat.oFlexibleDayPeriodsWide[sFlexibleDayPeriod];
1102
+ }
1103
+ return oFormat.oFlexibleDayPeriodsNarrow[sFlexibleDayPeriod];
1104
+ }
1105
+ if (oField.digits <= 3) {
1106
+ return oFormat.oFlexibleDayPeriodsAbbrevSt[sFlexibleDayPeriod];
1107
+ }
1108
+ if (oField.digits === 4) {
1109
+ return oFormat.oFlexibleDayPeriodsWideSt[sFlexibleDayPeriod];
1110
+ }
1111
+ return oFormat.oFlexibleDayPeriodsNarrowSt[sFlexibleDayPeriod];
938
1112
  },
939
1113
  parse: function (sValue, oPart, oFormat, oConfig) {
940
- var bPM;
941
- var iLength;
942
- var sAM = oFormat.aDayPeriods[0], sPM = oFormat.aDayPeriods[1];
943
- var rAMPM = /[aApP](?:\.)?[mM](?:\.)?/;
944
- var aMatch = sValue.match(rAMPM);
945
- var bVariant = aMatch && aMatch.index === 0;
946
- if (bVariant) {
947
- sValue = aMatch[0].replace(/\./g, '').toLowerCase() + sValue.substring(aMatch[0].length);
948
- sAM = sAM.replace(/\./g, '').toLowerCase();
949
- sPM = sPM.replace(/\./g, '').toLowerCase();
950
- }
951
- if (sValue.indexOf(sAM) === 0) {
952
- bPM = false;
953
- iLength = bVariant ? aMatch[0].length : sAM.length;
954
- } else if (sValue.indexOf(sPM) === 0) {
955
- bPM = true;
956
- iLength = bVariant ? aMatch[0].length : sPM.length;
1114
+ var i, oFound, oVariant, bContainsHour = oFormat.aFormatArray.some(function (oFormatElement) {
1115
+ return 'hHKk'.includes(oFormatElement.symbol);
1116
+ }), aFlexibleDayPeriodVariants = [
1117
+ oFormat.oFlexibleDayPeriodsWide,
1118
+ oFormat.oFlexibleDayPeriodsAbbrev,
1119
+ oFormat.oFlexibleDayPeriodsNarrow
1120
+ ];
1121
+ if (bContainsHour) {
1122
+ for (i = 0; i < aFlexibleDayPeriodVariants.length; i++) {
1123
+ oVariant = aFlexibleDayPeriodVariants[i];
1124
+ oFound = oParseHelper.findEntry(sValue, Object.values(oVariant), oFormat.oLocaleData.sCLDRLocaleId);
1125
+ if (oFound.index !== -1) {
1126
+ return {
1127
+ flexDayPeriod: Object.keys(oVariant)[oFound.index],
1128
+ length: oFound.length
1129
+ };
1130
+ }
1131
+ }
957
1132
  }
958
- return {
959
- pm: bPM,
960
- length: iLength
961
- };
1133
+ return { valid: false };
962
1134
  }
963
- },
964
- 'H': {
1135
+ }),
1136
+ 'H': DateFormat._createPatternSymbol({
965
1137
  name: 'hour0_23',
966
- format: function (oField, oDate, bUTC, oFormat) {
967
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1138
+ format: function (oField, oDate) {
1139
+ var iHours = oDate.getUTCHours();
968
1140
  return String(iHours).padStart(oField.digits, '0');
969
1141
  },
970
1142
  parse: function (sValue, oPart, oFormat, oConfig) {
971
- var bValid;
972
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
973
- var iHours = parseInt(sPart);
974
- bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
1143
+ var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)), iHours = parseInt(sPart), bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < 2, bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
975
1144
  if (oConfig.strict && iHours > 23) {
976
1145
  bValid = false;
977
1146
  }
@@ -980,21 +1149,19 @@ DateFormat.prototype.oSymbols = {
980
1149
  length: sPart.length,
981
1150
  valid: bValid
982
1151
  };
983
- }
984
- },
985
- 'k': {
1152
+ },
1153
+ isNumeric: true
1154
+ }),
1155
+ 'k': DateFormat._createPatternSymbol({
986
1156
  name: 'hour1_24',
987
- format: function (oField, oDate, bUTC, oFormat) {
988
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1157
+ format: function (oField, oDate) {
1158
+ var iHours = oDate.getUTCHours();
989
1159
  var sHours = iHours === 0 ? '24' : String(iHours);
990
1160
  return sHours.padStart(oField.digits, '0');
991
1161
  },
992
1162
  parse: function (sValue, oPart, oFormat, oConfig) {
993
- var bValid;
994
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
995
- var iHours = parseInt(sPart);
996
- bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
997
- if (iHours == 24) {
1163
+ var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)), iHours = parseInt(sPart), bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < 2, bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
1164
+ if (iHours === 24) {
998
1165
  iHours = 0;
999
1166
  }
1000
1167
  if (oConfig.strict && iHours > 23) {
@@ -1005,20 +1172,18 @@ DateFormat.prototype.oSymbols = {
1005
1172
  length: sPart.length,
1006
1173
  valid: bValid
1007
1174
  };
1008
- }
1009
- },
1010
- 'K': {
1175
+ },
1176
+ isNumeric: true
1177
+ }),
1178
+ 'K': DateFormat._createPatternSymbol({
1011
1179
  name: 'hour0_11',
1012
- format: function (oField, oDate, bUTC, oFormat) {
1013
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1180
+ format: function (oField, oDate) {
1181
+ var iHours = oDate.getUTCHours();
1014
1182
  var sHours = String(iHours > 11 ? iHours - 12 : iHours);
1015
1183
  return sHours.padStart(oField.digits, '0');
1016
1184
  },
1017
1185
  parse: function (sValue, oPart, oFormat, oConfig) {
1018
- var bValid;
1019
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
1020
- var iHours = parseInt(sPart);
1021
- bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
1186
+ var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)), iHours = parseInt(sPart), bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < 2, bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
1022
1187
  if (oConfig.strict && iHours > 11) {
1023
1188
  bValid = false;
1024
1189
  }
@@ -1027,16 +1192,17 @@ DateFormat.prototype.oSymbols = {
1027
1192
  length: sPart.length,
1028
1193
  valid: bValid
1029
1194
  };
1030
- }
1031
- },
1032
- 'h': {
1195
+ },
1196
+ isNumeric: true
1197
+ }),
1198
+ 'h': DateFormat._createPatternSymbol({
1033
1199
  name: 'hour1_12',
1034
- format: function (oField, oDate, bUTC, oFormat) {
1035
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1200
+ format: function (oField, oDate) {
1201
+ var iHours = oDate.getUTCHours();
1036
1202
  var sHours;
1037
1203
  if (iHours > 12) {
1038
1204
  sHours = String(iHours - 12);
1039
- } else if (iHours == 0) {
1205
+ } else if (iHours === 0) {
1040
1206
  sHours = '12';
1041
1207
  } else {
1042
1208
  sHours = String(iHours);
@@ -1044,11 +1210,8 @@ DateFormat.prototype.oSymbols = {
1044
1210
  return sHours.padStart(oField.digits, '0');
1045
1211
  },
1046
1212
  parse: function (sValue, oPart, oFormat, oConfig) {
1047
- var bPM = oConfig.dateValue.pm;
1048
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
1049
- var iHours = parseInt(sPart);
1050
- var bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
1051
- if (iHours == 12) {
1213
+ var bPM = oConfig.dateValue.pm, sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)), iHours = parseInt(sPart), bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < 2, bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
1214
+ if (iHours === 12) {
1052
1215
  iHours = 0;
1053
1216
  bPM = bPM === undefined ? true : bPM;
1054
1217
  }
@@ -1061,19 +1224,17 @@ DateFormat.prototype.oSymbols = {
1061
1224
  pm: bPM,
1062
1225
  valid: bValid
1063
1226
  };
1064
- }
1065
- },
1066
- 'm': {
1227
+ },
1228
+ isNumeric: true
1229
+ }),
1230
+ 'm': DateFormat._createPatternSymbol({
1067
1231
  name: 'minute',
1068
- format: function (oField, oDate, bUTC, oFormat) {
1069
- var iMinutes = bUTC ? oDate.getUTCMinutes() : oDate.getMinutes();
1232
+ format: function (oField, oDate) {
1233
+ var iMinutes = oDate.getUTCMinutes();
1070
1234
  return String(iMinutes).padStart(oField.digits, '0');
1071
1235
  },
1072
1236
  parse: function (sValue, oPart, oFormat, oConfig) {
1073
- var bValid;
1074
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
1075
- var iMinutes = parseInt(sPart);
1076
- bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
1237
+ var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2)), iMinutes = parseInt(sPart), bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < 2, bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
1077
1238
  if (oConfig.strict && iMinutes > 59) {
1078
1239
  bValid = false;
1079
1240
  }
@@ -1082,19 +1243,17 @@ DateFormat.prototype.oSymbols = {
1082
1243
  minute: iMinutes,
1083
1244
  valid: bValid
1084
1245
  };
1085
- }
1086
- },
1087
- 's': {
1246
+ },
1247
+ isNumeric: true
1248
+ }),
1249
+ 's': DateFormat._createPatternSymbol({
1088
1250
  name: 'second',
1089
- format: function (oField, oDate, bUTC, oFormat) {
1090
- var iSeconds = bUTC ? oDate.getUTCSeconds() : oDate.getSeconds();
1251
+ format: function (oField, oDate) {
1252
+ var iSeconds = oDate.getUTCSeconds();
1091
1253
  return String(iSeconds).padStart(oField.digits, '0');
1092
1254
  },
1093
1255
  parse: function (sValue, oPart, oFormat, oConfig) {
1094
- var bValid;
1095
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
1096
- var iSeconds = parseInt(sPart);
1097
- bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
1256
+ var iExpectedDigits = Math.max(oPart.digits, 2), sPart = oParseHelper.findNumbers(sValue, iExpectedDigits), bPartInvalid = sPart === '' || oConfig.exactLength && sPart.length < iExpectedDigits, iSeconds = parseInt(sPart), bValid = oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat);
1098
1257
  if (oConfig.strict && iSeconds > 59) {
1099
1258
  bValid = false;
1100
1259
  }
@@ -1103,12 +1262,13 @@ DateFormat.prototype.oSymbols = {
1103
1262
  second: iSeconds,
1104
1263
  valid: bValid
1105
1264
  };
1106
- }
1107
- },
1108
- 'S': {
1265
+ },
1266
+ isNumeric: true
1267
+ }),
1268
+ 'S': DateFormat._createPatternSymbol({
1109
1269
  name: 'fractionalsecond',
1110
- format: function (oField, oDate, bUTC, oFormat) {
1111
- var iMilliseconds = bUTC ? oDate.getUTCMilliseconds() : oDate.getMilliseconds();
1270
+ format: function (oField, oDate) {
1271
+ var iMilliseconds = oDate.getUTCMilliseconds();
1112
1272
  var sMilliseconds = String(iMilliseconds);
1113
1273
  var sFractionalseconds = sMilliseconds.padStart(3, '0');
1114
1274
  sFractionalseconds = sFractionalseconds.substr(0, oField.digits);
@@ -1116,31 +1276,33 @@ DateFormat.prototype.oSymbols = {
1116
1276
  return sFractionalseconds;
1117
1277
  },
1118
1278
  parse: function (sValue, oPart, oFormat, oConfig) {
1119
- var sPart = oParseHelper.findNumbers(sValue, oPart.digits);
1120
- var iLength = sPart.length;
1279
+ var sPart = oParseHelper.findNumbers(sValue, oPart.digits), iLength = sPart.length, bPartInvalid = oConfig.exactLength && iLength < oPart.digits;
1121
1280
  sPart = sPart.substr(0, 3);
1122
1281
  sPart = sPart.padEnd(3, '0');
1123
1282
  var iMilliseconds = parseInt(sPart);
1124
1283
  return {
1125
1284
  length: iLength,
1126
- millisecond: iMilliseconds
1285
+ millisecond: iMilliseconds,
1286
+ valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat)
1127
1287
  };
1128
- }
1129
- },
1130
- 'z': {
1288
+ },
1289
+ isNumeric: true
1290
+ }),
1291
+ 'z': DateFormat._createPatternSymbol({
1131
1292
  name: 'timezoneGeneral',
1132
- format: function (oField, oDate, bUTC, oFormat) {
1293
+ format: function (oField, oDate, bUTC, oFormat, sTimezone) {
1133
1294
  if (oField.digits > 3 && oDate.getTimezoneLong && oDate.getTimezoneLong()) {
1134
1295
  return oDate.getTimezoneLong();
1135
1296
  } else if (oDate.getTimezoneShort && oDate.getTimezoneShort()) {
1136
1297
  return oDate.getTimezoneShort();
1137
1298
  }
1299
+ var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
1138
1300
  var sTimeZone = 'GMT';
1139
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1140
- var bPositiveOffset = oDate.getTimezoneOffset() > 0;
1301
+ var iTZOffset = Math.abs(iTimezoneOffset / 60);
1302
+ var bPositiveOffset = iTimezoneOffset > 0;
1141
1303
  var iHourOffset = Math.floor(iTZOffset / 60);
1142
- var iMinuteOffset = iTZOffset % 60;
1143
- if (!bUTC && iTZOffset != 0) {
1304
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1305
+ if (!bUTC && iTZOffset !== 0) {
1144
1306
  sTimeZone += bPositiveOffset ? '-' : '+';
1145
1307
  sTimeZone += String(iHourOffset).padStart(2, '0');
1146
1308
  sTimeZone += ':';
@@ -1162,7 +1324,7 @@ DateFormat.prototype.oSymbols = {
1162
1324
  iLength = 1;
1163
1325
  iTZDiff = 0;
1164
1326
  } else {
1165
- return { error: 'cannot be parsed correcly by sap.ui.core.format.DateFormat: The given timezone is not supported!' };
1327
+ return { error: 'cannot be parsed correctly by sap.ui.core.format.DateFormat: The given timezone is not supported!' };
1166
1328
  }
1167
1329
  if (sValue.charAt(0) !== 'Z') {
1168
1330
  var oParsedTZ = oParseHelper.parseTZ(sValue.substr(iLength), true);
@@ -1174,14 +1336,15 @@ DateFormat.prototype.oSymbols = {
1174
1336
  tzDiff: iTZDiff
1175
1337
  };
1176
1338
  }
1177
- },
1178
- 'Z': {
1339
+ }),
1340
+ 'Z': DateFormat._createPatternSymbol({
1179
1341
  name: 'timezoneRFC822',
1180
- format: function (oField, oDate, bUTC, oFormat) {
1181
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1182
- var bPositiveOffset = oDate.getTimezoneOffset() > 0;
1342
+ format: function (oField, oDate, bUTC, oFormat, sTimezone) {
1343
+ var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
1344
+ var iTZOffset = Math.abs(iTimezoneOffset / 60);
1345
+ var bPositiveOffset = iTimezoneOffset > 0;
1183
1346
  var iHourOffset = Math.floor(iTZOffset / 60);
1184
- var iMinuteOffset = iTZOffset % 60;
1347
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1185
1348
  var sTimeZone = '';
1186
1349
  if (!bUTC) {
1187
1350
  sTimeZone += bPositiveOffset ? '-' : '+';
@@ -1193,16 +1356,17 @@ DateFormat.prototype.oSymbols = {
1193
1356
  parse: function (sValue, oPart, oFormat, oConfig) {
1194
1357
  return oParseHelper.parseTZ(sValue, false);
1195
1358
  }
1196
- },
1197
- 'X': {
1359
+ }),
1360
+ 'X': DateFormat._createPatternSymbol({
1198
1361
  name: 'timezoneISO8601',
1199
- format: function (oField, oDate, bUTC, oFormat) {
1200
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1201
- var bPositiveOffset = oDate.getTimezoneOffset() > 0;
1362
+ format: function (oField, oDate, bUTC, oFormat, sTimezone) {
1363
+ var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
1364
+ var iTZOffset = Math.abs(iTimezoneOffset / 60);
1365
+ var bPositiveOffset = iTimezoneOffset > 0;
1202
1366
  var iHourOffset = Math.floor(iTZOffset / 60);
1203
- var iMinuteOffset = iTZOffset % 60;
1367
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1204
1368
  var sTimeZone = '';
1205
- if (!bUTC && iTZOffset != 0) {
1369
+ if (!bUTC && iTZOffset !== 0) {
1206
1370
  sTimeZone += bPositiveOffset ? '-' : '+';
1207
1371
  sTimeZone += String(iHourOffset).padStart(2, '0');
1208
1372
  if (oField.digits > 1 || iMinuteOffset > 0) {
@@ -1226,11 +1390,52 @@ DateFormat.prototype.oSymbols = {
1226
1390
  return oParseHelper.parseTZ(sValue, oPart.digits === 3 || oPart.digits === 5);
1227
1391
  }
1228
1392
  }
1229
- }
1393
+ }),
1394
+ 'V': DateFormat._createPatternSymbol({
1395
+ name: 'timezoneID',
1396
+ format: function (oField, oDate, bUTC, oFormat, sTimezone) {
1397
+ if (!bUTC && oField.digits === 2) {
1398
+ return oFormat.oLocaleData.getTimezoneTranslations()[sTimezone] || sTimezone;
1399
+ }
1400
+ return '';
1401
+ },
1402
+ parse: function (sValue, oPart, oFormat, oConfig, sTimezone) {
1403
+ var oTimezoneParsed = {
1404
+ timezone: '',
1405
+ length: 0
1406
+ };
1407
+ if (oPart.digits === 2) {
1408
+ var mTimezoneTranslations = oFormat.oLocaleData.getTimezoneTranslations();
1409
+ if (sValue === mTimezoneTranslations[sTimezone]) {
1410
+ return {
1411
+ timezone: sTimezone,
1412
+ length: sValue.length
1413
+ };
1414
+ }
1415
+ var aTimezoneTranslations = Object.values(mTimezoneTranslations);
1416
+ var oTimezoneResult = oParseHelper.findEntry(sValue, aTimezoneTranslations, oFormat.oLocaleData.sCLDRLocaleId);
1417
+ if (oTimezoneResult.index !== -1) {
1418
+ return {
1419
+ timezone: Object.keys(mTimezoneTranslations)[oTimezoneResult.index],
1420
+ length: oTimezoneResult.length
1421
+ };
1422
+ }
1423
+ var sCurrentValue = '';
1424
+ for (var i = 0; i < sValue.length; i++) {
1425
+ sCurrentValue += sValue[i];
1426
+ if (TimezoneUtil.isValidTimezone(sCurrentValue)) {
1427
+ oTimezoneParsed.timezone = sCurrentValue;
1428
+ oTimezoneParsed.length = sCurrentValue.length;
1429
+ }
1430
+ }
1431
+ }
1432
+ return oTimezoneParsed;
1433
+ }
1434
+ })
1230
1435
  };
1231
- DateFormat.prototype._format = function (oJSDate, bUTC) {
1436
+ DateFormat.prototype._format = function (oJSDate, bUTC, sTimezone) {
1232
1437
  if (this.oFormatOptions.relative) {
1233
- var sRes = this.formatRelative(oJSDate, bUTC, this.oFormatOptions.relativeRange);
1438
+ var sRes = this.formatRelative(oJSDate, bUTC, this.oFormatOptions.relativeRange, sTimezone);
1234
1439
  if (sRes) {
1235
1440
  return sRes;
1236
1441
  }
@@ -1241,10 +1446,10 @@ DateFormat.prototype._format = function (oJSDate, bUTC) {
1241
1446
  for (var i = 0; i < this.aFormatArray.length; i++) {
1242
1447
  oPart = this.aFormatArray[i];
1243
1448
  sSymbol = oPart.symbol || '';
1244
- aBuffer.push(this.oSymbols[sSymbol].format(oPart, oDate, bUTC, this));
1449
+ aBuffer.push(this.oSymbols[sSymbol].format(oPart, oDate, bUTC, this, sTimezone));
1245
1450
  }
1246
1451
  sResult = aBuffer.join('');
1247
- if (Core.getConfiguration().getOriginInfo()) {
1452
+ if (Configuration.getOriginInfo()) {
1248
1453
  sResult = new String(sResult);
1249
1454
  sResult.originInfo = {
1250
1455
  source: 'Common Locale Data Repository',
@@ -1256,10 +1461,21 @@ DateFormat.prototype._format = function (oJSDate, bUTC) {
1256
1461
  return sResult;
1257
1462
  };
1258
1463
  DateFormat.prototype.format = function (vJSDate, bUTC) {
1464
+ var sTimezone;
1465
+ if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1466
+ sTimezone = bUTC;
1467
+ bUTC = false;
1468
+ checkTimezoneParameterType(sTimezone);
1469
+ if (sTimezone && !TimezoneUtil.isValidTimezone(sTimezone)) {
1470
+ Log.error('The given timezone isn\'t valid.');
1471
+ return '';
1472
+ }
1473
+ }
1259
1474
  var sCalendarType = this.oFormatOptions.calendarType, sResult;
1260
1475
  if (bUTC === undefined) {
1261
1476
  bUTC = this.oFormatOptions.UTC;
1262
1477
  }
1478
+ sTimezone = sTimezone || Configuration.getTimezone();
1263
1479
  if (Array.isArray(vJSDate)) {
1264
1480
  if (!this.oFormatOptions.interval) {
1265
1481
  Log.error('Non-interval DateFormat can\'t format more than one date instance.');
@@ -1269,27 +1485,30 @@ DateFormat.prototype.format = function (vJSDate, bUTC) {
1269
1485
  Log.error('Interval DateFormat can only format with 2 date instances but ' + vJSDate.length + ' is given.');
1270
1486
  return '';
1271
1487
  }
1488
+ vJSDate = vJSDate.map(function (oJSDate) {
1489
+ return convertToTimezone(oJSDate, sTimezone, bUTC);
1490
+ });
1272
1491
  if (this.oFormatOptions.singleIntervalValue) {
1273
1492
  if (vJSDate[0] === null) {
1274
1493
  Log.error('First date instance which is passed to the interval DateFormat shouldn\'t be null.');
1275
1494
  return '';
1276
1495
  }
1277
1496
  if (vJSDate[1] === null) {
1278
- sResult = this._format(vJSDate[0], bUTC);
1497
+ sResult = this._format(vJSDate[0], bUTC, sTimezone);
1279
1498
  }
1280
1499
  }
1281
1500
  if (sResult === undefined) {
1282
- var bValid = vJSDate.every(function (oJSDate) {
1283
- return oJSDate && !isNaN(oJSDate.getTime());
1284
- });
1285
- if (!bValid) {
1501
+ if (!vJSDate.every(isValidDateObject)) {
1286
1502
  Log.error('At least one date instance which is passed to the interval DateFormat isn\'t valid.');
1287
1503
  return '';
1288
1504
  }
1289
1505
  sResult = this._formatInterval(vJSDate, bUTC);
1290
1506
  }
1291
1507
  } else {
1292
- if (!vJSDate || isNaN(vJSDate.getTime())) {
1508
+ if (!isValidDateObject(vJSDate)) {
1509
+ if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE && this.oFormatOptions.pattern.includes('VV')) {
1510
+ return this.oLocaleData.getTimezoneTranslations()[sTimezone] || sTimezone;
1511
+ }
1293
1512
  Log.error('The given date instance isn\'t valid.');
1294
1513
  return '';
1295
1514
  }
@@ -1297,9 +1516,10 @@ DateFormat.prototype.format = function (vJSDate, bUTC) {
1297
1516
  Log.error('Interval DateFormat expects an array with two dates for the first argument but only one date is given.');
1298
1517
  return '';
1299
1518
  }
1300
- sResult = this._format(vJSDate, bUTC);
1519
+ vJSDate = convertToTimezone(vJSDate, sTimezone, bUTC);
1520
+ sResult = this._format(vJSDate, bUTC, sTimezone);
1301
1521
  }
1302
- if (sCalendarType == CalendarType.Japanese && this.oLocale.getLanguage() === 'ja') {
1522
+ if (sCalendarType === CalendarType.Japanese && this.oLocale.getLanguage() === 'ja') {
1303
1523
  sResult = sResult.replace(/(^|[^\d])1年/g, '$1元年');
1304
1524
  }
1305
1525
  return sResult;
@@ -1317,7 +1537,7 @@ DateFormat.prototype._formatInterval = function (aJSDates, bUTC) {
1317
1537
  var oDiffField = this._getGreatestDiffField([
1318
1538
  oFromDate,
1319
1539
  oToDate
1320
- ], bUTC);
1540
+ ]);
1321
1541
  if (!oDiffField) {
1322
1542
  return this._format(aJSDates[0], bUTC);
1323
1543
  }
@@ -1350,10 +1570,10 @@ var mFieldToGroup = {
1350
1570
  Minutes: 'Minute',
1351
1571
  Seconds: 'Second'
1352
1572
  };
1353
- DateFormat.prototype._getGreatestDiffField = function (aDates, bUTC) {
1573
+ DateFormat.prototype._getGreatestDiffField = function (aDates) {
1354
1574
  var bDiffFound = false, mDiff = {};
1355
1575
  this.aIntervalCompareFields.forEach(function (sField) {
1356
- var sGetterPrefix = 'get' + (bUTC ? 'UTC' : ''), sMethodName = sGetterPrefix + sField, sFieldGroup = mFieldToGroup[sField], vFromValue = aDates[0][sMethodName].apply(aDates[0]), vToValue = aDates[1][sMethodName].apply(aDates[1]);
1576
+ var sGetterPrefix = 'getUTC', sMethodName = sGetterPrefix + sField, sFieldGroup = mFieldToGroup[sField], vFromValue = aDates[0][sMethodName].apply(aDates[0]), vToValue = aDates[1][sMethodName].apply(aDates[1]);
1357
1577
  if (!deepEqual(vFromValue, vToValue)) {
1358
1578
  bDiffFound = true;
1359
1579
  mDiff[sFieldGroup] = true;
@@ -1364,19 +1584,32 @@ DateFormat.prototype._getGreatestDiffField = function (aDates, bUTC) {
1364
1584
  }
1365
1585
  return null;
1366
1586
  };
1367
- DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1368
- var iIndex = 0, oPart, sSubValue, oResult;
1369
- var oDateValue = { valid: true };
1370
- var oParseConf = {
1371
- formatArray: aFormatArray,
1372
- dateValue: oDateValue,
1373
- strict: bStrict
1374
- };
1587
+ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict, sTimezone) {
1588
+ var sFlexibleDayPeriod, oNextPart, oPart, bPM, oPrevPart, oResult, sSubValue, oDateValue = {
1589
+ valid: true,
1590
+ lastTimezonePatternSymbol: ''
1591
+ }, iIndex = 0, oParseConf = {
1592
+ formatArray: aFormatArray,
1593
+ dateValue: oDateValue,
1594
+ strict: bStrict
1595
+ }, that = this;
1596
+ function getSymbol(oPart0) {
1597
+ return that.oSymbols[oPart0.symbol || ''];
1598
+ }
1599
+ function isNumeric(oPart0) {
1600
+ return !!oPart0 && getSymbol(oPart0).isNumeric(oPart0.digits);
1601
+ }
1375
1602
  for (var i = 0; i < aFormatArray.length; i++) {
1376
1603
  sSubValue = sValue.substr(iIndex);
1377
1604
  oPart = aFormatArray[i];
1605
+ oPrevPart = aFormatArray[i - 1];
1606
+ oNextPart = aFormatArray[i + 1];
1378
1607
  oParseConf.index = i;
1379
- oResult = this.oSymbols[oPart.symbol || ''].parse(sSubValue, oPart, this, oParseConf) || {};
1608
+ oParseConf.exactLength = isNumeric(oPart) && (isNumeric(oPrevPart) || isNumeric(oNextPart));
1609
+ oResult = getSymbol(oPart).parse(sSubValue, oPart, this, oParseConf, sTimezone) || {};
1610
+ if (oResult.tzDiff !== undefined || oResult.timezone) {
1611
+ oResult.lastTimezonePatternSymbol = oPart.symbol;
1612
+ }
1380
1613
  oDateValue = extend(oDateValue, oResult);
1381
1614
  if (oResult.valid === false) {
1382
1615
  break;
@@ -1384,7 +1617,12 @@ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1384
1617
  iIndex += oResult.length || 0;
1385
1618
  }
1386
1619
  oDateValue.index = iIndex;
1387
- if (oDateValue.pm) {
1620
+ bPM = oDateValue.pm;
1621
+ if (oDateValue.flexDayPeriod && oDateValue.hour * 60 + (oDateValue.minute || 0) < 720) {
1622
+ sFlexibleDayPeriod = this.oLocaleData.getFlexibleDayPeriodOfTime(oDateValue.hour + 12, oDateValue.minute || 0);
1623
+ bPM = oDateValue.flexDayPeriod === sFlexibleDayPeriod;
1624
+ }
1625
+ if (bPM) {
1388
1626
  oDateValue.hour += 12;
1389
1627
  }
1390
1628
  if (oDateValue.dayNumberOfWeek === undefined && oDateValue.dayOfWeek !== undefined) {
@@ -1396,7 +1634,7 @@ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1396
1634
  }
1397
1635
  return oDateValue;
1398
1636
  };
1399
- DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bStrict) {
1637
+ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bStrict, sTimezone) {
1400
1638
  var aDateValues, iRepeat, oDateValue;
1401
1639
  this.intervalPatterns.some(function (sPattern) {
1402
1640
  var aFormatArray = this.parseCldrDatePattern(sPattern);
@@ -1408,7 +1646,7 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1408
1646
  }
1409
1647
  }
1410
1648
  if (iRepeat === undefined) {
1411
- oDateValue = this._parse(sValue, aFormatArray, bUTC, bStrict);
1649
+ oDateValue = this._parse(sValue, aFormatArray, bUTC, bStrict, sTimezone);
1412
1650
  if (oDateValue.index === 0 || oDateValue.index < sValue.length) {
1413
1651
  oDateValue.valid = false;
1414
1652
  }
@@ -1422,13 +1660,13 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1422
1660
  return true;
1423
1661
  } else {
1424
1662
  aDateValues = [];
1425
- oDateValue = this._parse(sValue, aFormatArray.slice(0, iRepeat), bUTC, bStrict);
1663
+ oDateValue = this._parse(sValue, aFormatArray.slice(0, iRepeat), bUTC, bStrict, sTimezone);
1426
1664
  if (oDateValue.valid === false) {
1427
1665
  return;
1428
1666
  }
1429
1667
  aDateValues.push(oDateValue);
1430
1668
  var iLength = oDateValue.index;
1431
- oDateValue = this._parse(sValue.substring(iLength), aFormatArray.slice(iRepeat), bUTC, bStrict);
1669
+ oDateValue = this._parse(sValue.substring(iLength), aFormatArray.slice(iRepeat), bUTC, bStrict, sTimezone);
1432
1670
  if (oDateValue.index === 0 || oDateValue.index + iLength < sValue.length) {
1433
1671
  oDateValue.valid = false;
1434
1672
  }
@@ -1441,65 +1679,62 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1441
1679
  }.bind(this));
1442
1680
  return aDateValues;
1443
1681
  };
1444
- var fnCreateDate = function (oDateValue, sCalendarType, bUTC, bStrict) {
1682
+ function getCalendarWeekParameter(oFormatOptions) {
1683
+ if (oFormatOptions.calendarWeekNumbering) {
1684
+ return oFormatOptions.calendarWeekNumbering;
1685
+ } else if (oFormatOptions.firstDayOfWeek !== undefined && oFormatOptions.minimalDaysInFirstWeek !== undefined) {
1686
+ return {
1687
+ firstDayOfWeek: oFormatOptions.firstDayOfWeek,
1688
+ minimalDaysInFirstWeek: oFormatOptions.minimalDaysInFirstWeek
1689
+ };
1690
+ }
1691
+ return undefined;
1692
+ }
1693
+ var convertToTimezone = function (oJSDate, sTimezone, bUTC) {
1694
+ if (!bUTC && isValidDateObject(oJSDate)) {
1695
+ return TimezoneUtil.convertToTimezone(oJSDate, sTimezone);
1696
+ }
1697
+ return oJSDate;
1698
+ };
1699
+ var fnCreateDate = function (oDateValue, sCalendarType, bUTC, bStrict, sTimezone, oFormatOptions, oLocale) {
1700
+ if (!oDateValue.valid) {
1701
+ return null;
1702
+ }
1445
1703
  var oDate, iYear = typeof oDateValue.year === 'number' ? oDateValue.year : 1970;
1446
- if (oDateValue.valid) {
1447
- if (bUTC || oDateValue.tzDiff !== undefined) {
1448
- oDate = UniversalDate.getInstance(new Date(0), sCalendarType);
1449
- oDate.setUTCEra(oDateValue.era || UniversalDate.getCurrentEra(sCalendarType));
1450
- oDate.setUTCFullYear(iYear);
1451
- oDate.setUTCMonth(oDateValue.month || 0);
1452
- oDate.setUTCDate(oDateValue.day || 1);
1453
- oDate.setUTCHours(oDateValue.hour || 0);
1454
- oDate.setUTCMinutes(oDateValue.minute || 0);
1455
- oDate.setUTCSeconds(oDateValue.second || 0);
1456
- oDate.setUTCMilliseconds(oDateValue.millisecond || 0);
1457
- if (bStrict && (oDateValue.day || 1) !== oDate.getUTCDate()) {
1458
- oDateValue.valid = false;
1459
- oDate = undefined;
1460
- } else {
1461
- if (oDateValue.tzDiff) {
1462
- oDate.setUTCMinutes((oDateValue.minute || 0) + oDateValue.tzDiff);
1463
- }
1464
- if (oDateValue.week !== undefined && (oDateValue.month === undefined || oDateValue.day === undefined)) {
1465
- oDate.setUTCWeek({
1466
- year: oDateValue.weekYear || oDateValue.year,
1467
- week: oDateValue.week
1468
- });
1469
- if (oDateValue.dayNumberOfWeek !== undefined) {
1470
- oDate.setUTCDate(oDate.getUTCDate() + oDateValue.dayNumberOfWeek - 1);
1471
- }
1472
- }
1473
- }
1474
- } else {
1475
- oDate = UniversalDate.getInstance(new Date(1970, 0, 1, 0, 0, 0), sCalendarType);
1476
- oDate.setEra(oDateValue.era || UniversalDate.getCurrentEra(sCalendarType));
1477
- oDate.setFullYear(iYear);
1478
- oDate.setMonth(oDateValue.month || 0);
1479
- oDate.setDate(oDateValue.day || 1);
1480
- oDate.setHours(oDateValue.hour || 0);
1481
- oDate.setMinutes(oDateValue.minute || 0);
1482
- oDate.setSeconds(oDateValue.second || 0);
1483
- oDate.setMilliseconds(oDateValue.millisecond || 0);
1484
- if (bStrict && (oDateValue.day || 1) !== oDate.getDate()) {
1485
- oDateValue.valid = false;
1486
- oDate = undefined;
1487
- } else if (oDateValue.week !== undefined && (oDateValue.month === undefined || oDateValue.day === undefined)) {
1488
- oDate.setWeek({
1489
- year: oDateValue.weekYear || oDateValue.year,
1490
- week: oDateValue.week
1491
- });
1492
- if (oDateValue.dayNumberOfWeek !== undefined) {
1493
- oDate.setDate(oDate.getDate() + oDateValue.dayNumberOfWeek - 1);
1494
- }
1495
- }
1704
+ oDate = UniversalDate.getInstance(new Date(0), sCalendarType);
1705
+ oDate.setUTCEra(oDateValue.era || UniversalDate.getCurrentEra(sCalendarType));
1706
+ oDate.setUTCFullYear(iYear);
1707
+ oDate.setUTCMonth(oDateValue.month || 0);
1708
+ oDate.setUTCDate(oDateValue.day || 1);
1709
+ oDate.setUTCHours(oDateValue.hour || 0);
1710
+ oDate.setUTCMinutes(oDateValue.minute || 0);
1711
+ oDate.setUTCSeconds(oDateValue.second || 0);
1712
+ oDate.setUTCMilliseconds(oDateValue.millisecond || 0);
1713
+ if (bStrict && (oDateValue.day || 1) !== oDate.getUTCDate()) {
1714
+ return null;
1715
+ }
1716
+ if (oDateValue.week !== undefined && (oDateValue.month === undefined || oDateValue.day === undefined)) {
1717
+ oDate.setUTCWeek({
1718
+ year: oDateValue.weekYear || oDateValue.year,
1719
+ week: oDateValue.week
1720
+ }, oLocale, getCalendarWeekParameter(oFormatOptions));
1721
+ if (oDateValue.dayNumberOfWeek !== undefined) {
1722
+ oDate.setUTCDate(oDate.getUTCDate() + oDateValue.dayNumberOfWeek - 1);
1496
1723
  }
1497
- if (oDateValue.valid) {
1498
- oDate = oDate.getJSDate();
1499
- return oDate;
1724
+ }
1725
+ oDate = oDate.getJSDate();
1726
+ if (!bUTC && (oDateValue.lastTimezonePatternSymbol === 'V' && oDateValue.timezone || oDateValue.tzDiff === undefined)) {
1727
+ if (oDateValue.timezone) {
1728
+ sTimezone = oDateValue.timezone;
1729
+ }
1730
+ if (sTimezone) {
1731
+ oDateValue.tzDiff = TimezoneUtil.calculateOffset(oDate, sTimezone);
1500
1732
  }
1501
1733
  }
1502
- return null;
1734
+ if (oDateValue.tzDiff) {
1735
+ oDate.setUTCSeconds(oDate.getUTCSeconds() + oDateValue.tzDiff);
1736
+ }
1737
+ return oDate;
1503
1738
  };
1504
1739
  function mergeWithoutOverwrite(object1, object2) {
1505
1740
  if (object1 === object2) {
@@ -1522,17 +1757,37 @@ function isValidDateRange(oStartDate, oEndDate) {
1522
1757
  }
1523
1758
  return true;
1524
1759
  }
1760
+ function isValidDateObject(oDate) {
1761
+ return oDate && typeof oDate.getTime === 'function' && !isNaN(oDate.getTime());
1762
+ }
1525
1763
  DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
1764
+ var bShowDate = this.oFormatOptions.showDate === undefined || this.oFormatOptions.showDate;
1765
+ var bShowTime = this.oFormatOptions.showTime === undefined || this.oFormatOptions.showTime;
1766
+ if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE && (bShowDate && !bShowTime || !bShowDate && bShowTime)) {
1767
+ throw new TypeError('The input can only be parsed back to date if both date and time are supplied.');
1768
+ }
1769
+ var sTimezone;
1770
+ if (bUTC === undefined && this.type !== mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1771
+ bUTC = this.oFormatOptions.UTC;
1772
+ }
1773
+ var bUTCInputParameter = bUTC;
1774
+ if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1775
+ sTimezone = bUTC;
1776
+ bUTC = false;
1777
+ checkTimezoneParameterType(sTimezone);
1778
+ if (sTimezone && !TimezoneUtil.isValidTimezone(sTimezone)) {
1779
+ Log.error('The given timezone isn\'t valid.');
1780
+ return null;
1781
+ }
1782
+ }
1526
1783
  sValue = sValue == null ? '' : String(sValue).trim();
1527
1784
  var oDateValue;
1528
1785
  var sCalendarType = this.oFormatOptions.calendarType;
1529
- if (bUTC === undefined) {
1530
- bUTC = this.oFormatOptions.UTC;
1531
- }
1786
+ sTimezone = sTimezone || Configuration.getTimezone();
1532
1787
  if (bStrict === undefined) {
1533
1788
  bStrict = this.oFormatOptions.strictParsing;
1534
1789
  }
1535
- if (sCalendarType == CalendarType.Japanese && this.oLocale.getLanguage() === 'ja') {
1790
+ if (sCalendarType === CalendarType.Japanese && this.oLocale.getLanguage() === 'ja') {
1536
1791
  sValue = sValue.replace(/元年/g, '1年');
1537
1792
  }
1538
1793
  if (!this.oFormatOptions.interval) {
@@ -1540,22 +1795,40 @@ DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
1540
1795
  if (oJSDate) {
1541
1796
  return oJSDate;
1542
1797
  }
1543
- oDateValue = this._parse(sValue, this.aFormatArray, bUTC, bStrict);
1798
+ oDateValue = this._parse(sValue, this.aFormatArray, bUTC, bStrict, sTimezone);
1544
1799
  if (oDateValue.index === 0 || oDateValue.index < sValue.length) {
1545
1800
  oDateValue.valid = false;
1546
1801
  }
1547
- oJSDate = fnCreateDate(oDateValue, sCalendarType, bUTC, bStrict);
1802
+ oJSDate = fnCreateDate(oDateValue, sCalendarType, bUTC, bStrict, sTimezone, this.oFormatOptions, this.oLocale);
1548
1803
  if (oJSDate) {
1804
+ if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1805
+ var bShowTimezone = this.oFormatOptions.showTimezone === undefined || this.oFormatOptions.showTimezone;
1806
+ if (!bShowTimezone && bShowDate && bShowTime) {
1807
+ return [
1808
+ oJSDate,
1809
+ undefined
1810
+ ];
1811
+ } else if (bShowTimezone && !bShowDate && !bShowTime) {
1812
+ return [
1813
+ undefined,
1814
+ oDateValue.timezone
1815
+ ];
1816
+ }
1817
+ return [
1818
+ oJSDate,
1819
+ oDateValue.timezone || undefined
1820
+ ];
1821
+ }
1549
1822
  return oJSDate;
1550
1823
  }
1551
1824
  } else {
1552
- var aDateValues = this._parseInterval(sValue, sCalendarType, bUTC, bStrict);
1825
+ var aDateValues = this._parseInterval(sValue, sCalendarType, bUTC, bStrict, sTimezone);
1553
1826
  var oJSDate1, oJSDate2;
1554
- if (aDateValues && aDateValues.length == 2) {
1827
+ if (aDateValues && aDateValues.length === 2) {
1555
1828
  var oDateValue1 = mergeWithoutOverwrite(aDateValues[0], aDateValues[1]);
1556
1829
  var oDateValue2 = mergeWithoutOverwrite(aDateValues[1], aDateValues[0]);
1557
- oJSDate1 = fnCreateDate(oDateValue1, sCalendarType, bUTC, bStrict);
1558
- oJSDate2 = fnCreateDate(oDateValue2, sCalendarType, bUTC, bStrict);
1830
+ oJSDate1 = fnCreateDate(oDateValue1, sCalendarType, bUTC, bStrict, sTimezone, this.oFormatOptions, this.oLocale);
1831
+ oJSDate2 = fnCreateDate(oDateValue2, sCalendarType, bUTC, bStrict, sTimezone, this.oFormatOptions, this.oLocale);
1559
1832
  if (oJSDate1 && oJSDate2) {
1560
1833
  if (this.oFormatOptions.singleIntervalValue && oJSDate1.getTime() === oJSDate2.getTime()) {
1561
1834
  return [
@@ -1578,11 +1851,14 @@ DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
1578
1851
  }
1579
1852
  }
1580
1853
  }
1581
- if (!this.bIsFallback) {
1854
+ if (this.aFallbackFormats) {
1582
1855
  var vDate;
1583
1856
  this.aFallbackFormats.every(function (oFallbackFormat) {
1584
- vDate = oFallbackFormat.parse(sValue, bUTC, bStrict);
1857
+ vDate = oFallbackFormat.parse(sValue, bUTCInputParameter, bStrict);
1585
1858
  if (Array.isArray(vDate)) {
1859
+ if (oFallbackFormat.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1860
+ return false;
1861
+ }
1586
1862
  return !(vDate[0] && vDate[1]);
1587
1863
  } else {
1588
1864
  return !vDate;
@@ -1607,20 +1883,20 @@ DateFormat.prototype.parseCldrDatePattern = function (sPattern) {
1607
1883
  for (i = 0; i < sPattern.length; i++) {
1608
1884
  var sCurChar = sPattern.charAt(i), sNextChar, sPrevChar, sPrevPrevChar;
1609
1885
  if (bQuoted) {
1610
- if (sCurChar == '\'') {
1886
+ if (sCurChar === '\'') {
1611
1887
  sPrevChar = sPattern.charAt(i - 1);
1612
1888
  sPrevPrevChar = sPattern.charAt(i - 2);
1613
1889
  sNextChar = sPattern.charAt(i + 1);
1614
- if (sPrevChar == '\'' && sPrevPrevChar != '\'') {
1890
+ if (sPrevChar === '\'' && sPrevPrevChar !== '\'') {
1615
1891
  bQuoted = false;
1616
- } else if (sNextChar == '\'') {
1892
+ } else if (sNextChar === '\'') {
1617
1893
  i += 1;
1618
1894
  } else {
1619
1895
  bQuoted = false;
1620
1896
  continue;
1621
1897
  }
1622
1898
  }
1623
- if (sState == 'text') {
1899
+ if (sState === 'text') {
1624
1900
  oCurrentObject.value += sCurChar;
1625
1901
  } else {
1626
1902
  oCurrentObject = {
@@ -1631,11 +1907,11 @@ DateFormat.prototype.parseCldrDatePattern = function (sPattern) {
1631
1907
  sState = 'text';
1632
1908
  }
1633
1909
  } else {
1634
- if (sCurChar == '\'') {
1910
+ if (sCurChar === '\'') {
1635
1911
  bQuoted = true;
1636
1912
  } else if (this.oSymbols[sCurChar]) {
1637
1913
  sNewState = this.oSymbols[sCurChar].name;
1638
- if (sState == sNewState) {
1914
+ if (sState === sNewState) {
1639
1915
  oCurrentObject.digits++;
1640
1916
  } else {
1641
1917
  oCurrentObject = {
@@ -1655,7 +1931,7 @@ DateFormat.prototype.parseCldrDatePattern = function (sPattern) {
1655
1931
  }
1656
1932
  }
1657
1933
  } else {
1658
- if (sState == 'text') {
1934
+ if (sState === 'text') {
1659
1935
  oCurrentObject.value += sCurChar;
1660
1936
  } else {
1661
1937
  oCurrentObject = {
@@ -1691,70 +1967,88 @@ DateFormat.prototype.parseRelative = function (sValue, bUTC) {
1691
1967
  }
1692
1968
  }
1693
1969
  function computeRelativeDate(iDiff, sScale) {
1694
- var iToday, oToday = new Date(), oJSDate;
1970
+ var oResult = UI5Date.getInstance();
1695
1971
  if (bUTC) {
1696
- iToday = oToday.getTime();
1697
- } else {
1698
- iToday = Date.UTC(oToday.getFullYear(), oToday.getMonth(), oToday.getDate(), oToday.getHours(), oToday.getMinutes(), oToday.getSeconds(), oToday.getMilliseconds());
1699
- }
1700
- oJSDate = new Date(iToday);
1701
- switch (sScale) {
1702
- case 'second':
1703
- oJSDate.setUTCSeconds(oJSDate.getUTCSeconds() + iDiff);
1704
- break;
1705
- case 'minute':
1706
- oJSDate.setUTCMinutes(oJSDate.getUTCMinutes() + iDiff);
1707
- break;
1708
- case 'hour':
1709
- oJSDate.setUTCHours(oJSDate.getUTCHours() + iDiff);
1710
- break;
1711
- case 'day':
1712
- oJSDate.setUTCDate(oJSDate.getUTCDate() + iDiff);
1713
- break;
1714
- case 'week':
1715
- oJSDate.setUTCDate(oJSDate.getUTCDate() + iDiff * 7);
1716
- break;
1717
- case 'month':
1718
- oJSDate.setUTCMonth(oJSDate.getUTCMonth() + iDiff);
1719
- break;
1720
- case 'quarter':
1721
- oJSDate.setUTCMonth(oJSDate.getUTCMonth() + iDiff * 3);
1722
- break;
1723
- case 'year':
1724
- oJSDate.setUTCFullYear(oJSDate.getUTCFullYear() + iDiff);
1725
- break;
1726
- }
1727
- if (bUTC) {
1728
- return oJSDate;
1972
+ oResult.setUTCFullYear(oResult.getFullYear(), oResult.getMonth(), oResult.getDate());
1973
+ oResult.setUTCHours(oResult.getHours(), oResult.getMinutes(), oResult.getSeconds(), oResult.getMilliseconds());
1974
+ switch (sScale) {
1975
+ case 'second':
1976
+ oResult.setUTCSeconds(oResult.getUTCSeconds() + iDiff);
1977
+ break;
1978
+ case 'minute':
1979
+ oResult.setUTCMinutes(oResult.getUTCMinutes() + iDiff);
1980
+ break;
1981
+ case 'hour':
1982
+ oResult.setUTCHours(oResult.getUTCHours() + iDiff);
1983
+ break;
1984
+ case 'day':
1985
+ oResult.setUTCDate(oResult.getUTCDate() + iDiff);
1986
+ break;
1987
+ case 'week':
1988
+ oResult.setUTCDate(oResult.getUTCDate() + iDiff * 7);
1989
+ break;
1990
+ case 'month':
1991
+ oResult.setUTCMonth(oResult.getUTCMonth() + iDiff);
1992
+ break;
1993
+ case 'quarter':
1994
+ oResult.setUTCMonth(oResult.getUTCMonth() + iDiff * 3);
1995
+ break;
1996
+ case 'year':
1997
+ oResult.setUTCFullYear(oResult.getUTCFullYear() + iDiff);
1998
+ break;
1999
+ }
1729
2000
  } else {
1730
- return new Date(oJSDate.getUTCFullYear(), oJSDate.getUTCMonth(), oJSDate.getUTCDate(), oJSDate.getUTCHours(), oJSDate.getUTCMinutes(), oJSDate.getUTCSeconds(), oJSDate.getUTCMilliseconds());
2001
+ switch (sScale) {
2002
+ case 'second':
2003
+ oResult.setSeconds(oResult.getSeconds() + iDiff);
2004
+ break;
2005
+ case 'minute':
2006
+ oResult.setMinutes(oResult.getMinutes() + iDiff);
2007
+ break;
2008
+ case 'hour':
2009
+ oResult.setHours(oResult.getHours() + iDiff);
2010
+ break;
2011
+ case 'day':
2012
+ oResult.setDate(oResult.getDate() + iDiff);
2013
+ break;
2014
+ case 'week':
2015
+ oResult.setDate(oResult.getDate() + iDiff * 7);
2016
+ break;
2017
+ case 'month':
2018
+ oResult.setMonth(oResult.getMonth() + iDiff);
2019
+ break;
2020
+ case 'quarter':
2021
+ oResult.setMonth(oResult.getMonth() + iDiff * 3);
2022
+ break;
2023
+ case 'year':
2024
+ oResult.setFullYear(oResult.getFullYear() + iDiff);
2025
+ break;
2026
+ }
1731
2027
  }
2028
+ return oResult;
1732
2029
  }
1733
2030
  };
1734
- DateFormat.prototype.formatRelative = function (oJSDate, bUTC, aRange) {
1735
- var oToday = new Date(), oDateUTC, sScale = this.oFormatOptions.relativeScale || 'day', iDiff, sPattern, iDiffSeconds;
2031
+ DateFormat.prototype.formatRelative = function (oJSDate, bUTC, aRange, sTimezone) {
2032
+ var oDateUTC, iDiff, iDiffSeconds, sPattern, oToday = convertToTimezone(new Date(), sTimezone), sScale = this.oFormatOptions.relativeScale || 'day';
1736
2033
  iDiffSeconds = (oJSDate.getTime() - oToday.getTime()) / 1000;
1737
- if (this.oFormatOptions.relativeScale == 'auto') {
2034
+ if (this.oFormatOptions.relativeScale === 'auto') {
1738
2035
  sScale = this._getScale(iDiffSeconds, this.aRelativeScales);
2036
+ sScale = fixScaleForMonths(oJSDate, oToday, sScale, iDiffSeconds);
1739
2037
  }
1740
2038
  if (!aRange) {
1741
2039
  aRange = this._mRanges[sScale];
1742
2040
  }
1743
- if (sScale == 'year' || sScale == 'month' || sScale == 'day') {
1744
- oToday = new Date(Date.UTC(oToday.getFullYear(), oToday.getMonth(), oToday.getDate()));
2041
+ if (sScale === 'year' || sScale === 'month' || sScale === 'day') {
2042
+ oToday = new Date(Date.UTC(oToday.getUTCFullYear(), oToday.getUTCMonth(), oToday.getUTCDate()));
1745
2043
  oDateUTC = new Date(0);
1746
- if (bUTC) {
1747
- oDateUTC.setUTCFullYear(oJSDate.getUTCFullYear(), oJSDate.getUTCMonth(), oJSDate.getUTCDate());
1748
- } else {
1749
- oDateUTC.setUTCFullYear(oJSDate.getFullYear(), oJSDate.getMonth(), oJSDate.getDate());
1750
- }
2044
+ oDateUTC.setUTCFullYear(oJSDate.getUTCFullYear(), oJSDate.getUTCMonth(), oJSDate.getUTCDate());
1751
2045
  oJSDate = oDateUTC;
1752
2046
  }
1753
2047
  iDiff = this._getDifference(sScale, [
1754
2048
  oToday,
1755
2049
  oJSDate
1756
2050
  ]);
1757
- if (this.oFormatOptions.relativeScale != 'auto' && (iDiff < aRange[0] || iDiff > aRange[1])) {
2051
+ if (this.oFormatOptions.relativeScale !== 'auto' && (iDiff < aRange[0] || iDiff > aRange[1])) {
1758
2052
  return null;
1759
2053
  }
1760
2054
  sPattern = this.oLocaleData.getRelativePattern(sScale, iDiff, iDiffSeconds > 0, this.oFormatOptions.relativeStyle);
@@ -1815,8 +2109,23 @@ DateFormat.prototype._getScale = function (iDiffSeconds, aScales) {
1815
2109
  }
1816
2110
  return sScale;
1817
2111
  };
2112
+ function fixScaleForMonths(oJSDate, oToday, sScale, iDiffSeconds) {
2113
+ var iMonthDiff = Math.abs(oJSDate.getUTCMonth() - oToday.getUTCMonth());
2114
+ if (sScale === 'week' && iMonthDiff === 2) {
2115
+ return 'month';
2116
+ } else if (sScale === 'week' && iMonthDiff === 1) {
2117
+ if (oJSDate.getUTCDate() === oToday.getUTCDate() || iDiffSeconds < 0 && oJSDate.getUTCDate() < oToday.getUTCDate() || iDiffSeconds > 0 && oJSDate.getUTCDate() > oToday.getUTCDate()) {
2118
+ return 'month';
2119
+ }
2120
+ } else if (sScale === 'month' && iMonthDiff === 1) {
2121
+ if (iDiffSeconds > 0 && oJSDate.getUTCDate() < oToday.getUTCDate() || iDiffSeconds < 0 && oJSDate.getUTCDate() > oToday.getUTCDate()) {
2122
+ return 'week';
2123
+ }
2124
+ }
2125
+ return sScale;
2126
+ }
1818
2127
  function cutDateFields(oDate, iStartIndex) {
1819
- var aFields = [
2128
+ var sMethodName, aFields = [
1820
2129
  'FullYear',
1821
2130
  'Month',
1822
2131
  'Date',
@@ -1824,24 +2133,23 @@ function cutDateFields(oDate, iStartIndex) {
1824
2133
  'Minutes',
1825
2134
  'Seconds',
1826
2135
  'Milliseconds'
1827
- ], sMethodName;
1828
- var oDateCopy = new Date(oDate.getTime());
2136
+ ], oDateCopy = new Date(oDate.getTime());
1829
2137
  for (var i = iStartIndex; i < aFields.length; i++) {
1830
- sMethodName = 'set' + aFields[iStartIndex];
2138
+ sMethodName = 'setUTC' + aFields[iStartIndex];
1831
2139
  oDateCopy[sMethodName].apply(oDateCopy, [0]);
1832
2140
  }
1833
2141
  return oDateCopy;
1834
2142
  }
1835
2143
  var mRelativeDiffs = {
1836
2144
  year: function (oFromDate, oToDate) {
1837
- return oToDate.getFullYear() - oFromDate.getFullYear();
2145
+ return oToDate.getUTCFullYear() - oFromDate.getUTCFullYear();
1838
2146
  },
1839
2147
  month: function (oFromDate, oToDate) {
1840
- return oToDate.getMonth() - oFromDate.getMonth() + this.year(oFromDate, oToDate) * 12;
2148
+ return oToDate.getUTCMonth() - oFromDate.getUTCMonth() + this.year(oFromDate, oToDate) * 12;
1841
2149
  },
1842
2150
  week: function (oFromDate, oToDate, oFormat) {
1843
- var iFromDay = oFormat._adaptDayOfWeek(oFromDate.getDay());
1844
- var iToDay = oFormat._adaptDayOfWeek(oToDate.getDay());
2151
+ var iFromDay = oFormat._adaptDayOfWeek(oFromDate.getUTCDay());
2152
+ var iToDay = oFormat._adaptDayOfWeek(oToDate.getUTCDay());
1845
2153
  oFromDate = cutDateFields(oFromDate, 3);
1846
2154
  oToDate = cutDateFields(oToDate, 3);
1847
2155
  return (oToDate.getTime() - oFromDate.getTime() - (iToDay - iFromDay) * oFormat._mScales.day * 1000) / (oFormat._mScales.week * 1000);
@@ -1868,7 +2176,12 @@ var mRelativeDiffs = {
1868
2176
  }
1869
2177
  };
1870
2178
  DateFormat.prototype._adaptDayOfWeek = function (iDayOfWeek) {
1871
- var iFirstDayOfWeek = LocaleData.getInstance(Core.getConfiguration().getFormatSettings().getFormatLocale()).getFirstDayOfWeek();
2179
+ var vCalendarWeekParameter = getCalendarWeekParameter(this.oFormatOptions), iFirstDayOfWeek;
2180
+ if (typeof vCalendarWeekParameter === 'object') {
2181
+ iFirstDayOfWeek = vCalendarWeekParameter.firstDayOfWeek;
2182
+ } else {
2183
+ iFirstDayOfWeek = CalendarUtils.getWeekConfigurationValues(vCalendarWeekParameter, this.oLocale).firstDayOfWeek;
2184
+ }
1872
2185
  var iDayNumberOfWeek = iDayOfWeek - (iFirstDayOfWeek - 1);
1873
2186
  if (iDayNumberOfWeek <= 0) {
1874
2187
  iDayNumberOfWeek += 7;