tachybase_todo/packages/core/utils/src/parse-date.ts
被雨水过滤的空气-Rain 34b0ce06ba
fix: fix quarter variables (#2648)
2023-09-14 17:56:42 +08:00

220 lines
4.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { offsetFromString } from './date';
import { dayjs } from './dayjs';
function parseUTC(value) {
if (value instanceof Date || dayjs.isDayjs(value)) {
return {
unit: 'utc',
start: value.toISOString(),
};
}
if (value.endsWith('Z')) {
return {
unit: 'utc',
start: value,
};
}
}
function parseYear(value) {
if (/^\d\d\d\d$/.test(value)) {
return {
unit: 'year',
start: `${value}-01-01 00:00:00`,
};
}
}
function parseQuarter(value) {
if (/^\d\d\d\dQ\d$/.test(value)) {
const [year, q] = value.split('Q');
return {
unit: 'quarter',
start: dayjs(year, 'YYYY').quarter(q).format('YYYY-MM-DD HH:mm:ss'),
};
}
}
function parseWeek(value) {
if (/^\d\d\d\d[W]\d\d$/.test(value)) {
const arr = value.split('W');
// dayjs 还不支持 dayjs("2019W19","gggg[W]ww") 这种语法
// 参见https://github.com/iamkun/dayjs/issues/784
return {
unit: 'isoWeek',
start: dayjs(arr[0], 'YYYY').add(Number(arr[1]), 'weeks').format('YYYY-MM-DD HH:mm:ss'),
};
}
if (/^\d\d\d\d[w]\d\d$/.test(value)) {
const arr = value.split('w');
return {
unit: 'week',
start: dayjs(arr[0], 'YYYY').week(Number(arr[1])).format('YYYY-MM-DD HH:mm:ss'),
};
}
}
function parseMonth(value) {
if (/^\d\d\d\d\-\d\d$/.test(value)) {
return {
unit: 'month',
start: `${value}-01 00:00:00`,
};
}
}
function parseDay(value) {
if (/^\d\d\d\d\-\d\d\-\d\d$/.test(value)) {
return {
unit: 'day',
start: `${value} 00:00:00`,
};
}
}
function parseHour(value) {
if (/^\d\d\d\d\-\d\d\-\d\d(\T|\s)\d\d$/.test(value)) {
return {
unit: 'hour',
start: `${value}:00:00`,
};
}
}
function parseMinute(value) {
if (/^\d\d\d\d\-\d\d\-\d\d(\T|\s)\d\d\:\d\d$/.test(value)) {
return {
unit: 'minute',
start: `${value}:00`,
};
}
}
function parseSecond(value) {
if (/^\d\d\d\d\-\d\d\-\d\d(\T|\s)\d\d\:\d\d\:\d\d$/.test(value)) {
return {
unit: 'second',
start: `${value}`,
};
}
}
function parseMillisecond(value) {
if (/^\d\d\d\d\-\d\d\-\d\d(\T|\s)\d\d\:\d\d\:\d\d\.\d\d\d$/.test(value)) {
return {
unit: 'millisecond',
start: `${value}`,
};
}
}
const parsers = [
parseUTC,
parseYear,
parseQuarter,
parseWeek,
parseMonth,
parseDay,
parseHour,
parseMinute,
parseSecond,
parseMillisecond,
];
type ParseDateResult = {
unit: any;
start: string;
timezone?: string;
};
function toISOString(m: dayjs.Dayjs) {
return m.toISOString();
}
function dateRange(r: ParseDateResult) {
if (!r.timezone) {
r.timezone = '+00:00';
}
let m: dayjs.Dayjs;
if (r.unit === 'utc') {
return dayjs(r?.start).toISOString();
} else {
m = dayjs(`${r?.start}${r?.timezone}`);
}
m = m.utcOffset(offsetFromString(r.timezone));
return [(m = m.startOf(r.unit)), m.add(1, r.unit === 'isoWeek' ? 'weeks' : r.unit).startOf(r.unit)].map(toISOString);
}
export function parseDate(value: any, options = {} as { timezone?: string }) {
if (!value) {
return;
}
if (Array.isArray(value)) {
return parseDateBetween(value, options);
}
let timezone = options.timezone || '+00:00';
const input = value;
if (typeof value === 'string') {
const match = /(.+)((\+|\-)\d\d\:\d\d)$/.exec(value);
if (match) {
value = match[1];
timezone = match[2];
}
if (/^(\(|\[)/.test(value)) {
return parseDateBetween(input, options);
}
}
for (const parse of parsers) {
const r = parse(value);
if (r) {
r['input'] = input;
if (!r['timezone']) {
r['timezone'] = timezone;
}
return dateRange(r);
}
}
}
function parseDateBetween(value: any, options = {} as { timezone?: string }) {
if (Array.isArray(value) && value.length > 1) {
const [startValue, endValue, op = '[]', timezone] = value;
const r0 = parseDate(startValue, { timezone });
const r1 = parseDate(endValue, { timezone });
let start;
let startOp;
let end;
let endOp;
if (typeof r0 === 'string') {
start = r0;
startOp = op[0];
} else {
start = op.startsWith('(') ? r0[1] : r0[0];
startOp = '[';
}
if (typeof r1 === 'string') {
end = r1;
endOp = op[1];
} else {
end = op.endsWith(')') ? r1[0] : r1[1];
endOp = ')';
}
const newOp = startOp + endOp;
return newOp === '[)' ? [start, end] : [start, end, newOp];
}
if (typeof value !== 'string') {
return;
}
const match = /(.+)((\+|\-)\d\d\:\d\d)$/.exec(value);
let timezone = options.timezone || '+00:00';
if (match) {
value = match[1];
timezone = match[2];
}
const m = /^(\(|\[)(.+)\,(.+)(\)|\])$/.exec(value);
if (!m) {
return;
}
return parseDateBetween([m[2], m[3], `${m[1]}${m[4]}`, timezone]);
}