tachybase_todo/packages/core/utils/src/parse-date.ts
被雨水过滤的空气-Rairn 098140d511
feat(parse-variables): support to parse variables in filter params (#1558)
* fix: add field linkage on setting default datetime

* fix: fix dateonly timezone problem

* fix: improve test

* docs(DatePicker): add demos

* fix(DatePicker): should return the beginning of a second

* feat(DatePicker): support non-UTC

* refactor: rename

* fix(RangePicker): get correct end date

* test(mapDatePicker): add test

* test(mapRangePicker): add test

* feat(Filter): use non-UTC to filter

* feat(FilterBlock): use non-UTC to filter

* feat: add '$dateBetween' operator in datetime

* feat: use RangePicker on toggled to 'dateBetween' operator

* feat: set ranges for RangePicker

* feat: backend support to parse 'dateBetween' operator

* fix: fix build error

* fix: adaptive content width

* feat: support to use var on data scope

* feat: add parse-variables plugin

* feat: support to parse variables

* feat: support only to set system variables

* test: rename

* feat: cover all

* fix: fix build error

* feat(RangePicker): extend more shortcut keys

* feat(parse-variables): support more date var

* feat: support user variables

* feat: disable unmatched options

* fix: use component name to filter option

* fix: fix build error

* feat: remove some operator of id

* chore: remove useless operators

* fix: built in plugin

* refactor: move to core from plugin

* refactor: remove code of plugin

* refactor: remove useless code

* fix: should after acl

* Update server.ts

* fix: compatible with old version

* feat: test cases

* refactor: rename to 'is between'

* refactor: parse filter

* fix: improve code

* feat: test cases

* fix: fix error

* fix: improve parse date

* fix: date variables

* fix: day range

* fix: test error

* fix: typo

* fix: test error

* feat: $user variable

* fix: toDate

* fix: fix the value range of shortcuts

* feat: add quarter and test

* feat: support to use user's association fields to filter

* refactor: use maxDepth

* refactor: remove useless code

* fix: make AssociationSelect.Designer to support variables

* fix: getField

* fix: parse utc

* fix: remove only

* fix: filter by ctx.db.getFieldByPath

* fix: avoid error

* fix: add translation

* fix(RangePicker): can be set to empty

* feat(utils): add hasEmptyValue

* fix: should not save empty

* fix: last few days should include today

* fix: limit user variable type to display

* fix: parse filter error

* fix: empty

* test: [skip ci]

* fix: remove ';'

* feat: improve code

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
2023-03-30 23:49:57 +08:00

214 lines
4.4 KiB
TypeScript

import moment from 'moment';
function parseUTC(value) {
if (moment.isDate(value) || moment.isMoment(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\d\Q\d$/.test(value)) {
return {
unit: 'quarter',
start: moment(value, 'YYYY[Q]Q').format('YYYY-MM-DD HH:mm:ss'),
};
}
}
function parseWeek(value) {
if (/^\d\d\d\d[W]\d\d$/.test(value)) {
return {
unit: 'isoWeek',
start: moment(value, 'GGGG[W]W').format('YYYY-MM-DD HH:mm:ss'),
};
}
if (/^\d\d\d\d[w]\d\d$/.test(value)) {
return {
unit: 'week',
start: moment(value, 'gggg[w]w').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: moment.Moment) {
return m.toISOString();
}
function dateRange(r: ParseDateResult) {
if (!r.timezone) {
r.timezone = '+00:00';
}
let m: moment.Moment;
if (r.unit === 'utc') {
return moment(r?.start).toISOString();
} else {
m = moment(`${r?.start}${r?.timezone}`);
}
m = m.utcOffset(r.timezone);
return [m.startOf(r.unit), m.clone().add(1, 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]);
}