Skip to content

Commit e10d4ab

Browse files
chenluliLAI-X
authored andcommitted
feat(ava/data): add function to parse ISO datetime string to js Date type
1 parent 95d413b commit e10d4ab

File tree

2 files changed

+55
-11
lines changed

2 files changed

+55
-11
lines changed

packages/ava/src/data/utils/isType/constants.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@ export const SPECIAL_BOOLEANS = [
1010

1111
// For isDateString.ts
1212
export const DELIMITER = '([-_./\\s])';
13-
export const YEAR = '(18|19|20)\\d{2}';
14-
export const MONTH = '(0?[1-9]|1[012])';
15-
export const DAY = '(0?[1-9]|[12]\\d|3[01])';
16-
export const WEEK = '([0-4]\\d|5[0-2])';
17-
export const WEEKDAY = '([1-7])';
18-
export const HOUR = '(0?\\d|1\\d|2[0-4])';
19-
export const MINUTE = '(0?\\d|[012345]\\d)';
20-
export const SECOND = MINUTE;
21-
export const MILLISECOND = '\\d{1,4}';
22-
export const YEARDAY = '((([0-2]\\d|3[0-5])\\d)|36[0-6])';
23-
export const OFFSET = `(Z|[+-]${HOUR}(:${MINUTE})?)`;
13+
export const YEAR = '(?<year>(18|19|20)\\d{2})';
14+
export const MONTH = '(?<month>0?[1-9]|1[012])';
15+
export const DAY = '(?<day>0?[1-9]|[12]\\d|3[01])';
16+
export const WEEK = '(?<week>[0-4]\\d|5[0-2])';
17+
export const WEEKDAY = '(?<weekday>[1-7])';
18+
export const BASE_HOUR = '(0?\\d|1\\d|2[0-4])';
19+
export const BASE_MINUTE = '(0?\\d|[012345]\\d)';
20+
export const HOUR = `(?<hour>${BASE_MINUTE})`;
21+
export const MINUTE = `(?<minute>${BASE_MINUTE})`;
22+
export const SECOND = `(?<second>${BASE_MINUTE})`;
23+
export const MILLISECOND = '(?<millisecond>\\d{1,4})';
24+
export const YEARDAY = '(?<yearDay>(([0-2]\\d|3[0-5])\\d)|36[0-6])';
25+
export const OFFSET = `(?<offset>Z|[+-]${BASE_HOUR}(:${BASE_MINUTE})?)`;

packages/ava/src/data/utils/isType/isDateString.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,45 @@ export function isDateString(value: unknown, strictDatePattern?: boolean): value
8181
}
8282
return false;
8383
}
84+
85+
/** parse ISO 8601 date string to standard Date type, if month and date is missing, will use new Date(01-01)
86+
* Reference: https://www.cl.cam.ac.uk/~mgk25/iso-time.html
87+
* 将日期字符串转为标准 Date 类型,如果没有月日,只有时间信息,会默认为 01-01
88+
*/
89+
export function parseIsoDateString(value: string, strictDatePattern: boolean = false): Date | null {
90+
const isoDateAndTimeRegs = getIsoDateAndTimeRegs(strictDatePattern);
91+
for (let i = 0; i < isoDateAndTimeRegs.length; i += 1) {
92+
const reg = isoDateAndTimeRegs[i];
93+
if (reg.test(value.trim())) {
94+
const matches = value.trim().match(reg);
95+
if (matches.groups) {
96+
const { year, month, day, week, weekday, hour, minute, second, millisecond, yearDay, offset } =
97+
matches.groups || {};
98+
const yearNum = parseInt(year, 10);
99+
if (yearDay) {
100+
return new Date(yearNum, 0, parseInt(yearDay, 10));
101+
}
102+
103+
if (week) {
104+
const weekNum = parseInt(week, 10);
105+
const weekDayNum = weekday ? parseInt(weekday, 10) : 1;
106+
const firstDayOfYear = new Date(yearNum, 0, 1);
107+
// 给定年份的第一天是周几
108+
const firstDayOfYearDayOfWeek = firstDayOfYear.getDay() === 0 ? 7 : firstDayOfYear.getDay();
109+
// 计算第一周的第一天相对 firstDayOfYear 的偏移量
110+
const firstWeekStartDayOffset = firstDayOfYearDayOfWeek === 1 ? 1 : 1 - firstDayOfYearDayOfWeek;
111+
// 目标日期偏移量
112+
const targetDateOffset = (weekNum - 1) * 7 + (weekDayNum + firstWeekStartDayOffset);
113+
return new Date(yearNum, 0, targetDateOffset);
114+
}
115+
116+
const formattedDateString = [year, month ?? '01', day ?? '01'].join('-');
117+
const formattedTimeString = `${[hour ?? '00', minute ?? '00', second ?? '00'].join(':')}.${
118+
millisecond ?? '000'
119+
}${offset ?? ''}`;
120+
return new Date(`${formattedDateString} ${formattedTimeString}`);
121+
}
122+
}
123+
}
124+
return null;
125+
}

0 commit comments

Comments
 (0)