@ui5/webcomponents-localization 0.0.0-e7dd012d7 → 0.0.0-e818f286e

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 (117) hide show
  1. package/.eslintignore +1 -0
  2. package/CHANGELOG.md +191 -0
  3. package/README.md +36 -6
  4. package/dist/Assets-static.js +2 -0
  5. package/dist/dates/CalendarDate.js +7 -1
  6. package/dist/dates/ExtremeDates.js +39 -0
  7. package/dist/dates/convertMonthNumbersToMonthNames.js +33 -0
  8. package/dist/dates/getDaysInMonth.js +11 -0
  9. package/dist/dates/getRoundedTimestamp.js +14 -0
  10. package/dist/dates/getTodayUTCTimestamp.js +9 -0
  11. package/dist/dates/modifyDateBy.js +42 -0
  12. package/dist/dates/transformDateToSecondaryType.js +20 -0
  13. package/dist/generated/assets/cldr/ar.json +5 -3
  14. package/dist/generated/assets/cldr/ar_EG.json +5 -3
  15. package/dist/generated/assets/cldr/ar_SA.json +5 -3
  16. package/dist/generated/assets/cldr/bg.json +5 -3
  17. package/dist/generated/assets/cldr/ca.json +5 -3
  18. package/dist/generated/assets/cldr/cs.json +5 -3
  19. package/dist/generated/assets/cldr/cy.json +5886 -0
  20. package/dist/generated/assets/cldr/da.json +5 -3
  21. package/dist/generated/assets/cldr/de.json +5 -3
  22. package/dist/generated/assets/cldr/de_AT.json +5 -3
  23. package/dist/generated/assets/cldr/de_CH.json +5 -3
  24. package/dist/generated/assets/cldr/el.json +5 -3
  25. package/dist/generated/assets/cldr/el_CY.json +5 -3
  26. package/dist/generated/assets/cldr/en.json +6 -3
  27. package/dist/generated/assets/cldr/en_AU.json +6 -4
  28. package/dist/generated/assets/cldr/en_GB.json +5 -3
  29. package/dist/generated/assets/cldr/en_HK.json +5 -3
  30. package/dist/generated/assets/cldr/en_IE.json +5 -3
  31. package/dist/generated/assets/cldr/en_IN.json +5 -3
  32. package/dist/generated/assets/cldr/en_NZ.json +5 -3
  33. package/dist/generated/assets/cldr/en_PG.json +5 -3
  34. package/dist/generated/assets/cldr/en_SG.json +5 -3
  35. package/dist/generated/assets/cldr/en_ZA.json +5 -3
  36. package/dist/generated/assets/cldr/es.json +5 -3
  37. package/dist/generated/assets/cldr/es_AR.json +5 -3
  38. package/dist/generated/assets/cldr/es_BO.json +5 -3
  39. package/dist/generated/assets/cldr/es_CL.json +5 -3
  40. package/dist/generated/assets/cldr/es_CO.json +5 -3
  41. package/dist/generated/assets/cldr/es_MX.json +5 -3
  42. package/dist/generated/assets/cldr/es_PE.json +5 -3
  43. package/dist/generated/assets/cldr/es_UY.json +5 -3
  44. package/dist/generated/assets/cldr/es_VE.json +5 -3
  45. package/dist/generated/assets/cldr/et.json +5 -3
  46. package/dist/generated/assets/cldr/fa.json +5 -3
  47. package/dist/generated/assets/cldr/fi.json +5 -3
  48. package/dist/generated/assets/cldr/fr.json +5 -3
  49. package/dist/generated/assets/cldr/fr_BE.json +5 -3
  50. package/dist/generated/assets/cldr/fr_CA.json +5 -3
  51. package/dist/generated/assets/cldr/fr_CH.json +5 -3
  52. package/dist/generated/assets/cldr/fr_LU.json +5 -3
  53. package/dist/generated/assets/cldr/he.json +5 -3
  54. package/dist/generated/assets/cldr/hi.json +5 -3
  55. package/dist/generated/assets/cldr/hr.json +5 -3
  56. package/dist/generated/assets/cldr/hu.json +5 -3
  57. package/dist/generated/assets/cldr/id.json +5 -3
  58. package/dist/generated/assets/cldr/it.json +5 -3
  59. package/dist/generated/assets/cldr/it_CH.json +5 -3
  60. package/dist/generated/assets/cldr/ja.json +5 -3
  61. package/dist/generated/assets/cldr/kk.json +5 -3
  62. package/dist/generated/assets/cldr/ko.json +5 -3
  63. package/dist/generated/assets/cldr/lt.json +5 -3
  64. package/dist/generated/assets/cldr/lv.json +5 -3
  65. package/dist/generated/assets/cldr/ms.json +5 -3
  66. package/dist/generated/assets/cldr/nb.json +5 -3
  67. package/dist/generated/assets/cldr/nl.json +5 -3
  68. package/dist/generated/assets/cldr/nl_BE.json +5 -3
  69. package/dist/generated/assets/cldr/pl.json +5 -3
  70. package/dist/generated/assets/cldr/pt.json +5 -3
  71. package/dist/generated/assets/cldr/pt_PT.json +5 -3
  72. package/dist/generated/assets/cldr/ro.json +5 -3
  73. package/dist/generated/assets/cldr/ru.json +5 -3
  74. package/dist/generated/assets/cldr/ru_UA.json +5 -3
  75. package/dist/generated/assets/cldr/sk.json +5 -3
  76. package/dist/generated/assets/cldr/sl.json +5 -3
  77. package/dist/generated/assets/cldr/sr.json +5 -3
  78. package/dist/generated/assets/cldr/sr_Latn.json +5129 -0
  79. package/dist/generated/assets/cldr/sv.json +5 -3
  80. package/dist/generated/assets/cldr/th.json +5 -3
  81. package/dist/generated/assets/cldr/tr.json +5 -3
  82. package/dist/generated/assets/cldr/uk.json +5 -3
  83. package/dist/generated/assets/cldr/vi.json +5 -3
  84. package/dist/generated/assets/cldr/zh_CN.json +5 -3
  85. package/dist/generated/assets/cldr/zh_HK.json +5 -3
  86. package/dist/generated/assets/cldr/zh_SG.json +5 -3
  87. package/dist/generated/assets/cldr/zh_TW.json +5 -3
  88. package/dist/generated/json-imports/LocaleData-static.js +90 -0
  89. package/dist/generated/json-imports/LocaleData.js +88 -91
  90. package/dist/sap/base/Log.js +2 -10
  91. package/dist/sap/base/assert.js +1 -5
  92. package/dist/sap/base/util/LoaderExtensions.js +12 -2
  93. package/dist/sap/base/util/array/uniqueSort.js +7 -7
  94. package/dist/sap/base/util/deepEqual.js +1 -5
  95. package/dist/sap/ui/base/Interface.js +3 -5
  96. package/dist/sap/ui/base/Metadata.js +1 -3
  97. package/dist/sap/ui/base/Object.js +26 -2
  98. package/dist/sap/ui/core/Core.js +2 -0
  99. package/dist/sap/ui/core/Locale.js +67 -31
  100. package/dist/sap/ui/core/LocaleData.js +56 -1504
  101. package/dist/sap/ui/core/date/UniversalDate.js +13 -5
  102. package/dist/sap/ui/core/format/DateFormat.js +402 -194
  103. package/dist/sap/ui/core/format/TimezoneUtil.js +83 -0
  104. package/package-scripts.js +10 -6
  105. package/package.json +12 -14
  106. package/src/Assets-static.js +2 -0
  107. package/src/dates/CalendarDate.js +7 -1
  108. package/src/dates/ExtremeDates.js +39 -0
  109. package/src/dates/convertMonthNumbersToMonthNames.js +33 -0
  110. package/src/dates/getDaysInMonth.js +11 -0
  111. package/src/dates/getRoundedTimestamp.js +14 -0
  112. package/src/dates/getTodayUTCTimestamp.js +9 -0
  113. package/src/dates/modifyDateBy.js +42 -0
  114. package/src/dates/transformDateToSecondaryType.js +20 -0
  115. package/src/sap/base/util/LoaderExtensions.js +12 -2
  116. package/src/sap/ui/core/Core.js +2 -0
  117. package/used-modules.txt +1 -0
@@ -3,6 +3,7 @@ import CalendarType from '../CalendarType.js';
3
3
  import Locale from '../Locale.js';
4
4
  import LocaleData from '../LocaleData.js';
5
5
  import UniversalDate from '../date/UniversalDate.js';
6
+ import TimezoneUtil from './TimezoneUtil.js';
6
7
  import deepEqual from '../../../base/util/deepEqual.js';
7
8
  import formatMessage from '../../../base/strings/formatMessage.js';
8
9
  import Log from '../../../base/Log.js';
@@ -10,8 +11,20 @@ import extend from '../../../base/util/extend.js';
10
11
  var DateFormat = function () {
11
12
  throw new Error();
12
13
  };
14
+ var mDateFormatTypes = {
15
+ DATE: 'date',
16
+ TIME: 'time',
17
+ DATETIME: 'datetime',
18
+ DATETIME_WITH_TIMEZONE: 'datetimeWithTimezone'
19
+ };
13
20
  var mCldrDatePattern = {};
21
+ var checkTimezoneParameterType = function (sTimezone) {
22
+ if (typeof sTimezone !== 'string' && !(sTimezone instanceof String) && sTimezone != null) {
23
+ throw new TypeError('The given timezone must be a string.');
24
+ }
25
+ };
14
26
  DateFormat.oDateInfo = {
27
+ type: mDateFormatTypes.DATE,
15
28
  oDefaultFormatOptions: {
16
29
  style: 'medium',
17
30
  relativeScale: 'day',
@@ -64,6 +77,7 @@ DateFormat.oDateInfo = {
64
77
  ]
65
78
  };
66
79
  DateFormat.oDateTimeInfo = {
80
+ type: mDateFormatTypes.DATETIME,
67
81
  oDefaultFormatOptions: {
68
82
  style: 'medium',
69
83
  relativeScale: 'auto',
@@ -126,7 +140,41 @@ DateFormat.oDateTimeInfo = {
126
140
  'Seconds'
127
141
  ]
128
142
  };
143
+ DateFormat._getDateTimeWithTimezoneInfo = function (oFormatOptions) {
144
+ var bShowDate = oFormatOptions.showDate === undefined || oFormatOptions.showDate;
145
+ var bShowTime = oFormatOptions.showTime === undefined || oFormatOptions.showTime;
146
+ var bShowTimezone = oFormatOptions.showTimezone === undefined || oFormatOptions.showTimezone;
147
+ var oBaselineType = DateFormat.oDateTimeInfo;
148
+ if (bShowDate && !bShowTime) {
149
+ oBaselineType = DateFormat.oDateInfo;
150
+ } else if (!bShowDate && bShowTime) {
151
+ oBaselineType = DateFormat.oTimeInfo;
152
+ }
153
+ return Object.assign({}, oBaselineType, {
154
+ type: mDateFormatTypes.DATETIME_WITH_TIMEZONE,
155
+ getTimezonePattern: function (sPattern) {
156
+ if (!bShowDate && !bShowTime && bShowTimezone) {
157
+ return 'VV';
158
+ } else if (!bShowTimezone) {
159
+ return sPattern;
160
+ } else {
161
+ return sPattern + ' VV';
162
+ }
163
+ },
164
+ getPattern: function (oLocaleData, sStyle, sCalendarType) {
165
+ if (!bShowDate && !bShowTime && bShowTimezone) {
166
+ return 'VV';
167
+ }
168
+ if (!bShowTimezone) {
169
+ return oBaselineType.getPattern(oLocaleData, sStyle, sCalendarType);
170
+ }
171
+ var sPattern = oBaselineType.getPattern(oLocaleData, sStyle, sCalendarType);
172
+ return oLocaleData.applyTimezonePattern(sPattern);
173
+ }
174
+ });
175
+ };
129
176
  DateFormat.oTimeInfo = {
177
+ type: mDateFormatTypes.TIME,
130
178
  oDefaultFormatOptions: {
131
179
  style: 'medium',
132
180
  relativeScale: 'auto',
@@ -179,6 +227,27 @@ DateFormat.getDateInstance = function (oFormatOptions, oLocale) {
179
227
  DateFormat.getDateTimeInstance = function (oFormatOptions, oLocale) {
180
228
  return this.createInstance(oFormatOptions, oLocale, this.oDateTimeInfo);
181
229
  };
230
+ DateFormat.getDateTimeWithTimezoneInstance = function (oFormatOptions, oLocale) {
231
+ if (oFormatOptions && !(oFormatOptions instanceof Locale)) {
232
+ oFormatOptions = Object.assign({}, oFormatOptions);
233
+ if (typeof oFormatOptions.showTimezone === 'string') {
234
+ var sShowTimezone = oFormatOptions.showTimezone;
235
+ if (oFormatOptions.showDate === undefined && oFormatOptions.showTime === undefined) {
236
+ if (sShowTimezone === 'Hide') {
237
+ oFormatOptions.showTimezone = false;
238
+ } else if (sShowTimezone === 'Only') {
239
+ oFormatOptions.showDate = false;
240
+ oFormatOptions.showTime = false;
241
+ }
242
+ }
243
+ oFormatOptions.showTimezone = sShowTimezone !== 'Hide';
244
+ }
245
+ if (oFormatOptions.showDate === false && oFormatOptions.showTime === false && oFormatOptions.showTimezone === false) {
246
+ throw new TypeError('Invalid Configuration. One of the following format options must be true: showDate, showTime or showTimezone.');
247
+ }
248
+ }
249
+ return this.createInstance(oFormatOptions, oLocale, DateFormat._getDateTimeWithTimezoneInfo(oFormatOptions || {}));
250
+ };
182
251
  DateFormat.getTimeInstance = function (oFormatOptions, oLocale) {
183
252
  return this.createInstance(oFormatOptions, oLocale, this.oTimeInfo);
184
253
  };
@@ -199,6 +268,16 @@ DateFormat.createInstance = function (oFormatOptions, oLocale, oInfo) {
199
268
  oFormat.oLocale = oLocale;
200
269
  oFormat.oLocaleData = LocaleData.getInstance(oLocale);
201
270
  oFormat.oFormatOptions = extend({}, oInfo.oDefaultFormatOptions, oFormatOptions);
271
+ if (oInfo.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
272
+ oFormat.oFormatOptions.interval = false;
273
+ oFormat.oFormatOptions.singleIntervalValue = false;
274
+ oFormat.oFormatOptions.UTC = false;
275
+ } else {
276
+ oFormat.oFormatOptions.showTimezone = undefined;
277
+ oFormat.oFormatOptions.showDate = undefined;
278
+ oFormat.oFormatOptions.showTime = undefined;
279
+ }
280
+ oFormat.type = oInfo.type;
202
281
  if (!oFormat.oFormatOptions.calendarType) {
203
282
  oFormat.oFormatOptions.calendarType = Core.getConfiguration().getCalendarType();
204
283
  }
@@ -246,7 +325,7 @@ DateFormat.createInstance = function (oFormatOptions, oLocale, oInfo) {
246
325
  if (oFormat.oFormatOptions.pattern && oInfo.bPatternFallbackWithoutDelimiter) {
247
326
  aFallbackFormatOptions = DateFormat._createFallbackOptionsWithoutDelimiter(oFormat.oFormatOptions.pattern).concat(aFallbackFormatOptions);
248
327
  }
249
- oFallbackFormats = DateFormat._createFallbackFormat(aFallbackFormatOptions, sCalendarType, oLocale, oInfo, oFormat.oFormatOptions.interval);
328
+ oFallbackFormats = DateFormat._createFallbackFormat(aFallbackFormatOptions, sCalendarType, oLocale, oInfo, oFormat.oFormatOptions);
250
329
  }
251
330
  oFormat.aFallbackFormats = oFallbackFormats;
252
331
  }
@@ -286,10 +365,16 @@ DateFormat.prototype.init = function () {
286
365
  this.aFormatArray = this.parseCldrDatePattern(this.oFormatOptions.pattern);
287
366
  this.sAllowedCharacters = this.getAllowedCharacters(this.aFormatArray);
288
367
  };
289
- DateFormat._createFallbackFormat = function (aFallbackFormatOptions, sCalendarType, oLocale, oInfo, bInterval) {
368
+ DateFormat._createFallbackFormat = function (aFallbackFormatOptions, sCalendarType, oLocale, oInfo, oParentFormatOptions) {
290
369
  return aFallbackFormatOptions.map(function (oOptions) {
291
370
  var oFormatOptions = Object.assign({}, oOptions);
292
- if (bInterval) {
371
+ oFormatOptions.showDate = oParentFormatOptions.showDate;
372
+ oFormatOptions.showTime = oParentFormatOptions.showTime;
373
+ oFormatOptions.showTimezone = oParentFormatOptions.showTimezone;
374
+ if (typeof oInfo.getTimezonePattern === 'function' && oFormatOptions.pattern) {
375
+ oFormatOptions.pattern = oInfo.getTimezonePattern(oFormatOptions.pattern);
376
+ }
377
+ if (oParentFormatOptions.interval) {
293
378
  oFormatOptions.interval = true;
294
379
  }
295
380
  oFormatOptions.calendarType = sCalendarType;
@@ -337,20 +422,35 @@ var oParseHelper = {
337
422
  }
338
423
  return sValue.substr(0, iLength);
339
424
  },
340
- findEntry: function (sValue, aList) {
425
+ startsWithIgnoreCase: function (sValue, sSubstring, sLocale) {
426
+ if (sValue.startsWith(sSubstring)) {
427
+ return true;
428
+ }
429
+ try {
430
+ var sSubToLocaleUpperCase = sSubstring.toLocaleUpperCase(sLocale);
431
+ var sValueUpperCase = sValue.toLocaleUpperCase(sLocale);
432
+ if (sSubToLocaleUpperCase.length !== sSubstring.length || sValueUpperCase.length !== sValue.length) {
433
+ return false;
434
+ }
435
+ return sValueUpperCase.startsWith(sSubToLocaleUpperCase);
436
+ } catch (e) {
437
+ return false;
438
+ }
439
+ },
440
+ findEntry: function (sValue, aList, sLocale) {
341
441
  var iFoundIndex = -1, iMatchedLength = 0;
342
442
  for (var j = 0; j < aList.length; j++) {
343
- if (aList[j] && aList[j].length > iMatchedLength && sValue.indexOf(aList[j]) === 0) {
443
+ if (aList[j] && aList[j].length > iMatchedLength && this.startsWithIgnoreCase(sValue, aList[j], sLocale)) {
344
444
  iFoundIndex = j;
345
445
  iMatchedLength = aList[j].length;
346
446
  }
347
447
  }
348
448
  return {
349
449
  index: iFoundIndex,
350
- value: iFoundIndex === -1 ? null : aList[iFoundIndex]
450
+ length: iMatchedLength
351
451
  };
352
452
  },
353
- parseTZ: function (sValue, bISO) {
453
+ parseTZ: function (sValue, bColonSeparated) {
354
454
  var iLength = 0;
355
455
  var iTZFactor = sValue.charAt(0) == '+' ? -1 : 1;
356
456
  var sPart;
@@ -358,15 +458,18 @@ var oParseHelper = {
358
458
  sPart = this.findNumbers(sValue.substr(iLength), 2);
359
459
  var iTZDiffHour = parseInt(sPart);
360
460
  iLength += 2;
361
- if (bISO) {
461
+ if (bColonSeparated) {
362
462
  iLength++;
363
463
  }
364
464
  sPart = this.findNumbers(sValue.substr(iLength), 2);
365
- iLength += 2;
366
- var iTZDiff = parseInt(sPart);
465
+ var iTZDiff = 0;
466
+ if (sPart) {
467
+ iLength += 2;
468
+ iTZDiff = parseInt(sPart);
469
+ }
367
470
  return {
368
471
  length: iLength,
369
- tzDiff: (iTZDiff + 60 * iTZDiffHour) * iTZFactor
472
+ tzDiff: (iTZDiff + 60 * iTZDiffHour) * 60 * iTZFactor
370
473
  };
371
474
  },
372
475
  checkValid: function (sType, bPartInvalid, oFormat) {
@@ -378,7 +481,7 @@ var oParseHelper = {
378
481
  DateFormat.prototype.oSymbols = {
379
482
  '': {
380
483
  name: 'text',
381
- format: function (oField, oDate, bUTC, oFormat) {
484
+ format: function (oField, oDate) {
382
485
  return oField.value;
383
486
  },
384
487
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -422,7 +525,7 @@ DateFormat.prototype.oSymbols = {
422
525
  'G': {
423
526
  name: 'era',
424
527
  format: function (oField, oDate, bUTC, oFormat) {
425
- var iEra = bUTC ? oDate.getUTCEra() : oDate.getEra();
528
+ var iEra = oDate.getUTCEra();
426
529
  if (oField.digits <= 3) {
427
530
  return oFormat.aErasAbbrev[iEra];
428
531
  } else if (oField.digits === 4) {
@@ -439,11 +542,11 @@ DateFormat.prototype.oSymbols = {
439
542
  ];
440
543
  for (var i = 0; i < aErasVariants.length; i++) {
441
544
  var aVariants = aErasVariants[i];
442
- var oFound = oParseHelper.findEntry(sValue, aVariants);
545
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
443
546
  if (oFound.index !== -1) {
444
547
  return {
445
548
  era: oFound.index,
446
- length: oFound.value.length
549
+ length: oFound.length
447
550
  };
448
551
  }
449
552
  }
@@ -456,7 +559,7 @@ DateFormat.prototype.oSymbols = {
456
559
  'y': {
457
560
  name: 'year',
458
561
  format: function (oField, oDate, bUTC, oFormat) {
459
- var iYear = bUTC ? oDate.getUTCFullYear() : oDate.getFullYear();
562
+ var iYear = oDate.getUTCFullYear();
460
563
  var sYear = String(iYear);
461
564
  var sCalendarType = oFormat.oFormatOptions.calendarType;
462
565
  if (oField.digits == 2 && sYear.length > 2) {
@@ -479,7 +582,7 @@ DateFormat.prototype.oSymbols = {
479
582
  }
480
583
  var iYear = parseInt(sPart);
481
584
  if (sCalendarType != CalendarType.Japanese && sPart.length <= 2) {
482
- var oCurrentDate = UniversalDate.getInstance(new Date(), sCalendarType), iCurrentYear = oCurrentDate.getFullYear(), iCurrentCentury = Math.floor(iCurrentYear / 100), iYearDiff = iCurrentCentury * 100 + iYear - iCurrentYear;
585
+ var oCurrentDate = UniversalDate.getInstance(new Date(), sCalendarType), iCurrentYear = oCurrentDate.getUTCFullYear(), iCurrentCentury = Math.floor(iCurrentYear / 100), iYearDiff = iCurrentCentury * 100 + iYear - iCurrentYear;
483
586
  if (iYearDiff < -70) {
484
587
  iYear += (iCurrentCentury + 1) * 100;
485
588
  } else if (iYearDiff < 30) {
@@ -498,7 +601,7 @@ DateFormat.prototype.oSymbols = {
498
601
  'Y': {
499
602
  name: 'weekYear',
500
603
  format: function (oField, oDate, bUTC, oFormat) {
501
- var oWeek = bUTC ? oDate.getUTCWeek() : oDate.getWeek();
604
+ var oWeek = oDate.getUTCWeek();
502
605
  var iWeekYear = oWeek.year;
503
606
  var sWeekYear = String(iWeekYear);
504
607
  var sCalendarType = oFormat.oFormatOptions.calendarType;
@@ -521,9 +624,9 @@ DateFormat.prototype.oSymbols = {
521
624
  sPart = oParseHelper.findNumbers(sValue, oPart.digits);
522
625
  }
523
626
  var iYear = parseInt(sPart);
524
- var iWeekYear;
627
+ var iWeekYear = iYear;
525
628
  if (sCalendarType != CalendarType.Japanese && sPart.length <= 2) {
526
- var oCurrentDate = UniversalDate.getInstance(new Date(), sCalendarType), iCurrentYear = oCurrentDate.getFullYear(), iCurrentCentury = Math.floor(iCurrentYear / 100), iYearDiff = iCurrentCentury * 100 + iWeekYear - iCurrentYear;
629
+ var oCurrentDate = UniversalDate.getInstance(new Date(), sCalendarType), iCurrentYear = oCurrentDate.getUTCFullYear(), iCurrentCentury = Math.floor(iCurrentYear / 100), iYearDiff = iCurrentCentury * 100 + iWeekYear - iCurrentYear;
527
630
  if (iYearDiff < -70) {
528
631
  iWeekYear += (iCurrentCentury + 1) * 100;
529
632
  } else if (iYearDiff < 30) {
@@ -543,7 +646,7 @@ DateFormat.prototype.oSymbols = {
543
646
  'M': {
544
647
  name: 'month',
545
648
  format: function (oField, oDate, bUTC, oFormat) {
546
- var iMonth = bUTC ? oDate.getUTCMonth() : oDate.getMonth();
649
+ var iMonth = oDate.getUTCMonth();
547
650
  if (oField.digits == 3) {
548
651
  return oFormat.aMonthsAbbrev[iMonth];
549
652
  } else if (oField.digits == 4) {
@@ -576,11 +679,11 @@ DateFormat.prototype.oSymbols = {
576
679
  } else {
577
680
  for (var i = 0; i < aMonthsVariants.length; i++) {
578
681
  var aVariants = aMonthsVariants[i];
579
- var oFound = oParseHelper.findEntry(sValue, aVariants);
682
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
580
683
  if (oFound.index !== -1) {
581
684
  return {
582
685
  month: oFound.index,
583
- length: oFound.value.length
686
+ length: oFound.length
584
687
  };
585
688
  }
586
689
  }
@@ -596,7 +699,7 @@ DateFormat.prototype.oSymbols = {
596
699
  'L': {
597
700
  name: 'monthStandalone',
598
701
  format: function (oField, oDate, bUTC, oFormat) {
599
- var iMonth = bUTC ? oDate.getUTCMonth() : oDate.getMonth();
702
+ var iMonth = oDate.getUTCMonth();
600
703
  if (oField.digits == 3) {
601
704
  return oFormat.aMonthsAbbrevSt[iMonth];
602
705
  } else if (oField.digits == 4) {
@@ -629,11 +732,11 @@ DateFormat.prototype.oSymbols = {
629
732
  } else {
630
733
  for (var i = 0; i < aMonthsVariants.length; i++) {
631
734
  var aVariants = aMonthsVariants[i];
632
- var oFound = oParseHelper.findEntry(sValue, aVariants);
735
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
633
736
  if (oFound.index !== -1) {
634
737
  return {
635
738
  month: oFound.index,
636
- length: oFound.value.length
739
+ length: oFound.length
637
740
  };
638
741
  }
639
742
  }
@@ -649,7 +752,7 @@ DateFormat.prototype.oSymbols = {
649
752
  'w': {
650
753
  name: 'weekInYear',
651
754
  format: function (oField, oDate, bUTC, oFormat) {
652
- var oWeek = bUTC ? oDate.getUTCWeek() : oDate.getWeek();
755
+ var oWeek = oDate.getUTCWeek();
653
756
  var iWeek = oWeek.week;
654
757
  var sWeek = String(iWeek + 1);
655
758
  if (oField.digits < 3) {
@@ -671,11 +774,11 @@ DateFormat.prototype.oSymbols = {
671
774
  bValid = oParseHelper.checkValid(oPart.type, !sPart, oFormat);
672
775
  } else {
673
776
  sPart = oFormat.oLocaleData.getCalendarWeek(oPart.digits === 3 ? 'narrow' : 'wide');
674
- sPart = sPart.replace('{0}', '[0-9]+');
777
+ sPart = sPart.replace('{0}', '([0-9]+)');
675
778
  var rWeekNumber = new RegExp(sPart), oResult = rWeekNumber.exec(sValue);
676
779
  if (oResult) {
677
780
  iLength = oResult[0].length;
678
- iWeek = parseInt(oResult[0]) - 1;
781
+ iWeek = parseInt(oResult[oResult.length - 1]) - 1;
679
782
  } else {
680
783
  bValid = oParseHelper.checkValid(oPart.type, true, oFormat);
681
784
  }
@@ -689,7 +792,7 @@ DateFormat.prototype.oSymbols = {
689
792
  },
690
793
  'W': {
691
794
  name: 'weekInMonth',
692
- format: function (oField, oDate, bUTC, oFormat) {
795
+ format: function (oField, oDate) {
693
796
  return '';
694
797
  },
695
798
  parse: function () {
@@ -698,7 +801,7 @@ DateFormat.prototype.oSymbols = {
698
801
  },
699
802
  'D': {
700
803
  name: 'dayInYear',
701
- format: function (oField, oDate, bUTC, oFormat) {
804
+ format: function (oField, oDate) {
702
805
  },
703
806
  parse: function () {
704
807
  return {};
@@ -706,8 +809,8 @@ DateFormat.prototype.oSymbols = {
706
809
  },
707
810
  'd': {
708
811
  name: 'day',
709
- format: function (oField, oDate, bUTC, oFormat) {
710
- var iDate = bUTC ? oDate.getUTCDate() : oDate.getDate();
812
+ format: function (oField, oDate) {
813
+ var iDate = oDate.getUTCDate();
711
814
  return String(iDate).padStart(oField.digits, '0');
712
815
  },
713
816
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -727,7 +830,7 @@ DateFormat.prototype.oSymbols = {
727
830
  'Q': {
728
831
  name: 'quarter',
729
832
  format: function (oField, oDate, bUTC, oFormat) {
730
- var iQuarter = bUTC ? oDate.getUTCQuarter() : oDate.getQuarter();
833
+ var iQuarter = oDate.getUTCQuarter();
731
834
  if (oField.digits == 3) {
732
835
  return oFormat.aQuartersAbbrev[iQuarter];
733
836
  } else if (oField.digits == 4) {
@@ -760,11 +863,11 @@ DateFormat.prototype.oSymbols = {
760
863
  } else {
761
864
  for (var i = 0; i < aQuartersVariants.length; i++) {
762
865
  var aVariants = aQuartersVariants[i];
763
- var oFound = oParseHelper.findEntry(sValue, aVariants);
866
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
764
867
  if (oFound.index !== -1) {
765
868
  return {
766
869
  quarter: oFound.index,
767
- length: oFound.value.length
870
+ length: oFound.length
768
871
  };
769
872
  }
770
873
  }
@@ -780,7 +883,7 @@ DateFormat.prototype.oSymbols = {
780
883
  'q': {
781
884
  name: 'quarterStandalone',
782
885
  format: function (oField, oDate, bUTC, oFormat) {
783
- var iQuarter = bUTC ? oDate.getUTCQuarter() : oDate.getQuarter();
886
+ var iQuarter = oDate.getUTCQuarter();
784
887
  if (oField.digits == 3) {
785
888
  return oFormat.aQuartersAbbrevSt[iQuarter];
786
889
  } else if (oField.digits == 4) {
@@ -813,11 +916,11 @@ DateFormat.prototype.oSymbols = {
813
916
  } else {
814
917
  for (var i = 0; i < aQuartersVariants.length; i++) {
815
918
  var aVariants = aQuartersVariants[i];
816
- var oFound = oParseHelper.findEntry(sValue, aVariants);
919
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
817
920
  if (oFound.index !== -1) {
818
921
  return {
819
922
  quarter: oFound.index,
820
- length: oFound.value.length
923
+ length: oFound.length
821
924
  };
822
925
  }
823
926
  }
@@ -832,7 +935,7 @@ DateFormat.prototype.oSymbols = {
832
935
  },
833
936
  'F': {
834
937
  name: 'dayOfWeekInMonth',
835
- format: function (oField, oDate, bUTC, oFormat) {
938
+ format: function (oField, oDate, oFormat) {
836
939
  return '';
837
940
  },
838
941
  parse: function () {
@@ -842,7 +945,7 @@ DateFormat.prototype.oSymbols = {
842
945
  'E': {
843
946
  name: 'dayNameInWeek',
844
947
  format: function (oField, oDate, bUTC, oFormat) {
845
- var iDay = bUTC ? oDate.getUTCDay() : oDate.getDay();
948
+ var iDay = oDate.getUTCDay();
846
949
  if (oField.digits < 4) {
847
950
  return oFormat.aDaysAbbrev[iDay];
848
951
  } else if (oField.digits == 4) {
@@ -866,11 +969,11 @@ DateFormat.prototype.oSymbols = {
866
969
  ];
867
970
  for (var i = 0; i < aDaysVariants.length; i++) {
868
971
  var aVariants = aDaysVariants[i];
869
- var oFound = oParseHelper.findEntry(sValue, aVariants);
972
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
870
973
  if (oFound.index !== -1) {
871
974
  return {
872
975
  dayOfWeek: oFound.index,
873
- length: oFound.value.length
976
+ length: oFound.length
874
977
  };
875
978
  }
876
979
  }
@@ -879,7 +982,7 @@ DateFormat.prototype.oSymbols = {
879
982
  'c': {
880
983
  name: 'dayNameInWeekStandalone',
881
984
  format: function (oField, oDate, bUTC, oFormat) {
882
- var iDay = bUTC ? oDate.getUTCDay() : oDate.getDay();
985
+ var iDay = oDate.getUTCDay();
883
986
  if (oField.digits < 4) {
884
987
  return oFormat.aDaysAbbrevSt[iDay];
885
988
  } else if (oField.digits == 4) {
@@ -903,11 +1006,11 @@ DateFormat.prototype.oSymbols = {
903
1006
  ];
904
1007
  for (var i = 0; i < aDaysVariants.length; i++) {
905
1008
  var aVariants = aDaysVariants[i];
906
- var oFound = oParseHelper.findEntry(sValue, aVariants);
1009
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
907
1010
  if (oFound.index !== -1) {
908
1011
  return {
909
1012
  day: oFound.index,
910
- length: oFound.value.length
1013
+ length: oFound.length
911
1014
  };
912
1015
  }
913
1016
  }
@@ -916,7 +1019,7 @@ DateFormat.prototype.oSymbols = {
916
1019
  'u': {
917
1020
  name: 'dayNumberOfWeek',
918
1021
  format: function (oField, oDate, bUTC, oFormat) {
919
- var iDay = bUTC ? oDate.getUTCDay() : oDate.getDay();
1022
+ var iDay = oDate.getUTCDay();
920
1023
  return oFormat._adaptDayOfWeek(iDay);
921
1024
  },
922
1025
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -930,20 +1033,24 @@ DateFormat.prototype.oSymbols = {
930
1033
  'a': {
931
1034
  name: 'amPmMarker',
932
1035
  format: function (oField, oDate, bUTC, oFormat) {
933
- var iDayPeriod = bUTC ? oDate.getUTCDayPeriod() : oDate.getDayPeriod();
1036
+ var iDayPeriod = oDate.getUTCDayPeriod();
934
1037
  return oFormat.aDayPeriods[iDayPeriod];
935
1038
  },
936
1039
  parse: function (sValue, oPart, oFormat, oConfig) {
937
1040
  var bPM;
938
1041
  var iLength;
939
1042
  var sAM = oFormat.aDayPeriods[0], sPM = oFormat.aDayPeriods[1];
940
- var rAMPM = /[aApP](?:\.)?[mM](?:\.)?/;
1043
+ var rAMPM = /[aApP](?:\.)?[\x20\xA0]?[mM](?:\.)?/;
941
1044
  var aMatch = sValue.match(rAMPM);
942
1045
  var bVariant = aMatch && aMatch.index === 0;
943
1046
  if (bVariant) {
944
- sValue = aMatch[0].replace(/\./g, '').toLowerCase() + sValue.substring(aMatch[0].length);
1047
+ sValue = aMatch[0];
1048
+ sAM = sAM.replace(/[\x20\xA0]/g, '');
1049
+ sPM = sPM.replace(/[\x20\xA0]/g, '');
1050
+ sValue = sValue.replace(/[\x20\xA0]/g, '');
945
1051
  sAM = sAM.replace(/\./g, '').toLowerCase();
946
1052
  sPM = sPM.replace(/\./g, '').toLowerCase();
1053
+ sValue = sValue.replace(/\./g, '').toLowerCase();
947
1054
  }
948
1055
  if (sValue.indexOf(sAM) === 0) {
949
1056
  bPM = false;
@@ -960,8 +1067,8 @@ DateFormat.prototype.oSymbols = {
960
1067
  },
961
1068
  'H': {
962
1069
  name: 'hour0_23',
963
- format: function (oField, oDate, bUTC, oFormat) {
964
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1070
+ format: function (oField, oDate) {
1071
+ var iHours = oDate.getUTCHours();
965
1072
  return String(iHours).padStart(oField.digits, '0');
966
1073
  },
967
1074
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -981,8 +1088,8 @@ DateFormat.prototype.oSymbols = {
981
1088
  },
982
1089
  'k': {
983
1090
  name: 'hour1_24',
984
- format: function (oField, oDate, bUTC, oFormat) {
985
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1091
+ format: function (oField, oDate) {
1092
+ var iHours = oDate.getUTCHours();
986
1093
  var sHours = iHours === 0 ? '24' : String(iHours);
987
1094
  return sHours.padStart(oField.digits, '0');
988
1095
  },
@@ -1006,8 +1113,8 @@ DateFormat.prototype.oSymbols = {
1006
1113
  },
1007
1114
  'K': {
1008
1115
  name: 'hour0_11',
1009
- format: function (oField, oDate, bUTC, oFormat) {
1010
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1116
+ format: function (oField, oDate) {
1117
+ var iHours = oDate.getUTCHours();
1011
1118
  var sHours = String(iHours > 11 ? iHours - 12 : iHours);
1012
1119
  return sHours.padStart(oField.digits, '0');
1013
1120
  },
@@ -1028,8 +1135,8 @@ DateFormat.prototype.oSymbols = {
1028
1135
  },
1029
1136
  'h': {
1030
1137
  name: 'hour1_12',
1031
- format: function (oField, oDate, bUTC, oFormat) {
1032
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1138
+ format: function (oField, oDate) {
1139
+ var iHours = oDate.getUTCHours();
1033
1140
  var sHours;
1034
1141
  if (iHours > 12) {
1035
1142
  sHours = String(iHours - 12);
@@ -1062,8 +1169,8 @@ DateFormat.prototype.oSymbols = {
1062
1169
  },
1063
1170
  'm': {
1064
1171
  name: 'minute',
1065
- format: function (oField, oDate, bUTC, oFormat) {
1066
- var iMinutes = bUTC ? oDate.getUTCMinutes() : oDate.getMinutes();
1172
+ format: function (oField, oDate) {
1173
+ var iMinutes = oDate.getUTCMinutes();
1067
1174
  return String(iMinutes).padStart(oField.digits, '0');
1068
1175
  },
1069
1176
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -1083,8 +1190,8 @@ DateFormat.prototype.oSymbols = {
1083
1190
  },
1084
1191
  's': {
1085
1192
  name: 'second',
1086
- format: function (oField, oDate, bUTC, oFormat) {
1087
- var iSeconds = bUTC ? oDate.getUTCSeconds() : oDate.getSeconds();
1193
+ format: function (oField, oDate) {
1194
+ var iSeconds = oDate.getUTCSeconds();
1088
1195
  return String(iSeconds).padStart(oField.digits, '0');
1089
1196
  },
1090
1197
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -1104,8 +1211,8 @@ DateFormat.prototype.oSymbols = {
1104
1211
  },
1105
1212
  'S': {
1106
1213
  name: 'fractionalsecond',
1107
- format: function (oField, oDate, bUTC, oFormat) {
1108
- var iMilliseconds = bUTC ? oDate.getUTCMilliseconds() : oDate.getMilliseconds();
1214
+ format: function (oField, oDate) {
1215
+ var iMilliseconds = oDate.getUTCMilliseconds();
1109
1216
  var sMilliseconds = String(iMilliseconds);
1110
1217
  var sFractionalseconds = sMilliseconds.padStart(3, '0');
1111
1218
  sFractionalseconds = sFractionalseconds.substr(0, oField.digits);
@@ -1126,17 +1233,18 @@ DateFormat.prototype.oSymbols = {
1126
1233
  },
1127
1234
  'z': {
1128
1235
  name: 'timezoneGeneral',
1129
- format: function (oField, oDate, bUTC, oFormat) {
1130
- if (oField.digits > 3 && oDate.getTimezoneLong()) {
1236
+ format: function (oField, oDate, bUTC, oFormat, sTimezone) {
1237
+ if (oField.digits > 3 && oDate.getTimezoneLong && oDate.getTimezoneLong()) {
1131
1238
  return oDate.getTimezoneLong();
1132
- } else if (oDate.getTimezoneShort()) {
1239
+ } else if (oDate.getTimezoneShort && oDate.getTimezoneShort()) {
1133
1240
  return oDate.getTimezoneShort();
1134
1241
  }
1242
+ var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
1135
1243
  var sTimeZone = 'GMT';
1136
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1137
- var bPositiveOffset = oDate.getTimezoneOffset() > 0;
1244
+ var iTZOffset = Math.abs(iTimezoneOffset / 60);
1245
+ var bPositiveOffset = iTimezoneOffset > 0;
1138
1246
  var iHourOffset = Math.floor(iTZOffset / 60);
1139
- var iMinuteOffset = iTZOffset % 60;
1247
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1140
1248
  if (!bUTC && iTZOffset != 0) {
1141
1249
  sTimeZone += bPositiveOffset ? '-' : '+';
1142
1250
  sTimeZone += String(iHourOffset).padStart(2, '0');
@@ -1155,13 +1263,13 @@ DateFormat.prototype.oSymbols = {
1155
1263
  iLength = 3;
1156
1264
  } else if (sValue.substring(0, 2) === 'UT') {
1157
1265
  iLength = 2;
1158
- } else if (sValue.charAt(0) == 'Z') {
1266
+ } else if (sValue.charAt(0) === 'Z') {
1159
1267
  iLength = 1;
1160
1268
  iTZDiff = 0;
1161
1269
  } else {
1162
- return { error: 'cannot be parsed correcly by sap.ui.core.format.DateFormat: The given timezone is not supported!' };
1270
+ return { error: 'cannot be parsed correctly by sap.ui.core.format.DateFormat: The given timezone is not supported!' };
1163
1271
  }
1164
- if (sValue.charAt(0) != 'Z') {
1272
+ if (sValue.charAt(0) !== 'Z') {
1165
1273
  var oParsedTZ = oParseHelper.parseTZ(sValue.substr(iLength), true);
1166
1274
  iLength += oParsedTZ.length;
1167
1275
  iTZDiff = oParsedTZ.tzDiff;
@@ -1174,13 +1282,14 @@ DateFormat.prototype.oSymbols = {
1174
1282
  },
1175
1283
  'Z': {
1176
1284
  name: 'timezoneRFC822',
1177
- format: function (oField, oDate, bUTC, oFormat) {
1178
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1179
- var bPositiveOffset = oDate.getTimezoneOffset() > 0;
1285
+ format: function (oField, oDate, bUTC, oFormat, sTimezone) {
1286
+ var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
1287
+ var iTZOffset = Math.abs(iTimezoneOffset / 60);
1288
+ var bPositiveOffset = iTimezoneOffset > 0;
1180
1289
  var iHourOffset = Math.floor(iTZOffset / 60);
1181
- var iMinuteOffset = iTZOffset % 60;
1290
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1182
1291
  var sTimeZone = '';
1183
- if (!bUTC && iTZOffset != 0) {
1292
+ if (!bUTC) {
1184
1293
  sTimeZone += bPositiveOffset ? '-' : '+';
1185
1294
  sTimeZone += String(iHourOffset).padStart(2, '0');
1186
1295
  sTimeZone += String(iMinuteOffset).padStart(2, '0');
@@ -1193,37 +1302,74 @@ DateFormat.prototype.oSymbols = {
1193
1302
  },
1194
1303
  'X': {
1195
1304
  name: 'timezoneISO8601',
1196
- format: function (oField, oDate, bUTC, oFormat) {
1197
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1198
- var bPositiveOffset = oDate.getTimezoneOffset() > 0;
1305
+ format: function (oField, oDate, bUTC, oFormat, sTimezone) {
1306
+ var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
1307
+ var iTZOffset = Math.abs(iTimezoneOffset / 60);
1308
+ var bPositiveOffset = iTimezoneOffset > 0;
1199
1309
  var iHourOffset = Math.floor(iTZOffset / 60);
1200
- var iMinuteOffset = iTZOffset % 60;
1310
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1201
1311
  var sTimeZone = '';
1202
1312
  if (!bUTC && iTZOffset != 0) {
1203
1313
  sTimeZone += bPositiveOffset ? '-' : '+';
1204
1314
  sTimeZone += String(iHourOffset).padStart(2, '0');
1205
- sTimeZone += ':';
1206
- sTimeZone += String(iMinuteOffset).padStart(2, '0');
1315
+ if (oField.digits > 1 || iMinuteOffset > 0) {
1316
+ if (oField.digits === 3 || oField.digits === 5) {
1317
+ sTimeZone += ':';
1318
+ }
1319
+ sTimeZone += String(iMinuteOffset).padStart(2, '0');
1320
+ }
1207
1321
  } else {
1208
1322
  sTimeZone += 'Z';
1209
1323
  }
1210
1324
  return sTimeZone;
1211
1325
  },
1212
1326
  parse: function (sValue, oPart, oFormat, oConfig) {
1213
- if (sValue.charAt(0) == 'Z') {
1327
+ if (sValue.charAt(0) === 'Z') {
1214
1328
  return {
1215
1329
  length: 1,
1216
1330
  tzDiff: 0
1217
1331
  };
1218
1332
  } else {
1219
- return oParseHelper.parseTZ(sValue, true);
1333
+ return oParseHelper.parseTZ(sValue, oPart.digits === 3 || oPart.digits === 5);
1334
+ }
1335
+ }
1336
+ },
1337
+ 'V': {
1338
+ name: 'timezoneID',
1339
+ format: function (oField, oDate, bUTC, oFormat, sTimezone) {
1340
+ if (!bUTC && oField.digits === 2) {
1341
+ return sTimezone;
1342
+ }
1343
+ return '';
1344
+ },
1345
+ parse: function (sValue, oPart, oFormat, oConfig, sTimezone) {
1346
+ var oTimezoneParsed = {
1347
+ timezone: '',
1348
+ length: 0
1349
+ };
1350
+ if (oPart.digits === 2) {
1351
+ if (sValue === sTimezone) {
1352
+ oTimezoneParsed.timezone = sTimezone;
1353
+ oTimezoneParsed.length = sTimezone.length;
1354
+ return oTimezoneParsed;
1355
+ }
1356
+ if (sValue) {
1357
+ var rIanaTimezone = new RegExp('([A-Za-z_])+([/][A-Za-z_]+)+');
1358
+ var aResult = rIanaTimezone.exec(sValue);
1359
+ if (aResult && aResult[0] && TimezoneUtil.isValidTimezone(aResult[0])) {
1360
+ oTimezoneParsed.timezone = aResult[0];
1361
+ oTimezoneParsed.length = aResult[0].length;
1362
+ return oTimezoneParsed;
1363
+ }
1364
+ }
1220
1365
  }
1366
+ return oTimezoneParsed;
1221
1367
  }
1222
1368
  }
1223
1369
  };
1224
- DateFormat.prototype._format = function (oJSDate, bUTC) {
1370
+ DateFormat.prototype._format = function (oJSDate, bUTC, sTimezone) {
1225
1371
  if (this.oFormatOptions.relative) {
1226
- var sRes = this.formatRelative(oJSDate, bUTC, this.oFormatOptions.relativeRange);
1372
+ var sRes = this.formatRelative(oJSDate, bUTC, this.oFormatOptions.relativeRange, sTimezone);
1227
1373
  if (sRes) {
1228
1374
  return sRes;
1229
1375
  }
@@ -1234,7 +1380,7 @@ DateFormat.prototype._format = function (oJSDate, bUTC) {
1234
1380
  for (var i = 0; i < this.aFormatArray.length; i++) {
1235
1381
  oPart = this.aFormatArray[i];
1236
1382
  sSymbol = oPart.symbol || '';
1237
- aBuffer.push(this.oSymbols[sSymbol].format(oPart, oDate, bUTC, this));
1383
+ aBuffer.push(this.oSymbols[sSymbol].format(oPart, oDate, bUTC, this, sTimezone));
1238
1384
  }
1239
1385
  sResult = aBuffer.join('');
1240
1386
  if (Core.getConfiguration().getOriginInfo()) {
@@ -1249,10 +1395,21 @@ DateFormat.prototype._format = function (oJSDate, bUTC) {
1249
1395
  return sResult;
1250
1396
  };
1251
1397
  DateFormat.prototype.format = function (vJSDate, bUTC) {
1398
+ var sTimezone;
1399
+ if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1400
+ sTimezone = bUTC;
1401
+ bUTC = false;
1402
+ checkTimezoneParameterType(sTimezone);
1403
+ if (sTimezone && !TimezoneUtil.isValidTimezone(sTimezone)) {
1404
+ Log.error('The given timezone isn\'t valid.');
1405
+ return '';
1406
+ }
1407
+ }
1252
1408
  var sCalendarType = this.oFormatOptions.calendarType, sResult;
1253
1409
  if (bUTC === undefined) {
1254
1410
  bUTC = this.oFormatOptions.UTC;
1255
1411
  }
1412
+ sTimezone = sTimezone || Core.getConfiguration().getTimezone();
1256
1413
  if (Array.isArray(vJSDate)) {
1257
1414
  if (!this.oFormatOptions.interval) {
1258
1415
  Log.error('Non-interval DateFormat can\'t format more than one date instance.');
@@ -1262,27 +1419,30 @@ DateFormat.prototype.format = function (vJSDate, bUTC) {
1262
1419
  Log.error('Interval DateFormat can only format with 2 date instances but ' + vJSDate.length + ' is given.');
1263
1420
  return '';
1264
1421
  }
1422
+ vJSDate = vJSDate.map(function (oJSDate) {
1423
+ return convertToTimezone(oJSDate, sTimezone, bUTC);
1424
+ });
1265
1425
  if (this.oFormatOptions.singleIntervalValue) {
1266
1426
  if (vJSDate[0] === null) {
1267
1427
  Log.error('First date instance which is passed to the interval DateFormat shouldn\'t be null.');
1268
1428
  return '';
1269
1429
  }
1270
1430
  if (vJSDate[1] === null) {
1271
- sResult = this._format(vJSDate[0], bUTC);
1431
+ sResult = this._format(vJSDate[0], bUTC, sTimezone);
1272
1432
  }
1273
1433
  }
1274
1434
  if (sResult === undefined) {
1275
- var bValid = vJSDate.every(function (oJSDate) {
1276
- return oJSDate && !isNaN(oJSDate.getTime());
1277
- });
1278
- if (!bValid) {
1435
+ if (!vJSDate.every(isValidDateObject)) {
1279
1436
  Log.error('At least one date instance which is passed to the interval DateFormat isn\'t valid.');
1280
1437
  return '';
1281
1438
  }
1282
1439
  sResult = this._formatInterval(vJSDate, bUTC);
1283
1440
  }
1284
1441
  } else {
1285
- if (!vJSDate || isNaN(vJSDate.getTime())) {
1442
+ if (!isValidDateObject(vJSDate)) {
1443
+ if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE && this.oFormatOptions.pattern.includes('VV')) {
1444
+ return sTimezone;
1445
+ }
1286
1446
  Log.error('The given date instance isn\'t valid.');
1287
1447
  return '';
1288
1448
  }
@@ -1290,7 +1450,8 @@ DateFormat.prototype.format = function (vJSDate, bUTC) {
1290
1450
  Log.error('Interval DateFormat expects an array with two dates for the first argument but only one date is given.');
1291
1451
  return '';
1292
1452
  }
1293
- sResult = this._format(vJSDate, bUTC);
1453
+ vJSDate = convertToTimezone(vJSDate, sTimezone, bUTC);
1454
+ sResult = this._format(vJSDate, bUTC, sTimezone);
1294
1455
  }
1295
1456
  if (sCalendarType == CalendarType.Japanese && this.oLocale.getLanguage() === 'ja') {
1296
1457
  sResult = sResult.replace(/(^|[^\d])1年/g, '$1元年');
@@ -1310,7 +1471,7 @@ DateFormat.prototype._formatInterval = function (aJSDates, bUTC) {
1310
1471
  var oDiffField = this._getGreatestDiffField([
1311
1472
  oFromDate,
1312
1473
  oToDate
1313
- ], bUTC);
1474
+ ]);
1314
1475
  if (!oDiffField) {
1315
1476
  return this._format(aJSDates[0], bUTC);
1316
1477
  }
@@ -1343,10 +1504,10 @@ var mFieldToGroup = {
1343
1504
  Minutes: 'Minute',
1344
1505
  Seconds: 'Second'
1345
1506
  };
1346
- DateFormat.prototype._getGreatestDiffField = function (aDates, bUTC) {
1507
+ DateFormat.prototype._getGreatestDiffField = function (aDates) {
1347
1508
  var bDiffFound = false, mDiff = {};
1348
1509
  this.aIntervalCompareFields.forEach(function (sField) {
1349
- 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]);
1510
+ var sGetterPrefix = 'getUTC', sMethodName = sGetterPrefix + sField, sFieldGroup = mFieldToGroup[sField], vFromValue = aDates[0][sMethodName].apply(aDates[0]), vToValue = aDates[1][sMethodName].apply(aDates[1]);
1350
1511
  if (!deepEqual(vFromValue, vToValue)) {
1351
1512
  bDiffFound = true;
1352
1513
  mDiff[sFieldGroup] = true;
@@ -1357,9 +1518,12 @@ DateFormat.prototype._getGreatestDiffField = function (aDates, bUTC) {
1357
1518
  }
1358
1519
  return null;
1359
1520
  };
1360
- DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1521
+ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict, sTimezone) {
1361
1522
  var iIndex = 0, oPart, sSubValue, oResult;
1362
- var oDateValue = { valid: true };
1523
+ var oDateValue = {
1524
+ valid: true,
1525
+ lastTimezonePatternSymbol: ''
1526
+ };
1363
1527
  var oParseConf = {
1364
1528
  formatArray: aFormatArray,
1365
1529
  dateValue: oDateValue,
@@ -1369,7 +1533,10 @@ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1369
1533
  sSubValue = sValue.substr(iIndex);
1370
1534
  oPart = aFormatArray[i];
1371
1535
  oParseConf.index = i;
1372
- oResult = this.oSymbols[oPart.symbol || ''].parse(sSubValue, oPart, this, oParseConf) || {};
1536
+ oResult = this.oSymbols[oPart.symbol || ''].parse(sSubValue, oPart, this, oParseConf, sTimezone) || {};
1537
+ if (oResult.tzDiff !== undefined || oResult.timezone) {
1538
+ oResult.lastTimezonePatternSymbol = oPart.symbol;
1539
+ }
1373
1540
  oDateValue = extend(oDateValue, oResult);
1374
1541
  if (oResult.valid === false) {
1375
1542
  break;
@@ -1389,7 +1556,7 @@ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1389
1556
  }
1390
1557
  return oDateValue;
1391
1558
  };
1392
- DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bStrict) {
1559
+ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bStrict, sTimezone) {
1393
1560
  var aDateValues, iRepeat, oDateValue;
1394
1561
  this.intervalPatterns.some(function (sPattern) {
1395
1562
  var aFormatArray = this.parseCldrDatePattern(sPattern);
@@ -1401,7 +1568,7 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1401
1568
  }
1402
1569
  }
1403
1570
  if (iRepeat === undefined) {
1404
- oDateValue = this._parse(sValue, aFormatArray, bUTC, bStrict);
1571
+ oDateValue = this._parse(sValue, aFormatArray, bUTC, bStrict, sTimezone);
1405
1572
  if (oDateValue.index === 0 || oDateValue.index < sValue.length) {
1406
1573
  oDateValue.valid = false;
1407
1574
  }
@@ -1415,13 +1582,13 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1415
1582
  return true;
1416
1583
  } else {
1417
1584
  aDateValues = [];
1418
- oDateValue = this._parse(sValue, aFormatArray.slice(0, iRepeat), bUTC, bStrict);
1585
+ oDateValue = this._parse(sValue, aFormatArray.slice(0, iRepeat), bUTC, bStrict, sTimezone);
1419
1586
  if (oDateValue.valid === false) {
1420
1587
  return;
1421
1588
  }
1422
1589
  aDateValues.push(oDateValue);
1423
1590
  var iLength = oDateValue.index;
1424
- oDateValue = this._parse(sValue.substring(iLength), aFormatArray.slice(iRepeat), bUTC, bStrict);
1591
+ oDateValue = this._parse(sValue.substring(iLength), aFormatArray.slice(iRepeat), bUTC, bStrict, sTimezone);
1425
1592
  if (oDateValue.index === 0 || oDateValue.index + iLength < sValue.length) {
1426
1593
  oDateValue.valid = false;
1427
1594
  }
@@ -1434,65 +1601,51 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1434
1601
  }.bind(this));
1435
1602
  return aDateValues;
1436
1603
  };
1437
- var fnCreateDate = function (oDateValue, sCalendarType, bUTC, bStrict) {
1604
+ var convertToTimezone = function (oJSDate, sTimezone, bUTC) {
1605
+ if (!bUTC && isValidDateObject(oJSDate)) {
1606
+ return TimezoneUtil.convertToTimezone(oJSDate, sTimezone);
1607
+ }
1608
+ return oJSDate;
1609
+ };
1610
+ var fnCreateDate = function (oDateValue, sCalendarType, bUTC, bStrict, sTimezone) {
1611
+ if (!oDateValue.valid) {
1612
+ return null;
1613
+ }
1438
1614
  var oDate, iYear = typeof oDateValue.year === 'number' ? oDateValue.year : 1970;
1439
- if (oDateValue.valid) {
1440
- if (bUTC || oDateValue.tzDiff !== undefined) {
1441
- oDate = UniversalDate.getInstance(new Date(0), sCalendarType);
1442
- oDate.setUTCEra(oDateValue.era || UniversalDate.getCurrentEra(sCalendarType));
1443
- oDate.setUTCFullYear(iYear);
1444
- oDate.setUTCMonth(oDateValue.month || 0);
1445
- oDate.setUTCDate(oDateValue.day || 1);
1446
- oDate.setUTCHours(oDateValue.hour || 0);
1447
- oDate.setUTCMinutes(oDateValue.minute || 0);
1448
- oDate.setUTCSeconds(oDateValue.second || 0);
1449
- oDate.setUTCMilliseconds(oDateValue.millisecond || 0);
1450
- if (bStrict && (oDateValue.day || 1) !== oDate.getUTCDate()) {
1451
- oDateValue.valid = false;
1452
- oDate = undefined;
1453
- } else {
1454
- if (oDateValue.tzDiff) {
1455
- oDate.setUTCMinutes((oDateValue.minute || 0) + oDateValue.tzDiff);
1456
- }
1457
- if (oDateValue.week !== undefined && (oDateValue.month === undefined || oDateValue.day === undefined)) {
1458
- oDate.setUTCWeek({
1459
- year: oDateValue.weekYear || oDateValue.year,
1460
- week: oDateValue.week
1461
- });
1462
- if (oDateValue.dayNumberOfWeek !== undefined) {
1463
- oDate.setUTCDate(oDate.getUTCDate() + oDateValue.dayNumberOfWeek - 1);
1464
- }
1465
- }
1466
- }
1467
- } else {
1468
- oDate = UniversalDate.getInstance(new Date(1970, 0, 1, 0, 0, 0), sCalendarType);
1469
- oDate.setEra(oDateValue.era || UniversalDate.getCurrentEra(sCalendarType));
1470
- oDate.setFullYear(iYear);
1471
- oDate.setMonth(oDateValue.month || 0);
1472
- oDate.setDate(oDateValue.day || 1);
1473
- oDate.setHours(oDateValue.hour || 0);
1474
- oDate.setMinutes(oDateValue.minute || 0);
1475
- oDate.setSeconds(oDateValue.second || 0);
1476
- oDate.setMilliseconds(oDateValue.millisecond || 0);
1477
- if (bStrict && (oDateValue.day || 1) !== oDate.getDate()) {
1478
- oDateValue.valid = false;
1479
- oDate = undefined;
1480
- } else if (oDateValue.week !== undefined && (oDateValue.month === undefined || oDateValue.day === undefined)) {
1481
- oDate.setWeek({
1482
- year: oDateValue.weekYear || oDateValue.year,
1483
- week: oDateValue.week
1484
- });
1485
- if (oDateValue.dayNumberOfWeek !== undefined) {
1486
- oDate.setDate(oDate.getDate() + oDateValue.dayNumberOfWeek - 1);
1487
- }
1488
- }
1615
+ oDate = UniversalDate.getInstance(new Date(0), sCalendarType);
1616
+ oDate.setUTCEra(oDateValue.era || UniversalDate.getCurrentEra(sCalendarType));
1617
+ oDate.setUTCFullYear(iYear);
1618
+ oDate.setUTCMonth(oDateValue.month || 0);
1619
+ oDate.setUTCDate(oDateValue.day || 1);
1620
+ oDate.setUTCHours(oDateValue.hour || 0);
1621
+ oDate.setUTCMinutes(oDateValue.minute || 0);
1622
+ oDate.setUTCSeconds(oDateValue.second || 0);
1623
+ oDate.setUTCMilliseconds(oDateValue.millisecond || 0);
1624
+ if (bStrict && (oDateValue.day || 1) !== oDate.getUTCDate()) {
1625
+ return null;
1626
+ }
1627
+ if (oDateValue.week !== undefined && (oDateValue.month === undefined || oDateValue.day === undefined)) {
1628
+ oDate.setUTCWeek({
1629
+ year: oDateValue.weekYear || oDateValue.year,
1630
+ week: oDateValue.week
1631
+ });
1632
+ if (oDateValue.dayNumberOfWeek !== undefined) {
1633
+ oDate.setUTCDate(oDate.getUTCDate() + oDateValue.dayNumberOfWeek - 1);
1489
1634
  }
1490
- if (oDateValue.valid) {
1491
- oDate = oDate.getJSDate();
1492
- return oDate;
1635
+ }
1636
+ oDate = oDate.getJSDate();
1637
+ if (!bUTC && (oDateValue.lastTimezonePatternSymbol === 'V' && oDateValue.timezone || oDateValue.tzDiff === undefined)) {
1638
+ if (oDateValue.timezone) {
1639
+ sTimezone = oDateValue.timezone;
1640
+ }
1641
+ if (sTimezone) {
1642
+ oDateValue.tzDiff = TimezoneUtil.calculateOffset(oDate, sTimezone);
1493
1643
  }
1494
1644
  }
1495
- return null;
1645
+ if (oDateValue.tzDiff) {
1646
+ oDate.setUTCSeconds((oDateValue.second || 0) + oDateValue.tzDiff);
1647
+ }
1648
+ return oDate;
1496
1649
  };
1497
1650
  function mergeWithoutOverwrite(object1, object2) {
1498
1651
  if (object1 === object2) {
@@ -1515,13 +1668,33 @@ function isValidDateRange(oStartDate, oEndDate) {
1515
1668
  }
1516
1669
  return true;
1517
1670
  }
1671
+ function isValidDateObject(oDate) {
1672
+ return oDate && typeof oDate.getTime === 'function' && !isNaN(oDate.getTime());
1673
+ }
1518
1674
  DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
1675
+ var bShowDate = this.oFormatOptions.showDate === undefined || this.oFormatOptions.showDate;
1676
+ var bShowTime = this.oFormatOptions.showTime === undefined || this.oFormatOptions.showTime;
1677
+ if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE && (bShowDate && !bShowTime || !bShowDate && bShowTime)) {
1678
+ throw new TypeError('The input can only be parsed back to date if both date and time are supplied.');
1679
+ }
1680
+ var sTimezone;
1681
+ if (bUTC === undefined && this.type !== mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1682
+ bUTC = this.oFormatOptions.UTC;
1683
+ }
1684
+ var bUTCInputParameter = bUTC;
1685
+ if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1686
+ sTimezone = bUTC;
1687
+ bUTC = false;
1688
+ checkTimezoneParameterType(sTimezone);
1689
+ if (sTimezone && !TimezoneUtil.isValidTimezone(sTimezone)) {
1690
+ Log.error('The given timezone isn\'t valid.');
1691
+ return null;
1692
+ }
1693
+ }
1519
1694
  sValue = sValue == null ? '' : String(sValue).trim();
1520
1695
  var oDateValue;
1521
1696
  var sCalendarType = this.oFormatOptions.calendarType;
1522
- if (bUTC === undefined) {
1523
- bUTC = this.oFormatOptions.UTC;
1524
- }
1697
+ sTimezone = sTimezone || Core.getConfiguration().getTimezone();
1525
1698
  if (bStrict === undefined) {
1526
1699
  bStrict = this.oFormatOptions.strictParsing;
1527
1700
  }
@@ -1533,22 +1706,40 @@ DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
1533
1706
  if (oJSDate) {
1534
1707
  return oJSDate;
1535
1708
  }
1536
- oDateValue = this._parse(sValue, this.aFormatArray, bUTC, bStrict);
1709
+ oDateValue = this._parse(sValue, this.aFormatArray, bUTC, bStrict, sTimezone);
1537
1710
  if (oDateValue.index === 0 || oDateValue.index < sValue.length) {
1538
1711
  oDateValue.valid = false;
1539
1712
  }
1540
- oJSDate = fnCreateDate(oDateValue, sCalendarType, bUTC, bStrict);
1713
+ oJSDate = fnCreateDate(oDateValue, sCalendarType, bUTC, bStrict, sTimezone);
1541
1714
  if (oJSDate) {
1715
+ if (this.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1716
+ var bShowTimezone = this.oFormatOptions.showTimezone === undefined || this.oFormatOptions.showTimezone;
1717
+ if (!bShowTimezone && bShowDate && bShowTime) {
1718
+ return [
1719
+ oJSDate,
1720
+ undefined
1721
+ ];
1722
+ } else if (bShowTimezone && !bShowDate && !bShowTime) {
1723
+ return [
1724
+ undefined,
1725
+ oDateValue.timezone
1726
+ ];
1727
+ }
1728
+ return [
1729
+ oJSDate,
1730
+ oDateValue.timezone || undefined
1731
+ ];
1732
+ }
1542
1733
  return oJSDate;
1543
1734
  }
1544
1735
  } else {
1545
- var aDateValues = this._parseInterval(sValue, sCalendarType, bUTC, bStrict);
1736
+ var aDateValues = this._parseInterval(sValue, sCalendarType, bUTC, bStrict, sTimezone);
1546
1737
  var oJSDate1, oJSDate2;
1547
1738
  if (aDateValues && aDateValues.length == 2) {
1548
1739
  var oDateValue1 = mergeWithoutOverwrite(aDateValues[0], aDateValues[1]);
1549
1740
  var oDateValue2 = mergeWithoutOverwrite(aDateValues[1], aDateValues[0]);
1550
- oJSDate1 = fnCreateDate(oDateValue1, sCalendarType, bUTC, bStrict);
1551
- oJSDate2 = fnCreateDate(oDateValue2, sCalendarType, bUTC, bStrict);
1741
+ oJSDate1 = fnCreateDate(oDateValue1, sCalendarType, bUTC, bStrict, sTimezone);
1742
+ oJSDate2 = fnCreateDate(oDateValue2, sCalendarType, bUTC, bStrict, sTimezone);
1552
1743
  if (oJSDate1 && oJSDate2) {
1553
1744
  if (this.oFormatOptions.singleIntervalValue && oJSDate1.getTime() === oJSDate2.getTime()) {
1554
1745
  return [
@@ -1574,8 +1765,11 @@ DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
1574
1765
  if (!this.bIsFallback) {
1575
1766
  var vDate;
1576
1767
  this.aFallbackFormats.every(function (oFallbackFormat) {
1577
- vDate = oFallbackFormat.parse(sValue, bUTC, bStrict);
1768
+ vDate = oFallbackFormat.parse(sValue, bUTCInputParameter, bStrict);
1578
1769
  if (Array.isArray(vDate)) {
1770
+ if (oFallbackFormat.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1771
+ return false;
1772
+ }
1579
1773
  return !(vDate[0] && vDate[1]);
1580
1774
  } else {
1581
1775
  return !vDate;
@@ -1724,23 +1918,20 @@ DateFormat.prototype.parseRelative = function (sValue, bUTC) {
1724
1918
  }
1725
1919
  }
1726
1920
  };
1727
- DateFormat.prototype.formatRelative = function (oJSDate, bUTC, aRange) {
1728
- var oToday = new Date(), oDateUTC, sScale = this.oFormatOptions.relativeScale || 'day', iDiff, sPattern, iDiffSeconds;
1921
+ DateFormat.prototype.formatRelative = function (oJSDate, bUTC, aRange, sTimezone) {
1922
+ var oToday = convertToTimezone(new Date(), sTimezone), oDateUTC, sScale = this.oFormatOptions.relativeScale || 'day', iDiff, sPattern, iDiffSeconds;
1729
1923
  iDiffSeconds = (oJSDate.getTime() - oToday.getTime()) / 1000;
1730
1924
  if (this.oFormatOptions.relativeScale == 'auto') {
1731
1925
  sScale = this._getScale(iDiffSeconds, this.aRelativeScales);
1926
+ sScale = fixScaleForMonths(oJSDate, oToday, sScale, iDiffSeconds);
1732
1927
  }
1733
1928
  if (!aRange) {
1734
1929
  aRange = this._mRanges[sScale];
1735
1930
  }
1736
1931
  if (sScale == 'year' || sScale == 'month' || sScale == 'day') {
1737
- oToday = new Date(Date.UTC(oToday.getFullYear(), oToday.getMonth(), oToday.getDate()));
1932
+ oToday = new Date(Date.UTC(oToday.getUTCFullYear(), oToday.getUTCMonth(), oToday.getUTCDate()));
1738
1933
  oDateUTC = new Date(0);
1739
- if (bUTC) {
1740
- oDateUTC.setUTCFullYear(oJSDate.getUTCFullYear(), oJSDate.getUTCMonth(), oJSDate.getUTCDate());
1741
- } else {
1742
- oDateUTC.setUTCFullYear(oJSDate.getFullYear(), oJSDate.getMonth(), oJSDate.getDate());
1743
- }
1934
+ oDateUTC.setUTCFullYear(oJSDate.getUTCFullYear(), oJSDate.getUTCMonth(), oJSDate.getUTCDate());
1744
1935
  oJSDate = oDateUTC;
1745
1936
  }
1746
1937
  iDiff = this._getDifference(sScale, [
@@ -1808,6 +1999,21 @@ DateFormat.prototype._getScale = function (iDiffSeconds, aScales) {
1808
1999
  }
1809
2000
  return sScale;
1810
2001
  };
2002
+ function fixScaleForMonths(oJSDate, oToday, sScale, iDiffSeconds) {
2003
+ var iMonthDiff = Math.abs(oJSDate.getUTCMonth() - oToday.getUTCMonth());
2004
+ if (sScale === 'week' && iMonthDiff === 2) {
2005
+ return 'month';
2006
+ } else if (sScale === 'week' && iMonthDiff === 1) {
2007
+ if (oJSDate.getUTCDate() === oToday.getUTCDate() || iDiffSeconds < 0 && oJSDate.getUTCDate() < oToday.getUTCDate() || iDiffSeconds > 0 && oJSDate.getUTCDate() > oToday.getUTCDate()) {
2008
+ return 'month';
2009
+ }
2010
+ } else if (sScale === 'month' && iMonthDiff === 1) {
2011
+ if (iDiffSeconds > 0 && oJSDate.getUTCDate() < oToday.getUTCDate() || iDiffSeconds < 0 && oJSDate.getUTCDate() > oToday.getUTCDate()) {
2012
+ return 'week';
2013
+ }
2014
+ }
2015
+ return sScale;
2016
+ }
1811
2017
  function cutDateFields(oDate, iStartIndex) {
1812
2018
  var aFields = [
1813
2019
  'FullYear',
@@ -1818,43 +2024,45 @@ function cutDateFields(oDate, iStartIndex) {
1818
2024
  'Seconds',
1819
2025
  'Milliseconds'
1820
2026
  ], sMethodName;
2027
+ var oDateCopy = new Date(oDate.getTime());
1821
2028
  for (var i = iStartIndex; i < aFields.length; i++) {
1822
- sMethodName = 'set' + aFields[iStartIndex];
1823
- oDate[sMethodName].apply(oDate, [0]);
2029
+ sMethodName = 'setUTC' + aFields[iStartIndex];
2030
+ oDateCopy[sMethodName].apply(oDateCopy, [0]);
1824
2031
  }
2032
+ return oDateCopy;
1825
2033
  }
1826
2034
  var mRelativeDiffs = {
1827
2035
  year: function (oFromDate, oToDate) {
1828
- return oToDate.getFullYear() - oFromDate.getFullYear();
2036
+ return oToDate.getUTCFullYear() - oFromDate.getUTCFullYear();
1829
2037
  },
1830
2038
  month: function (oFromDate, oToDate) {
1831
- return oToDate.getMonth() - oFromDate.getMonth() + this.year(oFromDate, oToDate) * 12;
2039
+ return oToDate.getUTCMonth() - oFromDate.getUTCMonth() + this.year(oFromDate, oToDate) * 12;
1832
2040
  },
1833
2041
  week: function (oFromDate, oToDate, oFormat) {
1834
- var iFromDay = oFormat._adaptDayOfWeek(oFromDate.getDay());
1835
- var iToDay = oFormat._adaptDayOfWeek(oToDate.getDay());
1836
- cutDateFields(oFromDate, 3);
1837
- cutDateFields(oToDate, 3);
2042
+ var iFromDay = oFormat._adaptDayOfWeek(oFromDate.getUTCDay());
2043
+ var iToDay = oFormat._adaptDayOfWeek(oToDate.getUTCDay());
2044
+ oFromDate = cutDateFields(oFromDate, 3);
2045
+ oToDate = cutDateFields(oToDate, 3);
1838
2046
  return (oToDate.getTime() - oFromDate.getTime() - (iToDay - iFromDay) * oFormat._mScales.day * 1000) / (oFormat._mScales.week * 1000);
1839
2047
  },
1840
2048
  day: function (oFromDate, oToDate, oFormat) {
1841
- cutDateFields(oFromDate, 3);
1842
- cutDateFields(oToDate, 3);
2049
+ oFromDate = cutDateFields(oFromDate, 3);
2050
+ oToDate = cutDateFields(oToDate, 3);
1843
2051
  return (oToDate.getTime() - oFromDate.getTime()) / (oFormat._mScales.day * 1000);
1844
2052
  },
1845
2053
  hour: function (oFromDate, oToDate, oFormat) {
1846
- cutDateFields(oFromDate, 4);
1847
- cutDateFields(oToDate, 4);
2054
+ oFromDate = cutDateFields(oFromDate, 4);
2055
+ oToDate = cutDateFields(oToDate, 4);
1848
2056
  return (oToDate.getTime() - oFromDate.getTime()) / (oFormat._mScales.hour * 1000);
1849
2057
  },
1850
2058
  minute: function (oFromDate, oToDate, oFormat) {
1851
- cutDateFields(oFromDate, 5);
1852
- cutDateFields(oToDate, 5);
2059
+ oFromDate = cutDateFields(oFromDate, 5);
2060
+ oToDate = cutDateFields(oToDate, 5);
1853
2061
  return (oToDate.getTime() - oFromDate.getTime()) / (oFormat._mScales.minute * 1000);
1854
2062
  },
1855
2063
  second: function (oFromDate, oToDate, oFormat) {
1856
- cutDateFields(oFromDate, 6);
1857
- cutDateFields(oToDate, 6);
2064
+ oFromDate = cutDateFields(oFromDate, 6);
2065
+ oToDate = cutDateFields(oToDate, 6);
1858
2066
  return (oToDate.getTime() - oFromDate.getTime()) / (oFormat._mScales.second * 1000);
1859
2067
  }
1860
2068
  };