@ui5/webcomponents-localization 0.0.0-dc3ccac50 → 0.0.0-dcd8e5389

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 (191) hide show
  1. package/.eslintignore +1 -1
  2. package/.npsrc.json +3 -0
  3. package/CHANGELOG.md +369 -0
  4. package/README.md +5 -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 +2816 -5906
  61. package/dist/generated/assets/cldr/ar_EG.json +2816 -5906
  62. package/dist/generated/assets/cldr/ar_SA.json +2815 -5906
  63. package/dist/generated/assets/cldr/bg.json +2733 -4979
  64. package/dist/generated/assets/cldr/ca.json +2680 -4996
  65. package/dist/generated/assets/cldr/cs.json +2716 -5498
  66. package/dist/generated/assets/cldr/cy.json +2797 -5884
  67. package/dist/generated/assets/cldr/da.json +2597 -4888
  68. package/dist/generated/assets/cldr/de.json +2614 -4916
  69. package/dist/generated/assets/cldr/de_AT.json +2614 -4917
  70. package/dist/generated/assets/cldr/de_CH.json +2614 -4915
  71. package/dist/generated/assets/cldr/el.json +2595 -4883
  72. package/dist/generated/assets/cldr/el_CY.json +2595 -4883
  73. package/dist/generated/assets/cldr/en.json +2583 -4971
  74. package/dist/generated/assets/cldr/en_AU.json +2592 -4962
  75. package/dist/generated/assets/cldr/en_GB.json +2584 -4971
  76. package/dist/generated/assets/cldr/en_HK.json +2593 -4977
  77. package/dist/generated/assets/cldr/en_IE.json +2584 -4971
  78. package/dist/generated/assets/cldr/en_IN.json +2588 -4972
  79. package/dist/generated/assets/cldr/en_NZ.json +2584 -4971
  80. package/dist/generated/assets/cldr/en_PG.json +2584 -4972
  81. package/dist/generated/assets/cldr/en_SG.json +2588 -4973
  82. package/dist/generated/assets/cldr/en_ZA.json +2584 -4972
  83. package/dist/generated/assets/cldr/es.json +2640 -4912
  84. package/dist/generated/assets/cldr/es_AR.json +2645 -4914
  85. package/dist/generated/assets/cldr/es_BO.json +2645 -4913
  86. package/dist/generated/assets/cldr/es_CL.json +2645 -4914
  87. package/dist/generated/assets/cldr/es_CO.json +2644 -4913
  88. package/dist/generated/assets/cldr/es_MX.json +2645 -4915
  89. package/dist/generated/assets/cldr/es_PE.json +2645 -4913
  90. package/dist/generated/assets/cldr/es_UY.json +2645 -4915
  91. package/dist/generated/assets/cldr/es_VE.json +2645 -4914
  92. package/dist/generated/assets/cldr/et.json +2599 -4967
  93. package/dist/generated/assets/cldr/fa.json +2618 -4883
  94. package/dist/generated/assets/cldr/fi.json +2726 -5008
  95. package/dist/generated/assets/cldr/fr.json +2590 -4979
  96. package/dist/generated/assets/cldr/fr_BE.json +2590 -4979
  97. package/dist/generated/assets/cldr/fr_CA.json +2605 -4973
  98. package/dist/generated/assets/cldr/fr_CH.json +2607 -4997
  99. package/dist/generated/assets/cldr/fr_LU.json +2590 -4979
  100. package/dist/generated/assets/cldr/he.json +2711 -5378
  101. package/dist/generated/assets/cldr/hi.json +2602 -4829
  102. package/dist/generated/assets/cldr/hr.json +2652 -4919
  103. package/dist/generated/assets/cldr/hu.json +2598 -4856
  104. package/dist/generated/assets/cldr/id.json +2544 -4658
  105. package/dist/generated/assets/cldr/it.json +2590 -4950
  106. package/dist/generated/assets/cldr/it_CH.json +2590 -4950
  107. package/dist/generated/assets/cldr/ja.json +2663 -4830
  108. package/dist/generated/assets/cldr/kk.json +2589 -4725
  109. package/dist/generated/assets/cldr/ko.json +2641 -4738
  110. package/dist/generated/assets/cldr/lt.json +2720 -5481
  111. package/dist/generated/assets/cldr/lv.json +2644 -5112
  112. package/dist/generated/assets/cldr/ms.json +2538 -4515
  113. package/dist/generated/assets/cldr/nb.json +2621 -4977
  114. package/dist/generated/assets/cldr/nl.json +2601 -4884
  115. package/dist/generated/assets/cldr/nl_BE.json +2601 -4884
  116. package/dist/generated/assets/cldr/pl.json +2723 -5176
  117. package/dist/generated/assets/cldr/pt.json +2607 -4805
  118. package/dist/generated/assets/cldr/pt_PT.json +2658 -4940
  119. package/dist/generated/assets/cldr/ro.json +2645 -5090
  120. package/dist/generated/assets/cldr/ru.json +2704 -5407
  121. package/dist/generated/assets/cldr/ru_UA.json +2704 -5407
  122. package/dist/generated/assets/cldr/sk.json +2726 -5370
  123. package/dist/generated/assets/cldr/sl.json +2688 -5340
  124. package/dist/generated/assets/cldr/sr.json +2663 -5126
  125. package/dist/generated/assets/cldr/sr_Latn.json +2666 -5127
  126. package/dist/generated/assets/cldr/sv.json +2631 -5011
  127. package/dist/generated/assets/cldr/th.json +2635 -4797
  128. package/dist/generated/assets/cldr/tr.json +2612 -4979
  129. package/dist/generated/assets/cldr/uk.json +2684 -5353
  130. package/dist/generated/assets/cldr/vi.json +2555 -4673
  131. package/dist/generated/assets/cldr/zh_CN.json +2555 -4632
  132. package/dist/generated/assets/cldr/zh_HK.json +2563 -4640
  133. package/dist/generated/assets/cldr/zh_SG.json +2562 -4640
  134. package/dist/generated/assets/cldr/zh_TW.json +2587 -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 -29
  144. package/dist/sap/base/assert.js +5 -6
  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/ui/core/Configuration.d.ts +17 -0
  149. package/dist/sap/ui/core/Configuration.js +21 -0
  150. package/dist/sap/ui/core/Configuration.js.map +1 -0
  151. package/dist/sap/ui/core/Core.d.ts +26 -0
  152. package/dist/sap/ui/core/Core.js +7 -32
  153. package/dist/sap/ui/core/Core.js.map +1 -0
  154. package/dist/sap/ui/core/FormatSettings.d.ts +10 -0
  155. package/dist/sap/ui/core/FormatSettings.js +14 -0
  156. package/dist/sap/ui/core/FormatSettings.js.map +1 -0
  157. package/dist/sap/ui/core/Locale.js +13 -0
  158. package/dist/sap/ui/core/LocaleData.js +180 -25
  159. package/dist/sap/ui/core/date/Buddhist.js +0 -6
  160. package/dist/sap/ui/core/date/CalendarUtils.js +36 -0
  161. package/dist/sap/ui/core/date/CalendarWeekNumbering.js +7 -0
  162. package/dist/sap/ui/core/date/Islamic.js +3 -3
  163. package/dist/sap/ui/core/date/Japanese.js +4 -4
  164. package/dist/sap/ui/core/date/UI5Date.js +305 -0
  165. package/dist/sap/ui/core/date/UniversalDate.js +84 -26
  166. package/dist/sap/ui/core/format/DateFormat.js +786 -477
  167. package/dist/sap/ui/core/format/TimezoneUtil.js +89 -0
  168. package/{package-scripts.js → package-scripts.cjs} +7 -10
  169. package/package.json +7 -5
  170. package/tsconfig.json +14 -0
  171. package/used-modules.txt +5 -1
  172. package/hash.txt +0 -1
  173. package/src/Assets.js +0 -2
  174. package/src/DateFormat.js +0 -3
  175. package/src/LocaleData.js +0 -3
  176. package/src/dates/CalendarDate.js +0 -223
  177. package/src/dates/ExtremeDates.js +0 -39
  178. package/src/dates/calculateWeekNumber.js +0 -51
  179. package/src/dates/getRoundedTimestamp.js +0 -14
  180. package/src/dates/getTodayUTCTimestamp.js +0 -9
  181. package/src/dates/modifyDateBy.js +0 -42
  182. package/src/getCachedLocaleDataInstance.js +0 -13
  183. package/src/locale/getLocaleData.js +0 -27
  184. package/src/sap/base/util/LoaderExtensions.js +0 -17
  185. package/src/sap/ui/core/Core.js +0 -38
  186. /package/{config/.eslintrc.js → .eslintrc.cjs} +0 -0
  187. /package/{src/features/calendar/Buddhist.js → dist/features/calendar/Buddhist.d.ts} +0 -0
  188. /package/{src/features/calendar/Gregorian.js → dist/features/calendar/Gregorian.d.ts} +0 -0
  189. /package/{src/features/calendar/Islamic.js → dist/features/calendar/Islamic.d.ts} +0 -0
  190. /package/{src/features/calendar/Japanese.js → dist/features/calendar/Japanese.d.ts} +0 -0
  191. /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,76 +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](?:\.)?[\x20\xA0]?[mM](?:\.)?/;
944
- var aMatch = sValue.match(rAMPM);
945
- var bVariant = aMatch && aMatch.index === 0;
946
- if (bVariant) {
947
- sValue = aMatch[0];
948
- sAM = sAM.replace(/[\x20\xA0]/g, '');
949
- sPM = sPM.replace(/[\x20\xA0]/g, '');
950
- sValue = sValue.replace(/[\x20\xA0]/g, '');
951
- sAM = sAM.replace(/\./g, '').toLowerCase();
952
- sPM = sPM.replace(/\./g, '').toLowerCase();
953
- sValue = sValue.replace(/\./g, '').toLowerCase();
954
- }
955
- if (sValue.indexOf(sAM) === 0) {
956
- bPM = false;
957
- iLength = bVariant ? aMatch[0].length : sAM.length;
958
- } else if (sValue.indexOf(sPM) === 0) {
959
- bPM = true;
960
- 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
+ }
961
1132
  }
962
- return {
963
- pm: bPM,
964
- length: iLength
965
- };
1133
+ return { valid: false };
966
1134
  }
967
- },
968
- 'H': {
1135
+ }),
1136
+ 'H': DateFormat._createPatternSymbol({
969
1137
  name: 'hour0_23',
970
- format: function (oField, oDate, bUTC, oFormat) {
971
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1138
+ format: function (oField, oDate) {
1139
+ var iHours = oDate.getUTCHours();
972
1140
  return String(iHours).padStart(oField.digits, '0');
973
1141
  },
974
1142
  parse: function (sValue, oPart, oFormat, oConfig) {
975
- var bValid;
976
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
977
- var iHours = parseInt(sPart);
978
- 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);
979
1144
  if (oConfig.strict && iHours > 23) {
980
1145
  bValid = false;
981
1146
  }
@@ -984,21 +1149,19 @@ DateFormat.prototype.oSymbols = {
984
1149
  length: sPart.length,
985
1150
  valid: bValid
986
1151
  };
987
- }
988
- },
989
- 'k': {
1152
+ },
1153
+ isNumeric: true
1154
+ }),
1155
+ 'k': DateFormat._createPatternSymbol({
990
1156
  name: 'hour1_24',
991
- format: function (oField, oDate, bUTC, oFormat) {
992
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1157
+ format: function (oField, oDate) {
1158
+ var iHours = oDate.getUTCHours();
993
1159
  var sHours = iHours === 0 ? '24' : String(iHours);
994
1160
  return sHours.padStart(oField.digits, '0');
995
1161
  },
996
1162
  parse: function (sValue, oPart, oFormat, oConfig) {
997
- var bValid;
998
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
999
- var iHours = parseInt(sPart);
1000
- bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
1001
- 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) {
1002
1165
  iHours = 0;
1003
1166
  }
1004
1167
  if (oConfig.strict && iHours > 23) {
@@ -1009,20 +1172,18 @@ DateFormat.prototype.oSymbols = {
1009
1172
  length: sPart.length,
1010
1173
  valid: bValid
1011
1174
  };
1012
- }
1013
- },
1014
- 'K': {
1175
+ },
1176
+ isNumeric: true
1177
+ }),
1178
+ 'K': DateFormat._createPatternSymbol({
1015
1179
  name: 'hour0_11',
1016
- format: function (oField, oDate, bUTC, oFormat) {
1017
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1180
+ format: function (oField, oDate) {
1181
+ var iHours = oDate.getUTCHours();
1018
1182
  var sHours = String(iHours > 11 ? iHours - 12 : iHours);
1019
1183
  return sHours.padStart(oField.digits, '0');
1020
1184
  },
1021
1185
  parse: function (sValue, oPart, oFormat, oConfig) {
1022
- var bValid;
1023
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
1024
- var iHours = parseInt(sPart);
1025
- 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);
1026
1187
  if (oConfig.strict && iHours > 11) {
1027
1188
  bValid = false;
1028
1189
  }
@@ -1031,16 +1192,17 @@ DateFormat.prototype.oSymbols = {
1031
1192
  length: sPart.length,
1032
1193
  valid: bValid
1033
1194
  };
1034
- }
1035
- },
1036
- 'h': {
1195
+ },
1196
+ isNumeric: true
1197
+ }),
1198
+ 'h': DateFormat._createPatternSymbol({
1037
1199
  name: 'hour1_12',
1038
- format: function (oField, oDate, bUTC, oFormat) {
1039
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1200
+ format: function (oField, oDate) {
1201
+ var iHours = oDate.getUTCHours();
1040
1202
  var sHours;
1041
1203
  if (iHours > 12) {
1042
1204
  sHours = String(iHours - 12);
1043
- } else if (iHours == 0) {
1205
+ } else if (iHours === 0) {
1044
1206
  sHours = '12';
1045
1207
  } else {
1046
1208
  sHours = String(iHours);
@@ -1048,11 +1210,8 @@ DateFormat.prototype.oSymbols = {
1048
1210
  return sHours.padStart(oField.digits, '0');
1049
1211
  },
1050
1212
  parse: function (sValue, oPart, oFormat, oConfig) {
1051
- var bPM = oConfig.dateValue.pm;
1052
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
1053
- var iHours = parseInt(sPart);
1054
- var bValid = oParseHelper.checkValid(oPart.type, sPart === '', oFormat);
1055
- 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) {
1056
1215
  iHours = 0;
1057
1216
  bPM = bPM === undefined ? true : bPM;
1058
1217
  }
@@ -1065,19 +1224,17 @@ DateFormat.prototype.oSymbols = {
1065
1224
  pm: bPM,
1066
1225
  valid: bValid
1067
1226
  };
1068
- }
1069
- },
1070
- 'm': {
1227
+ },
1228
+ isNumeric: true
1229
+ }),
1230
+ 'm': DateFormat._createPatternSymbol({
1071
1231
  name: 'minute',
1072
- format: function (oField, oDate, bUTC, oFormat) {
1073
- var iMinutes = bUTC ? oDate.getUTCMinutes() : oDate.getMinutes();
1232
+ format: function (oField, oDate) {
1233
+ var iMinutes = oDate.getUTCMinutes();
1074
1234
  return String(iMinutes).padStart(oField.digits, '0');
1075
1235
  },
1076
1236
  parse: function (sValue, oPart, oFormat, oConfig) {
1077
- var bValid;
1078
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
1079
- var iMinutes = parseInt(sPart);
1080
- 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);
1081
1238
  if (oConfig.strict && iMinutes > 59) {
1082
1239
  bValid = false;
1083
1240
  }
@@ -1086,19 +1243,17 @@ DateFormat.prototype.oSymbols = {
1086
1243
  minute: iMinutes,
1087
1244
  valid: bValid
1088
1245
  };
1089
- }
1090
- },
1091
- 's': {
1246
+ },
1247
+ isNumeric: true
1248
+ }),
1249
+ 's': DateFormat._createPatternSymbol({
1092
1250
  name: 'second',
1093
- format: function (oField, oDate, bUTC, oFormat) {
1094
- var iSeconds = bUTC ? oDate.getUTCSeconds() : oDate.getSeconds();
1251
+ format: function (oField, oDate) {
1252
+ var iSeconds = oDate.getUTCSeconds();
1095
1253
  return String(iSeconds).padStart(oField.digits, '0');
1096
1254
  },
1097
1255
  parse: function (sValue, oPart, oFormat, oConfig) {
1098
- var bValid;
1099
- var sPart = oParseHelper.findNumbers(sValue, Math.max(oPart.digits, 2));
1100
- var iSeconds = parseInt(sPart);
1101
- 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);
1102
1257
  if (oConfig.strict && iSeconds > 59) {
1103
1258
  bValid = false;
1104
1259
  }
@@ -1107,12 +1262,13 @@ DateFormat.prototype.oSymbols = {
1107
1262
  second: iSeconds,
1108
1263
  valid: bValid
1109
1264
  };
1110
- }
1111
- },
1112
- 'S': {
1265
+ },
1266
+ isNumeric: true
1267
+ }),
1268
+ 'S': DateFormat._createPatternSymbol({
1113
1269
  name: 'fractionalsecond',
1114
- format: function (oField, oDate, bUTC, oFormat) {
1115
- var iMilliseconds = bUTC ? oDate.getUTCMilliseconds() : oDate.getMilliseconds();
1270
+ format: function (oField, oDate) {
1271
+ var iMilliseconds = oDate.getUTCMilliseconds();
1116
1272
  var sMilliseconds = String(iMilliseconds);
1117
1273
  var sFractionalseconds = sMilliseconds.padStart(3, '0');
1118
1274
  sFractionalseconds = sFractionalseconds.substr(0, oField.digits);
@@ -1120,31 +1276,33 @@ DateFormat.prototype.oSymbols = {
1120
1276
  return sFractionalseconds;
1121
1277
  },
1122
1278
  parse: function (sValue, oPart, oFormat, oConfig) {
1123
- var sPart = oParseHelper.findNumbers(sValue, oPart.digits);
1124
- var iLength = sPart.length;
1279
+ var sPart = oParseHelper.findNumbers(sValue, oPart.digits), iLength = sPart.length, bPartInvalid = oConfig.exactLength && iLength < oPart.digits;
1125
1280
  sPart = sPart.substr(0, 3);
1126
1281
  sPart = sPart.padEnd(3, '0');
1127
1282
  var iMilliseconds = parseInt(sPart);
1128
1283
  return {
1129
1284
  length: iLength,
1130
- millisecond: iMilliseconds
1285
+ millisecond: iMilliseconds,
1286
+ valid: oParseHelper.checkValid(oPart.type, bPartInvalid, oFormat)
1131
1287
  };
1132
- }
1133
- },
1134
- 'z': {
1288
+ },
1289
+ isNumeric: true
1290
+ }),
1291
+ 'z': DateFormat._createPatternSymbol({
1135
1292
  name: 'timezoneGeneral',
1136
- format: function (oField, oDate, bUTC, oFormat) {
1293
+ format: function (oField, oDate, bUTC, oFormat, sTimezone) {
1137
1294
  if (oField.digits > 3 && oDate.getTimezoneLong && oDate.getTimezoneLong()) {
1138
1295
  return oDate.getTimezoneLong();
1139
1296
  } else if (oDate.getTimezoneShort && oDate.getTimezoneShort()) {
1140
1297
  return oDate.getTimezoneShort();
1141
1298
  }
1299
+ var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
1142
1300
  var sTimeZone = 'GMT';
1143
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1144
- var bPositiveOffset = oDate.getTimezoneOffset() > 0;
1301
+ var iTZOffset = Math.abs(iTimezoneOffset / 60);
1302
+ var bPositiveOffset = iTimezoneOffset > 0;
1145
1303
  var iHourOffset = Math.floor(iTZOffset / 60);
1146
- var iMinuteOffset = iTZOffset % 60;
1147
- if (!bUTC && iTZOffset != 0) {
1304
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1305
+ if (!bUTC && iTZOffset !== 0) {
1148
1306
  sTimeZone += bPositiveOffset ? '-' : '+';
1149
1307
  sTimeZone += String(iHourOffset).padStart(2, '0');
1150
1308
  sTimeZone += ':';
@@ -1178,14 +1336,15 @@ DateFormat.prototype.oSymbols = {
1178
1336
  tzDiff: iTZDiff
1179
1337
  };
1180
1338
  }
1181
- },
1182
- 'Z': {
1339
+ }),
1340
+ 'Z': DateFormat._createPatternSymbol({
1183
1341
  name: 'timezoneRFC822',
1184
- format: function (oField, oDate, bUTC, oFormat) {
1185
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1186
- 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;
1187
1346
  var iHourOffset = Math.floor(iTZOffset / 60);
1188
- var iMinuteOffset = iTZOffset % 60;
1347
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1189
1348
  var sTimeZone = '';
1190
1349
  if (!bUTC) {
1191
1350
  sTimeZone += bPositiveOffset ? '-' : '+';
@@ -1197,16 +1356,17 @@ DateFormat.prototype.oSymbols = {
1197
1356
  parse: function (sValue, oPart, oFormat, oConfig) {
1198
1357
  return oParseHelper.parseTZ(sValue, false);
1199
1358
  }
1200
- },
1201
- 'X': {
1359
+ }),
1360
+ 'X': DateFormat._createPatternSymbol({
1202
1361
  name: 'timezoneISO8601',
1203
- format: function (oField, oDate, bUTC, oFormat) {
1204
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1205
- 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;
1206
1366
  var iHourOffset = Math.floor(iTZOffset / 60);
1207
- var iMinuteOffset = iTZOffset % 60;
1367
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1208
1368
  var sTimeZone = '';
1209
- if (!bUTC && iTZOffset != 0) {
1369
+ if (!bUTC && iTZOffset !== 0) {
1210
1370
  sTimeZone += bPositiveOffset ? '-' : '+';
1211
1371
  sTimeZone += String(iHourOffset).padStart(2, '0');
1212
1372
  if (oField.digits > 1 || iMinuteOffset > 0) {
@@ -1230,11 +1390,52 @@ DateFormat.prototype.oSymbols = {
1230
1390
  return oParseHelper.parseTZ(sValue, oPart.digits === 3 || oPart.digits === 5);
1231
1391
  }
1232
1392
  }
1233
- }
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
+ })
1234
1435
  };
1235
- DateFormat.prototype._format = function (oJSDate, bUTC) {
1436
+ DateFormat.prototype._format = function (oJSDate, bUTC, sTimezone) {
1236
1437
  if (this.oFormatOptions.relative) {
1237
- var sRes = this.formatRelative(oJSDate, bUTC, this.oFormatOptions.relativeRange);
1438
+ var sRes = this.formatRelative(oJSDate, bUTC, this.oFormatOptions.relativeRange, sTimezone);
1238
1439
  if (sRes) {
1239
1440
  return sRes;
1240
1441
  }
@@ -1245,10 +1446,10 @@ DateFormat.prototype._format = function (oJSDate, bUTC) {
1245
1446
  for (var i = 0; i < this.aFormatArray.length; i++) {
1246
1447
  oPart = this.aFormatArray[i];
1247
1448
  sSymbol = oPart.symbol || '';
1248
- aBuffer.push(this.oSymbols[sSymbol].format(oPart, oDate, bUTC, this));
1449
+ aBuffer.push(this.oSymbols[sSymbol].format(oPart, oDate, bUTC, this, sTimezone));
1249
1450
  }
1250
1451
  sResult = aBuffer.join('');
1251
- if (Core.getConfiguration().getOriginInfo()) {
1452
+ if (Configuration.getOriginInfo()) {
1252
1453
  sResult = new String(sResult);
1253
1454
  sResult.originInfo = {
1254
1455
  source: 'Common Locale Data Repository',
@@ -1260,10 +1461,21 @@ DateFormat.prototype._format = function (oJSDate, bUTC) {
1260
1461
  return sResult;
1261
1462
  };
1262
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
+ }
1263
1474
  var sCalendarType = this.oFormatOptions.calendarType, sResult;
1264
1475
  if (bUTC === undefined) {
1265
1476
  bUTC = this.oFormatOptions.UTC;
1266
1477
  }
1478
+ sTimezone = sTimezone || Configuration.getTimezone();
1267
1479
  if (Array.isArray(vJSDate)) {
1268
1480
  if (!this.oFormatOptions.interval) {
1269
1481
  Log.error('Non-interval DateFormat can\'t format more than one date instance.');
@@ -1273,27 +1485,30 @@ DateFormat.prototype.format = function (vJSDate, bUTC) {
1273
1485
  Log.error('Interval DateFormat can only format with 2 date instances but ' + vJSDate.length + ' is given.');
1274
1486
  return '';
1275
1487
  }
1488
+ vJSDate = vJSDate.map(function (oJSDate) {
1489
+ return convertToTimezone(oJSDate, sTimezone, bUTC);
1490
+ });
1276
1491
  if (this.oFormatOptions.singleIntervalValue) {
1277
1492
  if (vJSDate[0] === null) {
1278
1493
  Log.error('First date instance which is passed to the interval DateFormat shouldn\'t be null.');
1279
1494
  return '';
1280
1495
  }
1281
1496
  if (vJSDate[1] === null) {
1282
- sResult = this._format(vJSDate[0], bUTC);
1497
+ sResult = this._format(vJSDate[0], bUTC, sTimezone);
1283
1498
  }
1284
1499
  }
1285
1500
  if (sResult === undefined) {
1286
- var bValid = vJSDate.every(function (oJSDate) {
1287
- return oJSDate && !isNaN(oJSDate.getTime());
1288
- });
1289
- if (!bValid) {
1501
+ if (!vJSDate.every(isValidDateObject)) {
1290
1502
  Log.error('At least one date instance which is passed to the interval DateFormat isn\'t valid.');
1291
1503
  return '';
1292
1504
  }
1293
1505
  sResult = this._formatInterval(vJSDate, bUTC);
1294
1506
  }
1295
1507
  } else {
1296
- 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
+ }
1297
1512
  Log.error('The given date instance isn\'t valid.');
1298
1513
  return '';
1299
1514
  }
@@ -1301,9 +1516,10 @@ DateFormat.prototype.format = function (vJSDate, bUTC) {
1301
1516
  Log.error('Interval DateFormat expects an array with two dates for the first argument but only one date is given.');
1302
1517
  return '';
1303
1518
  }
1304
- sResult = this._format(vJSDate, bUTC);
1519
+ vJSDate = convertToTimezone(vJSDate, sTimezone, bUTC);
1520
+ sResult = this._format(vJSDate, bUTC, sTimezone);
1305
1521
  }
1306
- if (sCalendarType == CalendarType.Japanese && this.oLocale.getLanguage() === 'ja') {
1522
+ if (sCalendarType === CalendarType.Japanese && this.oLocale.getLanguage() === 'ja') {
1307
1523
  sResult = sResult.replace(/(^|[^\d])1年/g, '$1元年');
1308
1524
  }
1309
1525
  return sResult;
@@ -1321,7 +1537,7 @@ DateFormat.prototype._formatInterval = function (aJSDates, bUTC) {
1321
1537
  var oDiffField = this._getGreatestDiffField([
1322
1538
  oFromDate,
1323
1539
  oToDate
1324
- ], bUTC);
1540
+ ]);
1325
1541
  if (!oDiffField) {
1326
1542
  return this._format(aJSDates[0], bUTC);
1327
1543
  }
@@ -1354,10 +1570,10 @@ var mFieldToGroup = {
1354
1570
  Minutes: 'Minute',
1355
1571
  Seconds: 'Second'
1356
1572
  };
1357
- DateFormat.prototype._getGreatestDiffField = function (aDates, bUTC) {
1573
+ DateFormat.prototype._getGreatestDiffField = function (aDates) {
1358
1574
  var bDiffFound = false, mDiff = {};
1359
1575
  this.aIntervalCompareFields.forEach(function (sField) {
1360
- 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]);
1361
1577
  if (!deepEqual(vFromValue, vToValue)) {
1362
1578
  bDiffFound = true;
1363
1579
  mDiff[sFieldGroup] = true;
@@ -1368,19 +1584,32 @@ DateFormat.prototype._getGreatestDiffField = function (aDates, bUTC) {
1368
1584
  }
1369
1585
  return null;
1370
1586
  };
1371
- DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1372
- var iIndex = 0, oPart, sSubValue, oResult;
1373
- var oDateValue = { valid: true };
1374
- var oParseConf = {
1375
- formatArray: aFormatArray,
1376
- dateValue: oDateValue,
1377
- strict: bStrict
1378
- };
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
+ }
1379
1602
  for (var i = 0; i < aFormatArray.length; i++) {
1380
1603
  sSubValue = sValue.substr(iIndex);
1381
1604
  oPart = aFormatArray[i];
1605
+ oPrevPart = aFormatArray[i - 1];
1606
+ oNextPart = aFormatArray[i + 1];
1382
1607
  oParseConf.index = i;
1383
- 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
+ }
1384
1613
  oDateValue = extend(oDateValue, oResult);
1385
1614
  if (oResult.valid === false) {
1386
1615
  break;
@@ -1388,7 +1617,12 @@ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1388
1617
  iIndex += oResult.length || 0;
1389
1618
  }
1390
1619
  oDateValue.index = iIndex;
1391
- 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) {
1392
1626
  oDateValue.hour += 12;
1393
1627
  }
1394
1628
  if (oDateValue.dayNumberOfWeek === undefined && oDateValue.dayOfWeek !== undefined) {
@@ -1400,7 +1634,7 @@ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1400
1634
  }
1401
1635
  return oDateValue;
1402
1636
  };
1403
- DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bStrict) {
1637
+ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bStrict, sTimezone) {
1404
1638
  var aDateValues, iRepeat, oDateValue;
1405
1639
  this.intervalPatterns.some(function (sPattern) {
1406
1640
  var aFormatArray = this.parseCldrDatePattern(sPattern);
@@ -1412,7 +1646,7 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1412
1646
  }
1413
1647
  }
1414
1648
  if (iRepeat === undefined) {
1415
- oDateValue = this._parse(sValue, aFormatArray, bUTC, bStrict);
1649
+ oDateValue = this._parse(sValue, aFormatArray, bUTC, bStrict, sTimezone);
1416
1650
  if (oDateValue.index === 0 || oDateValue.index < sValue.length) {
1417
1651
  oDateValue.valid = false;
1418
1652
  }
@@ -1426,13 +1660,13 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1426
1660
  return true;
1427
1661
  } else {
1428
1662
  aDateValues = [];
1429
- oDateValue = this._parse(sValue, aFormatArray.slice(0, iRepeat), bUTC, bStrict);
1663
+ oDateValue = this._parse(sValue, aFormatArray.slice(0, iRepeat), bUTC, bStrict, sTimezone);
1430
1664
  if (oDateValue.valid === false) {
1431
1665
  return;
1432
1666
  }
1433
1667
  aDateValues.push(oDateValue);
1434
1668
  var iLength = oDateValue.index;
1435
- oDateValue = this._parse(sValue.substring(iLength), aFormatArray.slice(iRepeat), bUTC, bStrict);
1669
+ oDateValue = this._parse(sValue.substring(iLength), aFormatArray.slice(iRepeat), bUTC, bStrict, sTimezone);
1436
1670
  if (oDateValue.index === 0 || oDateValue.index + iLength < sValue.length) {
1437
1671
  oDateValue.valid = false;
1438
1672
  }
@@ -1445,65 +1679,62 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1445
1679
  }.bind(this));
1446
1680
  return aDateValues;
1447
1681
  };
1448
- 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
+ }
1449
1703
  var oDate, iYear = typeof oDateValue.year === 'number' ? oDateValue.year : 1970;
1450
- if (oDateValue.valid) {
1451
- if (bUTC || oDateValue.tzDiff !== undefined) {
1452
- oDate = UniversalDate.getInstance(new Date(0), sCalendarType);
1453
- oDate.setUTCEra(oDateValue.era || UniversalDate.getCurrentEra(sCalendarType));
1454
- oDate.setUTCFullYear(iYear);
1455
- oDate.setUTCMonth(oDateValue.month || 0);
1456
- oDate.setUTCDate(oDateValue.day || 1);
1457
- oDate.setUTCHours(oDateValue.hour || 0);
1458
- oDate.setUTCMinutes(oDateValue.minute || 0);
1459
- oDate.setUTCSeconds(oDateValue.second || 0);
1460
- oDate.setUTCMilliseconds(oDateValue.millisecond || 0);
1461
- if (bStrict && (oDateValue.day || 1) !== oDate.getUTCDate()) {
1462
- oDateValue.valid = false;
1463
- oDate = undefined;
1464
- } else {
1465
- if (oDateValue.tzDiff) {
1466
- oDate.setUTCMinutes((oDateValue.minute || 0) + oDateValue.tzDiff);
1467
- }
1468
- if (oDateValue.week !== undefined && (oDateValue.month === undefined || oDateValue.day === undefined)) {
1469
- oDate.setUTCWeek({
1470
- year: oDateValue.weekYear || oDateValue.year,
1471
- week: oDateValue.week
1472
- });
1473
- if (oDateValue.dayNumberOfWeek !== undefined) {
1474
- oDate.setUTCDate(oDate.getUTCDate() + oDateValue.dayNumberOfWeek - 1);
1475
- }
1476
- }
1477
- }
1478
- } else {
1479
- oDate = UniversalDate.getInstance(new Date(1970, 0, 1, 0, 0, 0), sCalendarType);
1480
- oDate.setEra(oDateValue.era || UniversalDate.getCurrentEra(sCalendarType));
1481
- oDate.setFullYear(iYear);
1482
- oDate.setMonth(oDateValue.month || 0);
1483
- oDate.setDate(oDateValue.day || 1);
1484
- oDate.setHours(oDateValue.hour || 0);
1485
- oDate.setMinutes(oDateValue.minute || 0);
1486
- oDate.setSeconds(oDateValue.second || 0);
1487
- oDate.setMilliseconds(oDateValue.millisecond || 0);
1488
- if (bStrict && (oDateValue.day || 1) !== oDate.getDate()) {
1489
- oDateValue.valid = false;
1490
- oDate = undefined;
1491
- } else if (oDateValue.week !== undefined && (oDateValue.month === undefined || oDateValue.day === undefined)) {
1492
- oDate.setWeek({
1493
- year: oDateValue.weekYear || oDateValue.year,
1494
- week: oDateValue.week
1495
- });
1496
- if (oDateValue.dayNumberOfWeek !== undefined) {
1497
- oDate.setDate(oDate.getDate() + oDateValue.dayNumberOfWeek - 1);
1498
- }
1499
- }
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);
1500
1723
  }
1501
- if (oDateValue.valid) {
1502
- oDate = oDate.getJSDate();
1503
- 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);
1504
1732
  }
1505
1733
  }
1506
- return null;
1734
+ if (oDateValue.tzDiff) {
1735
+ oDate.setUTCSeconds(oDate.getUTCSeconds() + oDateValue.tzDiff);
1736
+ }
1737
+ return oDate;
1507
1738
  };
1508
1739
  function mergeWithoutOverwrite(object1, object2) {
1509
1740
  if (object1 === object2) {
@@ -1526,17 +1757,37 @@ function isValidDateRange(oStartDate, oEndDate) {
1526
1757
  }
1527
1758
  return true;
1528
1759
  }
1760
+ function isValidDateObject(oDate) {
1761
+ return oDate && typeof oDate.getTime === 'function' && !isNaN(oDate.getTime());
1762
+ }
1529
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
+ }
1530
1783
  sValue = sValue == null ? '' : String(sValue).trim();
1531
1784
  var oDateValue;
1532
1785
  var sCalendarType = this.oFormatOptions.calendarType;
1533
- if (bUTC === undefined) {
1534
- bUTC = this.oFormatOptions.UTC;
1535
- }
1786
+ sTimezone = sTimezone || Configuration.getTimezone();
1536
1787
  if (bStrict === undefined) {
1537
1788
  bStrict = this.oFormatOptions.strictParsing;
1538
1789
  }
1539
- if (sCalendarType == CalendarType.Japanese && this.oLocale.getLanguage() === 'ja') {
1790
+ if (sCalendarType === CalendarType.Japanese && this.oLocale.getLanguage() === 'ja') {
1540
1791
  sValue = sValue.replace(/元年/g, '1年');
1541
1792
  }
1542
1793
  if (!this.oFormatOptions.interval) {
@@ -1544,22 +1795,40 @@ DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
1544
1795
  if (oJSDate) {
1545
1796
  return oJSDate;
1546
1797
  }
1547
- oDateValue = this._parse(sValue, this.aFormatArray, bUTC, bStrict);
1798
+ oDateValue = this._parse(sValue, this.aFormatArray, bUTC, bStrict, sTimezone);
1548
1799
  if (oDateValue.index === 0 || oDateValue.index < sValue.length) {
1549
1800
  oDateValue.valid = false;
1550
1801
  }
1551
- oJSDate = fnCreateDate(oDateValue, sCalendarType, bUTC, bStrict);
1802
+ oJSDate = fnCreateDate(oDateValue, sCalendarType, bUTC, bStrict, sTimezone, this.oFormatOptions, this.oLocale);
1552
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
+ }
1553
1822
  return oJSDate;
1554
1823
  }
1555
1824
  } else {
1556
- var aDateValues = this._parseInterval(sValue, sCalendarType, bUTC, bStrict);
1825
+ var aDateValues = this._parseInterval(sValue, sCalendarType, bUTC, bStrict, sTimezone);
1557
1826
  var oJSDate1, oJSDate2;
1558
- if (aDateValues && aDateValues.length == 2) {
1827
+ if (aDateValues && aDateValues.length === 2) {
1559
1828
  var oDateValue1 = mergeWithoutOverwrite(aDateValues[0], aDateValues[1]);
1560
1829
  var oDateValue2 = mergeWithoutOverwrite(aDateValues[1], aDateValues[0]);
1561
- oJSDate1 = fnCreateDate(oDateValue1, sCalendarType, bUTC, bStrict);
1562
- 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);
1563
1832
  if (oJSDate1 && oJSDate2) {
1564
1833
  if (this.oFormatOptions.singleIntervalValue && oJSDate1.getTime() === oJSDate2.getTime()) {
1565
1834
  return [
@@ -1582,11 +1851,14 @@ DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
1582
1851
  }
1583
1852
  }
1584
1853
  }
1585
- if (!this.bIsFallback) {
1854
+ if (this.aFallbackFormats) {
1586
1855
  var vDate;
1587
1856
  this.aFallbackFormats.every(function (oFallbackFormat) {
1588
- vDate = oFallbackFormat.parse(sValue, bUTC, bStrict);
1857
+ vDate = oFallbackFormat.parse(sValue, bUTCInputParameter, bStrict);
1589
1858
  if (Array.isArray(vDate)) {
1859
+ if (oFallbackFormat.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1860
+ return false;
1861
+ }
1590
1862
  return !(vDate[0] && vDate[1]);
1591
1863
  } else {
1592
1864
  return !vDate;
@@ -1611,20 +1883,20 @@ DateFormat.prototype.parseCldrDatePattern = function (sPattern) {
1611
1883
  for (i = 0; i < sPattern.length; i++) {
1612
1884
  var sCurChar = sPattern.charAt(i), sNextChar, sPrevChar, sPrevPrevChar;
1613
1885
  if (bQuoted) {
1614
- if (sCurChar == '\'') {
1886
+ if (sCurChar === '\'') {
1615
1887
  sPrevChar = sPattern.charAt(i - 1);
1616
1888
  sPrevPrevChar = sPattern.charAt(i - 2);
1617
1889
  sNextChar = sPattern.charAt(i + 1);
1618
- if (sPrevChar == '\'' && sPrevPrevChar != '\'') {
1890
+ if (sPrevChar === '\'' && sPrevPrevChar !== '\'') {
1619
1891
  bQuoted = false;
1620
- } else if (sNextChar == '\'') {
1892
+ } else if (sNextChar === '\'') {
1621
1893
  i += 1;
1622
1894
  } else {
1623
1895
  bQuoted = false;
1624
1896
  continue;
1625
1897
  }
1626
1898
  }
1627
- if (sState == 'text') {
1899
+ if (sState === 'text') {
1628
1900
  oCurrentObject.value += sCurChar;
1629
1901
  } else {
1630
1902
  oCurrentObject = {
@@ -1635,11 +1907,11 @@ DateFormat.prototype.parseCldrDatePattern = function (sPattern) {
1635
1907
  sState = 'text';
1636
1908
  }
1637
1909
  } else {
1638
- if (sCurChar == '\'') {
1910
+ if (sCurChar === '\'') {
1639
1911
  bQuoted = true;
1640
1912
  } else if (this.oSymbols[sCurChar]) {
1641
1913
  sNewState = this.oSymbols[sCurChar].name;
1642
- if (sState == sNewState) {
1914
+ if (sState === sNewState) {
1643
1915
  oCurrentObject.digits++;
1644
1916
  } else {
1645
1917
  oCurrentObject = {
@@ -1659,7 +1931,7 @@ DateFormat.prototype.parseCldrDatePattern = function (sPattern) {
1659
1931
  }
1660
1932
  }
1661
1933
  } else {
1662
- if (sState == 'text') {
1934
+ if (sState === 'text') {
1663
1935
  oCurrentObject.value += sCurChar;
1664
1936
  } else {
1665
1937
  oCurrentObject = {
@@ -1695,70 +1967,88 @@ DateFormat.prototype.parseRelative = function (sValue, bUTC) {
1695
1967
  }
1696
1968
  }
1697
1969
  function computeRelativeDate(iDiff, sScale) {
1698
- var iToday, oToday = new Date(), oJSDate;
1970
+ var oResult = UI5Date.getInstance();
1699
1971
  if (bUTC) {
1700
- iToday = oToday.getTime();
1701
- } else {
1702
- iToday = Date.UTC(oToday.getFullYear(), oToday.getMonth(), oToday.getDate(), oToday.getHours(), oToday.getMinutes(), oToday.getSeconds(), oToday.getMilliseconds());
1703
- }
1704
- oJSDate = new Date(iToday);
1705
- switch (sScale) {
1706
- case 'second':
1707
- oJSDate.setUTCSeconds(oJSDate.getUTCSeconds() + iDiff);
1708
- break;
1709
- case 'minute':
1710
- oJSDate.setUTCMinutes(oJSDate.getUTCMinutes() + iDiff);
1711
- break;
1712
- case 'hour':
1713
- oJSDate.setUTCHours(oJSDate.getUTCHours() + iDiff);
1714
- break;
1715
- case 'day':
1716
- oJSDate.setUTCDate(oJSDate.getUTCDate() + iDiff);
1717
- break;
1718
- case 'week':
1719
- oJSDate.setUTCDate(oJSDate.getUTCDate() + iDiff * 7);
1720
- break;
1721
- case 'month':
1722
- oJSDate.setUTCMonth(oJSDate.getUTCMonth() + iDiff);
1723
- break;
1724
- case 'quarter':
1725
- oJSDate.setUTCMonth(oJSDate.getUTCMonth() + iDiff * 3);
1726
- break;
1727
- case 'year':
1728
- oJSDate.setUTCFullYear(oJSDate.getUTCFullYear() + iDiff);
1729
- break;
1730
- }
1731
- if (bUTC) {
1732
- 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
+ }
1733
2000
  } else {
1734
- 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
+ }
1735
2027
  }
2028
+ return oResult;
1736
2029
  }
1737
2030
  };
1738
- DateFormat.prototype.formatRelative = function (oJSDate, bUTC, aRange) {
1739
- 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';
1740
2033
  iDiffSeconds = (oJSDate.getTime() - oToday.getTime()) / 1000;
1741
- if (this.oFormatOptions.relativeScale == 'auto') {
2034
+ if (this.oFormatOptions.relativeScale === 'auto') {
1742
2035
  sScale = this._getScale(iDiffSeconds, this.aRelativeScales);
2036
+ sScale = fixScaleForMonths(oJSDate, oToday, sScale, iDiffSeconds);
1743
2037
  }
1744
2038
  if (!aRange) {
1745
2039
  aRange = this._mRanges[sScale];
1746
2040
  }
1747
- if (sScale == 'year' || sScale == 'month' || sScale == 'day') {
1748
- 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()));
1749
2043
  oDateUTC = new Date(0);
1750
- if (bUTC) {
1751
- oDateUTC.setUTCFullYear(oJSDate.getUTCFullYear(), oJSDate.getUTCMonth(), oJSDate.getUTCDate());
1752
- } else {
1753
- oDateUTC.setUTCFullYear(oJSDate.getFullYear(), oJSDate.getMonth(), oJSDate.getDate());
1754
- }
2044
+ oDateUTC.setUTCFullYear(oJSDate.getUTCFullYear(), oJSDate.getUTCMonth(), oJSDate.getUTCDate());
1755
2045
  oJSDate = oDateUTC;
1756
2046
  }
1757
2047
  iDiff = this._getDifference(sScale, [
1758
2048
  oToday,
1759
2049
  oJSDate
1760
2050
  ]);
1761
- if (this.oFormatOptions.relativeScale != 'auto' && (iDiff < aRange[0] || iDiff > aRange[1])) {
2051
+ if (this.oFormatOptions.relativeScale !== 'auto' && (iDiff < aRange[0] || iDiff > aRange[1])) {
1762
2052
  return null;
1763
2053
  }
1764
2054
  sPattern = this.oLocaleData.getRelativePattern(sScale, iDiff, iDiffSeconds > 0, this.oFormatOptions.relativeStyle);
@@ -1819,8 +2109,23 @@ DateFormat.prototype._getScale = function (iDiffSeconds, aScales) {
1819
2109
  }
1820
2110
  return sScale;
1821
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
+ }
1822
2127
  function cutDateFields(oDate, iStartIndex) {
1823
- var aFields = [
2128
+ var sMethodName, aFields = [
1824
2129
  'FullYear',
1825
2130
  'Month',
1826
2131
  'Date',
@@ -1828,24 +2133,23 @@ function cutDateFields(oDate, iStartIndex) {
1828
2133
  'Minutes',
1829
2134
  'Seconds',
1830
2135
  'Milliseconds'
1831
- ], sMethodName;
1832
- var oDateCopy = new Date(oDate.getTime());
2136
+ ], oDateCopy = new Date(oDate.getTime());
1833
2137
  for (var i = iStartIndex; i < aFields.length; i++) {
1834
- sMethodName = 'set' + aFields[iStartIndex];
2138
+ sMethodName = 'setUTC' + aFields[iStartIndex];
1835
2139
  oDateCopy[sMethodName].apply(oDateCopy, [0]);
1836
2140
  }
1837
2141
  return oDateCopy;
1838
2142
  }
1839
2143
  var mRelativeDiffs = {
1840
2144
  year: function (oFromDate, oToDate) {
1841
- return oToDate.getFullYear() - oFromDate.getFullYear();
2145
+ return oToDate.getUTCFullYear() - oFromDate.getUTCFullYear();
1842
2146
  },
1843
2147
  month: function (oFromDate, oToDate) {
1844
- return oToDate.getMonth() - oFromDate.getMonth() + this.year(oFromDate, oToDate) * 12;
2148
+ return oToDate.getUTCMonth() - oFromDate.getUTCMonth() + this.year(oFromDate, oToDate) * 12;
1845
2149
  },
1846
2150
  week: function (oFromDate, oToDate, oFormat) {
1847
- var iFromDay = oFormat._adaptDayOfWeek(oFromDate.getDay());
1848
- var iToDay = oFormat._adaptDayOfWeek(oToDate.getDay());
2151
+ var iFromDay = oFormat._adaptDayOfWeek(oFromDate.getUTCDay());
2152
+ var iToDay = oFormat._adaptDayOfWeek(oToDate.getUTCDay());
1849
2153
  oFromDate = cutDateFields(oFromDate, 3);
1850
2154
  oToDate = cutDateFields(oToDate, 3);
1851
2155
  return (oToDate.getTime() - oFromDate.getTime() - (iToDay - iFromDay) * oFormat._mScales.day * 1000) / (oFormat._mScales.week * 1000);
@@ -1872,7 +2176,12 @@ var mRelativeDiffs = {
1872
2176
  }
1873
2177
  };
1874
2178
  DateFormat.prototype._adaptDayOfWeek = function (iDayOfWeek) {
1875
- 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
+ }
1876
2185
  var iDayNumberOfWeek = iDayOfWeek - (iFirstDayOfWeek - 1);
1877
2186
  if (iDayNumberOfWeek <= 0) {
1878
2187
  iDayNumberOfWeek += 7;