Skip to content

Commit 79ef0bd

Browse files
committed
refactor(date-editor): parse format and tests, rename parse value
1 parent 448e967 commit 79ef0bd

File tree

3 files changed

+87
-6
lines changed

3 files changed

+87
-6
lines changed

projects/igniteui-angular/src/lib/date-picker/date-picker.utils.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { isIE } from '../core/utils';
22
import { DatePart, DatePartInfo } from '../directives/date-time-editor/date-time-editor.common';
3-
import { max } from 'rxjs/operators';
43

54
/**
65
* This enum is used to keep the date validation result.
@@ -51,7 +50,12 @@ export abstract class DatePickerUtil {
5150
private static readonly PROMPT_CHAR = '_';
5251
private static readonly DEFAULT_LOCALE = 'en';
5352

54-
public static parseDateFromMask(inputData: string, dateTimeParts: DatePartInfo[]): Date | null {
53+
/**
54+
* Parse a Date value from masked string input based on determined date parts
55+
* @param inputData masked value to parse
56+
* @param dateTimeParts Date parts array for the mask
57+
*/
58+
public static parseValueFromMask(inputData: string, dateTimeParts: DatePartInfo[]): Date | null {
5559
const parts: { [key in DatePart]: number } = {} as any;
5660
dateTimeParts.forEach(dp => {
5761
let value = parseInt(this.getCleanVal(inputData, dp), 10);
@@ -102,26 +106,32 @@ export abstract class DatePickerUtil {
102106
}
103107
}
104108

109+
/**
110+
* Parse the mask into date/time and literal parts
111+
*/
105112
public static parseDateTimeFormat(mask: string, locale: string = DatePickerUtil.DEFAULT_LOCALE): DatePartInfo[] {
106113
const format = mask || DatePickerUtil.getDefaultInputFormat(locale);
107114
const dateTimeParts: DatePartInfo[] = [];
108115
const formatArray = Array.from(format);
109116
let currentPart: DatePartInfo = null;
110117
let position = 0;
111-
for (let i = 0; ; i++, position++) {
118+
119+
for (let i = 0; i < formatArray.length; i++, position++) {
112120
const type = DatePickerUtil.determineDatePart(formatArray[i]);
113121
if (currentPart) {
114122
if (currentPart.type === type) {
115123
currentPart.format += formatArray[i];
116-
continue;
124+
if (i < formatArray.length - 1) {
125+
continue;
126+
}
117127
}
118128

119129
DatePickerUtil.ensureLeadingZero(currentPart);
120130
currentPart.end = currentPart.start + currentPart.format.length;
121131
position = currentPart.end;
122132
dateTimeParts.push(currentPart);
123133
}
124-
if (i >= formatArray.length) { break; }
134+
125135
currentPart = {
126136
start: position,
127137
end: position + formatArray[i].length,
@@ -185,6 +195,7 @@ export abstract class DatePickerUtil {
185195
public static spinYear(delta: number, newDate: Date): void {
186196
const maxDate = DatePickerUtil.daysInMonth(newDate.getFullYear() + delta, newDate.getMonth());
187197
if (newDate.getDate() > maxDate) {
198+
// clip to max to avoid leap year change shifting the entire value
188199
newDate.setDate(maxDate);
189200
}
190201
newDate.setFullYear(newDate.getFullYear() + delta);

projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
524524

525525
private parseDate(val: string): Date | null {
526526
if (!val) { return null; }
527-
return DatePickerUtil.parseDateFromMask(val, this._inputDateParts);
527+
return DatePickerUtil.parseValueFromMask(val, this._inputDateParts);
528528
}
529529

530530
private moveCursor(event: KeyboardEvent): void {
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { DatePickerUtil } from '../../date-picker/date-picker.utils';
2+
import { DatePart, DatePartInfo } from './date-time-editor.common';
3+
4+
function reduceToDictionary(parts: DatePartInfo[]) {
5+
return parts.reduce((obj, x) => {
6+
obj[x.type] = x;
7+
return obj;
8+
}, {});
9+
}
10+
11+
describe('Date Time Parsing', () => {
12+
it('should correctly parse all date time parts (base)', () => {
13+
const result = DatePickerUtil.parseDateTimeFormat('dd/MM/yyyy HH:mm:ss tt');
14+
const expected = [
15+
{start: 0, end: 2, type: DatePart.Date, format: 'dd'},
16+
{start: 2, end: 3, type: DatePart.Literal, format: '/'},
17+
{start: 3, end: 5, type: DatePart.Month, format: 'MM'},
18+
{start: 5, end: 6, type: DatePart.Literal, format: '/'},
19+
{start: 6, end: 10, type: DatePart.Year, format: 'yyyy'},
20+
{start: 10, end: 11, type: DatePart.Literal, format: ' '},
21+
{start: 11, end: 13, type: DatePart.Hours, format: 'HH'},
22+
{start: 13, end: 14, type: DatePart.Literal, format: ':'},
23+
{start: 14, end: 16, type: DatePart.Minutes, format: 'mm'},
24+
{start: 16, end: 17, type: DatePart.Literal, format: ':'},
25+
{start: 17, end: 19, type: DatePart.Seconds, format: 'ss'},
26+
{start: 19, end: 20, type: DatePart.Literal, format: ' '},
27+
{start: 20, end: 22, type: DatePart.AmPm, format: 'tt'}
28+
];
29+
expect(JSON.stringify(result)).toEqual(JSON.stringify(expected));
30+
});
31+
32+
it('should correctly parse date parts of with short formats', () => {
33+
let result = DatePickerUtil.parseDateTimeFormat('MM/dd/yyyy');
34+
let resDict = reduceToDictionary(result);
35+
expect(result.length).toEqual(5);
36+
expect(resDict[DatePart.Month]).toEqual(jasmine.objectContaining({ start: 0, end: 2 }));
37+
expect(resDict[DatePart.Date]).toEqual(jasmine.objectContaining({ start: 3, end: 5 }));
38+
expect(resDict[DatePart.Year]).toEqual(jasmine.objectContaining({ start: 6, end: 10 }));
39+
40+
result = DatePickerUtil.parseDateTimeFormat('M/d/yy');
41+
resDict = reduceToDictionary(result);
42+
expect(result.length).toEqual(5);
43+
expect(resDict[DatePart.Month]).toEqual(jasmine.objectContaining({ start: 0, end: 2 }));
44+
expect(resDict[DatePart.Date]).toEqual(jasmine.objectContaining({ start: 3, end: 5 }));
45+
expect(resDict[DatePart.Year]).toEqual(jasmine.objectContaining({ start: 6, end: 8 }));
46+
47+
result = DatePickerUtil.parseDateTimeFormat('dd.MM.yyyy г.');
48+
resDict = reduceToDictionary(result);
49+
expect(result.length).toEqual(6);
50+
expect(resDict[DatePart.Date]).toEqual(jasmine.objectContaining({ start: 0, end: 2 }));
51+
expect(resDict[DatePart.Month]).toEqual(jasmine.objectContaining({ start: 3, end: 5 }));
52+
expect(resDict[DatePart.Year]).toEqual(jasmine.objectContaining({ start: 6, end: 10 }));
53+
54+
return; // TODO
55+
result = DatePickerUtil.parseDateTimeFormat('dd.MM.yyyyг');
56+
resDict = reduceToDictionary(result);
57+
expect(result.length).toEqual(6);
58+
expect(resDict[DatePart.Date]).toEqual(jasmine.objectContaining({ start: 0, end: 2 }));
59+
expect(resDict[DatePart.Month]).toEqual(jasmine.objectContaining({ start: 3, end: 5 }));
60+
expect(resDict[DatePart.Year]).toEqual(jasmine.objectContaining({ start: 6, end: 10 }));
61+
expect(result[5]?.format).toEqual('г');
62+
63+
result = DatePickerUtil.parseDateTimeFormat('yyyy/MM/d');
64+
resDict = reduceToDictionary(result);
65+
expect(result.length).toEqual(5);
66+
expect(resDict[DatePart.Year]).toEqual(jasmine.objectContaining({ start: 0, end: 4 }));
67+
expect(resDict[DatePart.Month]).toEqual(jasmine.objectContaining({ start: 5, end: 7 }));
68+
expect(resDict[DatePart.Date]).toEqual(jasmine.objectContaining({ start: 8, end: 10 }));
69+
});
70+
});

0 commit comments

Comments
 (0)