@ui5/webcomponents-localization 1.2.6 → 1.4.0

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.
@@ -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,17 +422,32 @@ 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
453
  parseTZ: function (sValue, bColonSeparated) {
@@ -369,7 +469,7 @@ var oParseHelper = {
369
469
  }
370
470
  return {
371
471
  length: iLength,
372
- tzDiff: (iTZDiff + 60 * iTZDiffHour) * iTZFactor
472
+ tzDiff: (iTZDiff + 60 * iTZDiffHour) * 60 * iTZFactor
373
473
  };
374
474
  },
375
475
  checkValid: function (sType, bPartInvalid, oFormat) {
@@ -381,7 +481,7 @@ var oParseHelper = {
381
481
  DateFormat.prototype.oSymbols = {
382
482
  '': {
383
483
  name: 'text',
384
- format: function (oField, oDate, bUTC, oFormat) {
484
+ format: function (oField, oDate) {
385
485
  return oField.value;
386
486
  },
387
487
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -425,7 +525,7 @@ DateFormat.prototype.oSymbols = {
425
525
  'G': {
426
526
  name: 'era',
427
527
  format: function (oField, oDate, bUTC, oFormat) {
428
- var iEra = bUTC ? oDate.getUTCEra() : oDate.getEra();
528
+ var iEra = oDate.getUTCEra();
429
529
  if (oField.digits <= 3) {
430
530
  return oFormat.aErasAbbrev[iEra];
431
531
  } else if (oField.digits === 4) {
@@ -442,11 +542,11 @@ DateFormat.prototype.oSymbols = {
442
542
  ];
443
543
  for (var i = 0; i < aErasVariants.length; i++) {
444
544
  var aVariants = aErasVariants[i];
445
- var oFound = oParseHelper.findEntry(sValue, aVariants);
545
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
446
546
  if (oFound.index !== -1) {
447
547
  return {
448
548
  era: oFound.index,
449
- length: oFound.value.length
549
+ length: oFound.length
450
550
  };
451
551
  }
452
552
  }
@@ -459,7 +559,7 @@ DateFormat.prototype.oSymbols = {
459
559
  'y': {
460
560
  name: 'year',
461
561
  format: function (oField, oDate, bUTC, oFormat) {
462
- var iYear = bUTC ? oDate.getUTCFullYear() : oDate.getFullYear();
562
+ var iYear = oDate.getUTCFullYear();
463
563
  var sYear = String(iYear);
464
564
  var sCalendarType = oFormat.oFormatOptions.calendarType;
465
565
  if (oField.digits == 2 && sYear.length > 2) {
@@ -482,7 +582,7 @@ DateFormat.prototype.oSymbols = {
482
582
  }
483
583
  var iYear = parseInt(sPart);
484
584
  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;
585
+ var oCurrentDate = UniversalDate.getInstance(new Date(), sCalendarType), iCurrentYear = oCurrentDate.getUTCFullYear(), iCurrentCentury = Math.floor(iCurrentYear / 100), iYearDiff = iCurrentCentury * 100 + iYear - iCurrentYear;
486
586
  if (iYearDiff < -70) {
487
587
  iYear += (iCurrentCentury + 1) * 100;
488
588
  } else if (iYearDiff < 30) {
@@ -501,7 +601,7 @@ DateFormat.prototype.oSymbols = {
501
601
  'Y': {
502
602
  name: 'weekYear',
503
603
  format: function (oField, oDate, bUTC, oFormat) {
504
- var oWeek = bUTC ? oDate.getUTCWeek() : oDate.getWeek();
604
+ var oWeek = oDate.getUTCWeek();
505
605
  var iWeekYear = oWeek.year;
506
606
  var sWeekYear = String(iWeekYear);
507
607
  var sCalendarType = oFormat.oFormatOptions.calendarType;
@@ -524,9 +624,9 @@ DateFormat.prototype.oSymbols = {
524
624
  sPart = oParseHelper.findNumbers(sValue, oPart.digits);
525
625
  }
526
626
  var iYear = parseInt(sPart);
527
- var iWeekYear;
627
+ var iWeekYear = iYear;
528
628
  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;
629
+ var oCurrentDate = UniversalDate.getInstance(new Date(), sCalendarType), iCurrentYear = oCurrentDate.getUTCFullYear(), iCurrentCentury = Math.floor(iCurrentYear / 100), iYearDiff = iCurrentCentury * 100 + iWeekYear - iCurrentYear;
530
630
  if (iYearDiff < -70) {
531
631
  iWeekYear += (iCurrentCentury + 1) * 100;
532
632
  } else if (iYearDiff < 30) {
@@ -546,7 +646,7 @@ DateFormat.prototype.oSymbols = {
546
646
  'M': {
547
647
  name: 'month',
548
648
  format: function (oField, oDate, bUTC, oFormat) {
549
- var iMonth = bUTC ? oDate.getUTCMonth() : oDate.getMonth();
649
+ var iMonth = oDate.getUTCMonth();
550
650
  if (oField.digits == 3) {
551
651
  return oFormat.aMonthsAbbrev[iMonth];
552
652
  } else if (oField.digits == 4) {
@@ -579,11 +679,11 @@ DateFormat.prototype.oSymbols = {
579
679
  } else {
580
680
  for (var i = 0; i < aMonthsVariants.length; i++) {
581
681
  var aVariants = aMonthsVariants[i];
582
- var oFound = oParseHelper.findEntry(sValue, aVariants);
682
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
583
683
  if (oFound.index !== -1) {
584
684
  return {
585
685
  month: oFound.index,
586
- length: oFound.value.length
686
+ length: oFound.length
587
687
  };
588
688
  }
589
689
  }
@@ -599,7 +699,7 @@ DateFormat.prototype.oSymbols = {
599
699
  'L': {
600
700
  name: 'monthStandalone',
601
701
  format: function (oField, oDate, bUTC, oFormat) {
602
- var iMonth = bUTC ? oDate.getUTCMonth() : oDate.getMonth();
702
+ var iMonth = oDate.getUTCMonth();
603
703
  if (oField.digits == 3) {
604
704
  return oFormat.aMonthsAbbrevSt[iMonth];
605
705
  } else if (oField.digits == 4) {
@@ -632,11 +732,11 @@ DateFormat.prototype.oSymbols = {
632
732
  } else {
633
733
  for (var i = 0; i < aMonthsVariants.length; i++) {
634
734
  var aVariants = aMonthsVariants[i];
635
- var oFound = oParseHelper.findEntry(sValue, aVariants);
735
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
636
736
  if (oFound.index !== -1) {
637
737
  return {
638
738
  month: oFound.index,
639
- length: oFound.value.length
739
+ length: oFound.length
640
740
  };
641
741
  }
642
742
  }
@@ -652,7 +752,7 @@ DateFormat.prototype.oSymbols = {
652
752
  'w': {
653
753
  name: 'weekInYear',
654
754
  format: function (oField, oDate, bUTC, oFormat) {
655
- var oWeek = bUTC ? oDate.getUTCWeek() : oDate.getWeek();
755
+ var oWeek = oDate.getUTCWeek();
656
756
  var iWeek = oWeek.week;
657
757
  var sWeek = String(iWeek + 1);
658
758
  if (oField.digits < 3) {
@@ -674,11 +774,11 @@ DateFormat.prototype.oSymbols = {
674
774
  bValid = oParseHelper.checkValid(oPart.type, !sPart, oFormat);
675
775
  } else {
676
776
  sPart = oFormat.oLocaleData.getCalendarWeek(oPart.digits === 3 ? 'narrow' : 'wide');
677
- sPart = sPart.replace('{0}', '[0-9]+');
777
+ sPart = sPart.replace('{0}', '([0-9]+)');
678
778
  var rWeekNumber = new RegExp(sPart), oResult = rWeekNumber.exec(sValue);
679
779
  if (oResult) {
680
780
  iLength = oResult[0].length;
681
- iWeek = parseInt(oResult[0]) - 1;
781
+ iWeek = parseInt(oResult[oResult.length - 1]) - 1;
682
782
  } else {
683
783
  bValid = oParseHelper.checkValid(oPart.type, true, oFormat);
684
784
  }
@@ -692,7 +792,7 @@ DateFormat.prototype.oSymbols = {
692
792
  },
693
793
  'W': {
694
794
  name: 'weekInMonth',
695
- format: function (oField, oDate, bUTC, oFormat) {
795
+ format: function (oField, oDate) {
696
796
  return '';
697
797
  },
698
798
  parse: function () {
@@ -701,7 +801,7 @@ DateFormat.prototype.oSymbols = {
701
801
  },
702
802
  'D': {
703
803
  name: 'dayInYear',
704
- format: function (oField, oDate, bUTC, oFormat) {
804
+ format: function (oField, oDate) {
705
805
  },
706
806
  parse: function () {
707
807
  return {};
@@ -709,8 +809,8 @@ DateFormat.prototype.oSymbols = {
709
809
  },
710
810
  'd': {
711
811
  name: 'day',
712
- format: function (oField, oDate, bUTC, oFormat) {
713
- var iDate = bUTC ? oDate.getUTCDate() : oDate.getDate();
812
+ format: function (oField, oDate) {
813
+ var iDate = oDate.getUTCDate();
714
814
  return String(iDate).padStart(oField.digits, '0');
715
815
  },
716
816
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -730,7 +830,7 @@ DateFormat.prototype.oSymbols = {
730
830
  'Q': {
731
831
  name: 'quarter',
732
832
  format: function (oField, oDate, bUTC, oFormat) {
733
- var iQuarter = bUTC ? oDate.getUTCQuarter() : oDate.getQuarter();
833
+ var iQuarter = oDate.getUTCQuarter();
734
834
  if (oField.digits == 3) {
735
835
  return oFormat.aQuartersAbbrev[iQuarter];
736
836
  } else if (oField.digits == 4) {
@@ -763,11 +863,11 @@ DateFormat.prototype.oSymbols = {
763
863
  } else {
764
864
  for (var i = 0; i < aQuartersVariants.length; i++) {
765
865
  var aVariants = aQuartersVariants[i];
766
- var oFound = oParseHelper.findEntry(sValue, aVariants);
866
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
767
867
  if (oFound.index !== -1) {
768
868
  return {
769
869
  quarter: oFound.index,
770
- length: oFound.value.length
870
+ length: oFound.length
771
871
  };
772
872
  }
773
873
  }
@@ -783,7 +883,7 @@ DateFormat.prototype.oSymbols = {
783
883
  'q': {
784
884
  name: 'quarterStandalone',
785
885
  format: function (oField, oDate, bUTC, oFormat) {
786
- var iQuarter = bUTC ? oDate.getUTCQuarter() : oDate.getQuarter();
886
+ var iQuarter = oDate.getUTCQuarter();
787
887
  if (oField.digits == 3) {
788
888
  return oFormat.aQuartersAbbrevSt[iQuarter];
789
889
  } else if (oField.digits == 4) {
@@ -816,11 +916,11 @@ DateFormat.prototype.oSymbols = {
816
916
  } else {
817
917
  for (var i = 0; i < aQuartersVariants.length; i++) {
818
918
  var aVariants = aQuartersVariants[i];
819
- var oFound = oParseHelper.findEntry(sValue, aVariants);
919
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
820
920
  if (oFound.index !== -1) {
821
921
  return {
822
922
  quarter: oFound.index,
823
- length: oFound.value.length
923
+ length: oFound.length
824
924
  };
825
925
  }
826
926
  }
@@ -835,7 +935,7 @@ DateFormat.prototype.oSymbols = {
835
935
  },
836
936
  'F': {
837
937
  name: 'dayOfWeekInMonth',
838
- format: function (oField, oDate, bUTC, oFormat) {
938
+ format: function (oField, oDate, oFormat) {
839
939
  return '';
840
940
  },
841
941
  parse: function () {
@@ -845,7 +945,7 @@ DateFormat.prototype.oSymbols = {
845
945
  'E': {
846
946
  name: 'dayNameInWeek',
847
947
  format: function (oField, oDate, bUTC, oFormat) {
848
- var iDay = bUTC ? oDate.getUTCDay() : oDate.getDay();
948
+ var iDay = oDate.getUTCDay();
849
949
  if (oField.digits < 4) {
850
950
  return oFormat.aDaysAbbrev[iDay];
851
951
  } else if (oField.digits == 4) {
@@ -869,11 +969,11 @@ DateFormat.prototype.oSymbols = {
869
969
  ];
870
970
  for (var i = 0; i < aDaysVariants.length; i++) {
871
971
  var aVariants = aDaysVariants[i];
872
- var oFound = oParseHelper.findEntry(sValue, aVariants);
972
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
873
973
  if (oFound.index !== -1) {
874
974
  return {
875
975
  dayOfWeek: oFound.index,
876
- length: oFound.value.length
976
+ length: oFound.length
877
977
  };
878
978
  }
879
979
  }
@@ -882,7 +982,7 @@ DateFormat.prototype.oSymbols = {
882
982
  'c': {
883
983
  name: 'dayNameInWeekStandalone',
884
984
  format: function (oField, oDate, bUTC, oFormat) {
885
- var iDay = bUTC ? oDate.getUTCDay() : oDate.getDay();
985
+ var iDay = oDate.getUTCDay();
886
986
  if (oField.digits < 4) {
887
987
  return oFormat.aDaysAbbrevSt[iDay];
888
988
  } else if (oField.digits == 4) {
@@ -906,11 +1006,11 @@ DateFormat.prototype.oSymbols = {
906
1006
  ];
907
1007
  for (var i = 0; i < aDaysVariants.length; i++) {
908
1008
  var aVariants = aDaysVariants[i];
909
- var oFound = oParseHelper.findEntry(sValue, aVariants);
1009
+ var oFound = oParseHelper.findEntry(sValue, aVariants, oFormat.oLocaleData.sCLDRLocaleId);
910
1010
  if (oFound.index !== -1) {
911
1011
  return {
912
1012
  day: oFound.index,
913
- length: oFound.value.length
1013
+ length: oFound.length
914
1014
  };
915
1015
  }
916
1016
  }
@@ -919,7 +1019,7 @@ DateFormat.prototype.oSymbols = {
919
1019
  'u': {
920
1020
  name: 'dayNumberOfWeek',
921
1021
  format: function (oField, oDate, bUTC, oFormat) {
922
- var iDay = bUTC ? oDate.getUTCDay() : oDate.getDay();
1022
+ var iDay = oDate.getUTCDay();
923
1023
  return oFormat._adaptDayOfWeek(iDay);
924
1024
  },
925
1025
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -933,7 +1033,7 @@ DateFormat.prototype.oSymbols = {
933
1033
  'a': {
934
1034
  name: 'amPmMarker',
935
1035
  format: function (oField, oDate, bUTC, oFormat) {
936
- var iDayPeriod = bUTC ? oDate.getUTCDayPeriod() : oDate.getDayPeriod();
1036
+ var iDayPeriod = oDate.getUTCDayPeriod();
937
1037
  return oFormat.aDayPeriods[iDayPeriod];
938
1038
  },
939
1039
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -967,8 +1067,8 @@ DateFormat.prototype.oSymbols = {
967
1067
  },
968
1068
  'H': {
969
1069
  name: 'hour0_23',
970
- format: function (oField, oDate, bUTC, oFormat) {
971
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1070
+ format: function (oField, oDate) {
1071
+ var iHours = oDate.getUTCHours();
972
1072
  return String(iHours).padStart(oField.digits, '0');
973
1073
  },
974
1074
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -988,8 +1088,8 @@ DateFormat.prototype.oSymbols = {
988
1088
  },
989
1089
  'k': {
990
1090
  name: 'hour1_24',
991
- format: function (oField, oDate, bUTC, oFormat) {
992
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1091
+ format: function (oField, oDate) {
1092
+ var iHours = oDate.getUTCHours();
993
1093
  var sHours = iHours === 0 ? '24' : String(iHours);
994
1094
  return sHours.padStart(oField.digits, '0');
995
1095
  },
@@ -1013,8 +1113,8 @@ DateFormat.prototype.oSymbols = {
1013
1113
  },
1014
1114
  'K': {
1015
1115
  name: 'hour0_11',
1016
- format: function (oField, oDate, bUTC, oFormat) {
1017
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1116
+ format: function (oField, oDate) {
1117
+ var iHours = oDate.getUTCHours();
1018
1118
  var sHours = String(iHours > 11 ? iHours - 12 : iHours);
1019
1119
  return sHours.padStart(oField.digits, '0');
1020
1120
  },
@@ -1035,8 +1135,8 @@ DateFormat.prototype.oSymbols = {
1035
1135
  },
1036
1136
  'h': {
1037
1137
  name: 'hour1_12',
1038
- format: function (oField, oDate, bUTC, oFormat) {
1039
- var iHours = bUTC ? oDate.getUTCHours() : oDate.getHours();
1138
+ format: function (oField, oDate) {
1139
+ var iHours = oDate.getUTCHours();
1040
1140
  var sHours;
1041
1141
  if (iHours > 12) {
1042
1142
  sHours = String(iHours - 12);
@@ -1069,8 +1169,8 @@ DateFormat.prototype.oSymbols = {
1069
1169
  },
1070
1170
  'm': {
1071
1171
  name: 'minute',
1072
- format: function (oField, oDate, bUTC, oFormat) {
1073
- var iMinutes = bUTC ? oDate.getUTCMinutes() : oDate.getMinutes();
1172
+ format: function (oField, oDate) {
1173
+ var iMinutes = oDate.getUTCMinutes();
1074
1174
  return String(iMinutes).padStart(oField.digits, '0');
1075
1175
  },
1076
1176
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -1090,8 +1190,8 @@ DateFormat.prototype.oSymbols = {
1090
1190
  },
1091
1191
  's': {
1092
1192
  name: 'second',
1093
- format: function (oField, oDate, bUTC, oFormat) {
1094
- var iSeconds = bUTC ? oDate.getUTCSeconds() : oDate.getSeconds();
1193
+ format: function (oField, oDate) {
1194
+ var iSeconds = oDate.getUTCSeconds();
1095
1195
  return String(iSeconds).padStart(oField.digits, '0');
1096
1196
  },
1097
1197
  parse: function (sValue, oPart, oFormat, oConfig) {
@@ -1111,8 +1211,8 @@ DateFormat.prototype.oSymbols = {
1111
1211
  },
1112
1212
  'S': {
1113
1213
  name: 'fractionalsecond',
1114
- format: function (oField, oDate, bUTC, oFormat) {
1115
- var iMilliseconds = bUTC ? oDate.getUTCMilliseconds() : oDate.getMilliseconds();
1214
+ format: function (oField, oDate) {
1215
+ var iMilliseconds = oDate.getUTCMilliseconds();
1116
1216
  var sMilliseconds = String(iMilliseconds);
1117
1217
  var sFractionalseconds = sMilliseconds.padStart(3, '0');
1118
1218
  sFractionalseconds = sFractionalseconds.substr(0, oField.digits);
@@ -1133,17 +1233,18 @@ DateFormat.prototype.oSymbols = {
1133
1233
  },
1134
1234
  'z': {
1135
1235
  name: 'timezoneGeneral',
1136
- format: function (oField, oDate, bUTC, oFormat) {
1236
+ format: function (oField, oDate, bUTC, oFormat, sTimezone) {
1137
1237
  if (oField.digits > 3 && oDate.getTimezoneLong && oDate.getTimezoneLong()) {
1138
1238
  return oDate.getTimezoneLong();
1139
1239
  } else if (oDate.getTimezoneShort && oDate.getTimezoneShort()) {
1140
1240
  return oDate.getTimezoneShort();
1141
1241
  }
1242
+ var iTimezoneOffset = TimezoneUtil.calculateOffset(oDate, sTimezone);
1142
1243
  var sTimeZone = 'GMT';
1143
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1144
- var bPositiveOffset = oDate.getTimezoneOffset() > 0;
1244
+ var iTZOffset = Math.abs(iTimezoneOffset / 60);
1245
+ var bPositiveOffset = iTimezoneOffset > 0;
1145
1246
  var iHourOffset = Math.floor(iTZOffset / 60);
1146
- var iMinuteOffset = iTZOffset % 60;
1247
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1147
1248
  if (!bUTC && iTZOffset != 0) {
1148
1249
  sTimeZone += bPositiveOffset ? '-' : '+';
1149
1250
  sTimeZone += String(iHourOffset).padStart(2, '0');
@@ -1181,11 +1282,12 @@ DateFormat.prototype.oSymbols = {
1181
1282
  },
1182
1283
  'Z': {
1183
1284
  name: 'timezoneRFC822',
1184
- format: function (oField, oDate, bUTC, oFormat) {
1185
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1186
- 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;
1187
1289
  var iHourOffset = Math.floor(iTZOffset / 60);
1188
- var iMinuteOffset = iTZOffset % 60;
1290
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1189
1291
  var sTimeZone = '';
1190
1292
  if (!bUTC) {
1191
1293
  sTimeZone += bPositiveOffset ? '-' : '+';
@@ -1200,11 +1302,12 @@ DateFormat.prototype.oSymbols = {
1200
1302
  },
1201
1303
  'X': {
1202
1304
  name: 'timezoneISO8601',
1203
- format: function (oField, oDate, bUTC, oFormat) {
1204
- var iTZOffset = Math.abs(oDate.getTimezoneOffset());
1205
- 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;
1206
1309
  var iHourOffset = Math.floor(iTZOffset / 60);
1207
- var iMinuteOffset = iTZOffset % 60;
1310
+ var iMinuteOffset = Math.floor(iTZOffset % 60);
1208
1311
  var sTimeZone = '';
1209
1312
  if (!bUTC && iTZOffset != 0) {
1210
1313
  sTimeZone += bPositiveOffset ? '-' : '+';
@@ -1230,11 +1333,43 @@ DateFormat.prototype.oSymbols = {
1230
1333
  return oParseHelper.parseTZ(sValue, oPart.digits === 3 || oPart.digits === 5);
1231
1334
  }
1232
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
+ }
1365
+ }
1366
+ return oTimezoneParsed;
1367
+ }
1233
1368
  }
1234
1369
  };
1235
- DateFormat.prototype._format = function (oJSDate, bUTC) {
1370
+ DateFormat.prototype._format = function (oJSDate, bUTC, sTimezone) {
1236
1371
  if (this.oFormatOptions.relative) {
1237
- var sRes = this.formatRelative(oJSDate, bUTC, this.oFormatOptions.relativeRange);
1372
+ var sRes = this.formatRelative(oJSDate, bUTC, this.oFormatOptions.relativeRange, sTimezone);
1238
1373
  if (sRes) {
1239
1374
  return sRes;
1240
1375
  }
@@ -1245,7 +1380,7 @@ DateFormat.prototype._format = function (oJSDate, bUTC) {
1245
1380
  for (var i = 0; i < this.aFormatArray.length; i++) {
1246
1381
  oPart = this.aFormatArray[i];
1247
1382
  sSymbol = oPart.symbol || '';
1248
- aBuffer.push(this.oSymbols[sSymbol].format(oPart, oDate, bUTC, this));
1383
+ aBuffer.push(this.oSymbols[sSymbol].format(oPart, oDate, bUTC, this, sTimezone));
1249
1384
  }
1250
1385
  sResult = aBuffer.join('');
1251
1386
  if (Core.getConfiguration().getOriginInfo()) {
@@ -1260,10 +1395,21 @@ DateFormat.prototype._format = function (oJSDate, bUTC) {
1260
1395
  return sResult;
1261
1396
  };
1262
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
+ }
1263
1408
  var sCalendarType = this.oFormatOptions.calendarType, sResult;
1264
1409
  if (bUTC === undefined) {
1265
1410
  bUTC = this.oFormatOptions.UTC;
1266
1411
  }
1412
+ sTimezone = sTimezone || Core.getConfiguration().getTimezone();
1267
1413
  if (Array.isArray(vJSDate)) {
1268
1414
  if (!this.oFormatOptions.interval) {
1269
1415
  Log.error('Non-interval DateFormat can\'t format more than one date instance.');
@@ -1273,27 +1419,30 @@ DateFormat.prototype.format = function (vJSDate, bUTC) {
1273
1419
  Log.error('Interval DateFormat can only format with 2 date instances but ' + vJSDate.length + ' is given.');
1274
1420
  return '';
1275
1421
  }
1422
+ vJSDate = vJSDate.map(function (oJSDate) {
1423
+ return convertToTimezone(oJSDate, sTimezone, bUTC);
1424
+ });
1276
1425
  if (this.oFormatOptions.singleIntervalValue) {
1277
1426
  if (vJSDate[0] === null) {
1278
1427
  Log.error('First date instance which is passed to the interval DateFormat shouldn\'t be null.');
1279
1428
  return '';
1280
1429
  }
1281
1430
  if (vJSDate[1] === null) {
1282
- sResult = this._format(vJSDate[0], bUTC);
1431
+ sResult = this._format(vJSDate[0], bUTC, sTimezone);
1283
1432
  }
1284
1433
  }
1285
1434
  if (sResult === undefined) {
1286
- var bValid = vJSDate.every(function (oJSDate) {
1287
- return oJSDate && !isNaN(oJSDate.getTime());
1288
- });
1289
- if (!bValid) {
1435
+ if (!vJSDate.every(isValidDateObject)) {
1290
1436
  Log.error('At least one date instance which is passed to the interval DateFormat isn\'t valid.');
1291
1437
  return '';
1292
1438
  }
1293
1439
  sResult = this._formatInterval(vJSDate, bUTC);
1294
1440
  }
1295
1441
  } else {
1296
- 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
+ }
1297
1446
  Log.error('The given date instance isn\'t valid.');
1298
1447
  return '';
1299
1448
  }
@@ -1301,7 +1450,8 @@ DateFormat.prototype.format = function (vJSDate, bUTC) {
1301
1450
  Log.error('Interval DateFormat expects an array with two dates for the first argument but only one date is given.');
1302
1451
  return '';
1303
1452
  }
1304
- sResult = this._format(vJSDate, bUTC);
1453
+ vJSDate = convertToTimezone(vJSDate, sTimezone, bUTC);
1454
+ sResult = this._format(vJSDate, bUTC, sTimezone);
1305
1455
  }
1306
1456
  if (sCalendarType == CalendarType.Japanese && this.oLocale.getLanguage() === 'ja') {
1307
1457
  sResult = sResult.replace(/(^|[^\d])1年/g, '$1元年');
@@ -1321,7 +1471,7 @@ DateFormat.prototype._formatInterval = function (aJSDates, bUTC) {
1321
1471
  var oDiffField = this._getGreatestDiffField([
1322
1472
  oFromDate,
1323
1473
  oToDate
1324
- ], bUTC);
1474
+ ]);
1325
1475
  if (!oDiffField) {
1326
1476
  return this._format(aJSDates[0], bUTC);
1327
1477
  }
@@ -1354,10 +1504,10 @@ var mFieldToGroup = {
1354
1504
  Minutes: 'Minute',
1355
1505
  Seconds: 'Second'
1356
1506
  };
1357
- DateFormat.prototype._getGreatestDiffField = function (aDates, bUTC) {
1507
+ DateFormat.prototype._getGreatestDiffField = function (aDates) {
1358
1508
  var bDiffFound = false, mDiff = {};
1359
1509
  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]);
1510
+ var sGetterPrefix = 'getUTC', sMethodName = sGetterPrefix + sField, sFieldGroup = mFieldToGroup[sField], vFromValue = aDates[0][sMethodName].apply(aDates[0]), vToValue = aDates[1][sMethodName].apply(aDates[1]);
1361
1511
  if (!deepEqual(vFromValue, vToValue)) {
1362
1512
  bDiffFound = true;
1363
1513
  mDiff[sFieldGroup] = true;
@@ -1368,9 +1518,12 @@ DateFormat.prototype._getGreatestDiffField = function (aDates, bUTC) {
1368
1518
  }
1369
1519
  return null;
1370
1520
  };
1371
- DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1521
+ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict, sTimezone) {
1372
1522
  var iIndex = 0, oPart, sSubValue, oResult;
1373
- var oDateValue = { valid: true };
1523
+ var oDateValue = {
1524
+ valid: true,
1525
+ lastTimezonePatternSymbol: ''
1526
+ };
1374
1527
  var oParseConf = {
1375
1528
  formatArray: aFormatArray,
1376
1529
  dateValue: oDateValue,
@@ -1380,7 +1533,10 @@ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1380
1533
  sSubValue = sValue.substr(iIndex);
1381
1534
  oPart = aFormatArray[i];
1382
1535
  oParseConf.index = i;
1383
- 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
+ }
1384
1540
  oDateValue = extend(oDateValue, oResult);
1385
1541
  if (oResult.valid === false) {
1386
1542
  break;
@@ -1400,7 +1556,7 @@ DateFormat.prototype._parse = function (sValue, aFormatArray, bUTC, bStrict) {
1400
1556
  }
1401
1557
  return oDateValue;
1402
1558
  };
1403
- DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bStrict) {
1559
+ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bStrict, sTimezone) {
1404
1560
  var aDateValues, iRepeat, oDateValue;
1405
1561
  this.intervalPatterns.some(function (sPattern) {
1406
1562
  var aFormatArray = this.parseCldrDatePattern(sPattern);
@@ -1412,7 +1568,7 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1412
1568
  }
1413
1569
  }
1414
1570
  if (iRepeat === undefined) {
1415
- oDateValue = this._parse(sValue, aFormatArray, bUTC, bStrict);
1571
+ oDateValue = this._parse(sValue, aFormatArray, bUTC, bStrict, sTimezone);
1416
1572
  if (oDateValue.index === 0 || oDateValue.index < sValue.length) {
1417
1573
  oDateValue.valid = false;
1418
1574
  }
@@ -1426,13 +1582,13 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1426
1582
  return true;
1427
1583
  } else {
1428
1584
  aDateValues = [];
1429
- oDateValue = this._parse(sValue, aFormatArray.slice(0, iRepeat), bUTC, bStrict);
1585
+ oDateValue = this._parse(sValue, aFormatArray.slice(0, iRepeat), bUTC, bStrict, sTimezone);
1430
1586
  if (oDateValue.valid === false) {
1431
1587
  return;
1432
1588
  }
1433
1589
  aDateValues.push(oDateValue);
1434
1590
  var iLength = oDateValue.index;
1435
- oDateValue = this._parse(sValue.substring(iLength), aFormatArray.slice(iRepeat), bUTC, bStrict);
1591
+ oDateValue = this._parse(sValue.substring(iLength), aFormatArray.slice(iRepeat), bUTC, bStrict, sTimezone);
1436
1592
  if (oDateValue.index === 0 || oDateValue.index + iLength < sValue.length) {
1437
1593
  oDateValue.valid = false;
1438
1594
  }
@@ -1445,65 +1601,51 @@ DateFormat.prototype._parseInterval = function (sValue, sCalendarType, bUTC, bSt
1445
1601
  }.bind(this));
1446
1602
  return aDateValues;
1447
1603
  };
1448
- 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
+ }
1449
1614
  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
- }
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);
1500
1634
  }
1501
- if (oDateValue.valid) {
1502
- oDate = oDate.getJSDate();
1503
- 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);
1504
1643
  }
1505
1644
  }
1506
- return null;
1645
+ if (oDateValue.tzDiff) {
1646
+ oDate.setUTCSeconds((oDateValue.second || 0) + oDateValue.tzDiff);
1647
+ }
1648
+ return oDate;
1507
1649
  };
1508
1650
  function mergeWithoutOverwrite(object1, object2) {
1509
1651
  if (object1 === object2) {
@@ -1526,13 +1668,33 @@ function isValidDateRange(oStartDate, oEndDate) {
1526
1668
  }
1527
1669
  return true;
1528
1670
  }
1671
+ function isValidDateObject(oDate) {
1672
+ return oDate && typeof oDate.getTime === 'function' && !isNaN(oDate.getTime());
1673
+ }
1529
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
+ }
1530
1694
  sValue = sValue == null ? '' : String(sValue).trim();
1531
1695
  var oDateValue;
1532
1696
  var sCalendarType = this.oFormatOptions.calendarType;
1533
- if (bUTC === undefined) {
1534
- bUTC = this.oFormatOptions.UTC;
1535
- }
1697
+ sTimezone = sTimezone || Core.getConfiguration().getTimezone();
1536
1698
  if (bStrict === undefined) {
1537
1699
  bStrict = this.oFormatOptions.strictParsing;
1538
1700
  }
@@ -1544,22 +1706,40 @@ DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
1544
1706
  if (oJSDate) {
1545
1707
  return oJSDate;
1546
1708
  }
1547
- oDateValue = this._parse(sValue, this.aFormatArray, bUTC, bStrict);
1709
+ oDateValue = this._parse(sValue, this.aFormatArray, bUTC, bStrict, sTimezone);
1548
1710
  if (oDateValue.index === 0 || oDateValue.index < sValue.length) {
1549
1711
  oDateValue.valid = false;
1550
1712
  }
1551
- oJSDate = fnCreateDate(oDateValue, sCalendarType, bUTC, bStrict);
1713
+ oJSDate = fnCreateDate(oDateValue, sCalendarType, bUTC, bStrict, sTimezone);
1552
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
+ }
1553
1733
  return oJSDate;
1554
1734
  }
1555
1735
  } else {
1556
- var aDateValues = this._parseInterval(sValue, sCalendarType, bUTC, bStrict);
1736
+ var aDateValues = this._parseInterval(sValue, sCalendarType, bUTC, bStrict, sTimezone);
1557
1737
  var oJSDate1, oJSDate2;
1558
1738
  if (aDateValues && aDateValues.length == 2) {
1559
1739
  var oDateValue1 = mergeWithoutOverwrite(aDateValues[0], aDateValues[1]);
1560
1740
  var oDateValue2 = mergeWithoutOverwrite(aDateValues[1], aDateValues[0]);
1561
- oJSDate1 = fnCreateDate(oDateValue1, sCalendarType, bUTC, bStrict);
1562
- oJSDate2 = fnCreateDate(oDateValue2, sCalendarType, bUTC, bStrict);
1741
+ oJSDate1 = fnCreateDate(oDateValue1, sCalendarType, bUTC, bStrict, sTimezone);
1742
+ oJSDate2 = fnCreateDate(oDateValue2, sCalendarType, bUTC, bStrict, sTimezone);
1563
1743
  if (oJSDate1 && oJSDate2) {
1564
1744
  if (this.oFormatOptions.singleIntervalValue && oJSDate1.getTime() === oJSDate2.getTime()) {
1565
1745
  return [
@@ -1585,8 +1765,11 @@ DateFormat.prototype.parse = function (sValue, bUTC, bStrict) {
1585
1765
  if (!this.bIsFallback) {
1586
1766
  var vDate;
1587
1767
  this.aFallbackFormats.every(function (oFallbackFormat) {
1588
- vDate = oFallbackFormat.parse(sValue, bUTC, bStrict);
1768
+ vDate = oFallbackFormat.parse(sValue, bUTCInputParameter, bStrict);
1589
1769
  if (Array.isArray(vDate)) {
1770
+ if (oFallbackFormat.type === mDateFormatTypes.DATETIME_WITH_TIMEZONE) {
1771
+ return false;
1772
+ }
1590
1773
  return !(vDate[0] && vDate[1]);
1591
1774
  } else {
1592
1775
  return !vDate;
@@ -1735,23 +1918,20 @@ DateFormat.prototype.parseRelative = function (sValue, bUTC) {
1735
1918
  }
1736
1919
  }
1737
1920
  };
1738
- DateFormat.prototype.formatRelative = function (oJSDate, bUTC, aRange) {
1739
- 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;
1740
1923
  iDiffSeconds = (oJSDate.getTime() - oToday.getTime()) / 1000;
1741
1924
  if (this.oFormatOptions.relativeScale == 'auto') {
1742
1925
  sScale = this._getScale(iDiffSeconds, this.aRelativeScales);
1926
+ sScale = fixScaleForMonths(oJSDate, oToday, sScale, iDiffSeconds);
1743
1927
  }
1744
1928
  if (!aRange) {
1745
1929
  aRange = this._mRanges[sScale];
1746
1930
  }
1747
1931
  if (sScale == 'year' || sScale == 'month' || sScale == 'day') {
1748
- oToday = new Date(Date.UTC(oToday.getFullYear(), oToday.getMonth(), oToday.getDate()));
1932
+ oToday = new Date(Date.UTC(oToday.getUTCFullYear(), oToday.getUTCMonth(), oToday.getUTCDate()));
1749
1933
  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
- }
1934
+ oDateUTC.setUTCFullYear(oJSDate.getUTCFullYear(), oJSDate.getUTCMonth(), oJSDate.getUTCDate());
1755
1935
  oJSDate = oDateUTC;
1756
1936
  }
1757
1937
  iDiff = this._getDifference(sScale, [
@@ -1819,6 +1999,21 @@ DateFormat.prototype._getScale = function (iDiffSeconds, aScales) {
1819
1999
  }
1820
2000
  return sScale;
1821
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
+ }
1822
2017
  function cutDateFields(oDate, iStartIndex) {
1823
2018
  var aFields = [
1824
2019
  'FullYear',
@@ -1831,21 +2026,21 @@ function cutDateFields(oDate, iStartIndex) {
1831
2026
  ], sMethodName;
1832
2027
  var oDateCopy = new Date(oDate.getTime());
1833
2028
  for (var i = iStartIndex; i < aFields.length; i++) {
1834
- sMethodName = 'set' + aFields[iStartIndex];
2029
+ sMethodName = 'setUTC' + aFields[iStartIndex];
1835
2030
  oDateCopy[sMethodName].apply(oDateCopy, [0]);
1836
2031
  }
1837
2032
  return oDateCopy;
1838
2033
  }
1839
2034
  var mRelativeDiffs = {
1840
2035
  year: function (oFromDate, oToDate) {
1841
- return oToDate.getFullYear() - oFromDate.getFullYear();
2036
+ return oToDate.getUTCFullYear() - oFromDate.getUTCFullYear();
1842
2037
  },
1843
2038
  month: function (oFromDate, oToDate) {
1844
- return oToDate.getMonth() - oFromDate.getMonth() + this.year(oFromDate, oToDate) * 12;
2039
+ return oToDate.getUTCMonth() - oFromDate.getUTCMonth() + this.year(oFromDate, oToDate) * 12;
1845
2040
  },
1846
2041
  week: function (oFromDate, oToDate, oFormat) {
1847
- var iFromDay = oFormat._adaptDayOfWeek(oFromDate.getDay());
1848
- var iToDay = oFormat._adaptDayOfWeek(oToDate.getDay());
2042
+ var iFromDay = oFormat._adaptDayOfWeek(oFromDate.getUTCDay());
2043
+ var iToDay = oFormat._adaptDayOfWeek(oToDate.getUTCDay());
1849
2044
  oFromDate = cutDateFields(oFromDate, 3);
1850
2045
  oToDate = cutDateFields(oToDate, 3);
1851
2046
  return (oToDate.getTime() - oFromDate.getTime() - (iToDay - iFromDay) * oFormat._mScales.day * 1000) / (oFormat._mScales.week * 1000);