Skip to content

Commit 0dd353e

Browse files
marker-daomarker dao ®
andauthored
DateBox: Use UTC units to get correct date, if date is just a year string (T1323373) (#32850)
Co-authored-by: marker dao ® <youdontknow@marker-dao.eth>
1 parent 9691b5c commit 0dd353e

4 files changed

Lines changed: 62 additions & 8 deletions

File tree

packages/devextreme/js/__internal/core/utils/m_date_serialization.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ const NUMBER_SERIALIZATION_FORMAT = 'number';
77
const DATE_SERIALIZATION_FORMAT = 'yyyy/MM/dd';
88
const DATETIME_SERIALIZATION_FORMAT = 'yyyy/MM/dd HH:mm:ss';
99

10+
const ISO_PARTIAL_DATE_PATTERN = /^\d{4,}(-\d{2})?$/;
1011
const ISO8601_PATTERN = /^(\d{4,})(-)?(\d{2})(-)?(\d{2})(?:T(\d{2})(:)?(\d{2})?(:)?(\d{2}(?:\.(\d{1,3})\d*)?)?)?(Z|([+-])(\d{2})(:)?(\d{2})?)?$/;
1112
const ISO8601_TIME_PATTERN = /^(\d{2}):(\d{2})(:(\d{2}))?$/;
12-
1313
const ISO8601_PATTERN_PARTS = ['', 'yyyy', '', 'MM', '', 'dd', 'THH', '', 'mm', '', 'ss', '.SSS'];
1414
const DATE_SERIALIZATION_PATTERN = /^(\d{4})\/(\d{2})\/(\d{2})$/;
1515

@@ -29,21 +29,43 @@ function getTimePart(part) {
2929
return +part || 0;
3030
}
3131

32-
function parseDate(text) {
33-
const isDefaultSerializationFormat = getDateSerializationFormat(text) === DATE_SERIALIZATION_FORMAT;
32+
function createLocalDateFromUTCTimestamp(timestamp: number): Date {
33+
const utc = new Date(timestamp);
34+
35+
return new Date(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());
36+
}
37+
38+
function isISOPartialDateString(text: string): boolean {
39+
return ISO_PARTIAL_DATE_PATTERN.test(text);
40+
}
41+
42+
function parseDate(text): string | Date {
43+
const isDefaultSerializationFormat = getDateSerializationFormat(text)
44+
=== DATE_SERIALIZATION_FORMAT;
45+
3446
const parsedValue = !isDate(text) && Date.parse(text);
47+
3548
if (!parsedValue && isDefaultSerializationFormat) {
3649
const parts = text.match(DATE_SERIALIZATION_PATTERN);
50+
3751
if (parts) {
3852
const newDate = new Date(getTimePart(parts[1]), getTimePart(parts[2]), getTimePart(parts[3]));
53+
3954
newDate.setFullYear(getTimePart(parts[1]));
4055
newDate.setMonth(getTimePart(parts[2]) - 1);
4156
newDate.setDate(getTimePart(parts[3]));
57+
4258
return newDate;
4359
}
4460
}
4561

46-
return isNumber(parsedValue) ? new Date(parsedValue) : text;
62+
if (!isNumber(parsedValue)) {
63+
return text;
64+
}
65+
66+
return isISOPartialDateString(text)
67+
? createLocalDateFromUTCTimestamp(parsedValue)
68+
: new Date(parsedValue);
4769
}
4870

4971
function parseISO8601String(text) {
@@ -173,6 +195,7 @@ const getDateSerializationFormat = function (value) {
173195
};
174196

175197
const dateSerialization = {
198+
createLocalDateFromUTCTimestamp,
176199
dateParser,
177200
deserializeDate,
178201
serializeDate,

packages/devextreme/js/__internal/ui/date_box/date_box.base.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -835,17 +835,26 @@ class DateBox extends DropDownEditor<DateBoxBaseProperties> {
835835
getDateOption(optionName: 'value' | 'min' | 'max'): Date | null {
836836
const { [optionName]: optionValue } = this.option();
837837

838-
return dateSerialization.deserializeDate(optionValue) as Date | null;
838+
const deserializedDate: Date | null = dateSerialization.deserializeDate(optionValue);
839+
840+
return deserializedDate;
839841
}
840842

841843
setDateOption(optionName: 'value' | 'min' | 'max', value: DateLike | undefined): void {
842-
this.option(optionName, this._serializeDate(value));
844+
const serializedDate = this._serializeDate(value);
845+
846+
this.option(optionName, serializedDate);
843847
}
844848

845849
_serializeDate(date?: DateLike): Date | string | null {
846850
const serializationFormat = this._getSerializationFormat();
847851

848-
return dateSerialization.serializeDate(date, serializationFormat) as Date | string | null;
852+
const serializedDate: Date | string | null = dateSerialization.serializeDate(
853+
date,
854+
serializationFormat,
855+
);
856+
857+
return serializedDate;
849858
}
850859

851860
_clearValue(): void {

packages/devextreme/js/__internal/ui/date_box/m_date_box.strategy.calendar.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,9 @@ class CalendarStrategy extends DateBoxStrategy {
219219
return;
220220
}
221221

222-
this._widget.option('value', this.dateBoxValue());
222+
const value = this.dateBoxValue();
223+
224+
this._widget.option({ value });
223225
}
224226

225227
textChangedHandler(): void {

packages/devextreme/testing/tests/DevExpress.core/utils.date_serialization.tests.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,26 @@ QUnit.test('deserializing first date (serialization format is string)', function
107107
assert.deepEqual(result, date, 'date is returned');
108108
});
109109

110+
QUnit.test('deserializing year-only string should return correct year (T1323373)', function(assert) {
111+
const result = dateSerialization.deserializeDate('2026');
112+
113+
assert.ok(result instanceof Date, 'result is a Date');
114+
assert.equal(result.getFullYear(), 2026, 'year is 2026');
115+
assert.equal(result.getMonth(), 0, 'month is January');
116+
assert.equal(result.getDate(), 1, 'day is 1');
117+
});
118+
119+
QUnit.test('createLocalDateFromUTCTimestamp returns local date with UTC components', function(assert) {
120+
const utcTimestamp = Date.UTC(2026, 0, 1);
121+
const result = dateSerialization.createLocalDateFromUTCTimestamp(utcTimestamp);
122+
123+
assert.ok(result instanceof Date, 'result is a Date');
124+
assert.equal(result.getFullYear(), 2026, 'year matches UTC year');
125+
assert.equal(result.getMonth(), 0, 'month matches UTC month');
126+
assert.equal(result.getDate(), 1, 'date matches UTC date');
127+
assert.equal(result.getHours(), 0, 'hours are 0');
128+
});
129+
110130
QUnit.test('serialization ISO8601 dates', function(assert) {
111131
const date = new Date(2015, 3, 5, 6, 7, 25, 125);
112132

0 commit comments

Comments
 (0)