feat: 🎸 added higher resoulution options in the dateTime Filter (#16548)

Title: "feat: Add second, minute & hour resolution options to relative
date Filter action"
---

## Summary

This PR enables support for smaller time units — **Seconds, Minutes, and
Hours** — in the *Relative Date* filter used in workflows, rather than
being limited to days only.

---

## What Changed

This PR extends the relative date filter to include support for the
following units:

✔️ `SECOND`  
✔️ `MINUTE`  
✔️ `HOUR`  
✔️ (Existing: `DAY`, `WEEK`, `MONTH`, etc.)

Changes include:

- Adding `SECOND`, `MINUTE`, and `HOUR` options to the internal relative
date unit enum/constant.
- Updating utility functions and parsers to correctly interpret and
evaluate these new units.
- Enhancing existing tests and adding new tests to cover second, minute,
and hour relative filters.

---

## Testing

New and updated tests include:

- Unit tests for serialization of relative filter values including
seconds, minutes, and hours.
- Workflow filter evaluation tests that verify minute/hour resolution
behaves correctly.

Tests are included in the changeset.

---

## Backward Compatibility

This change is fully backward compatible:

- All existing relative date filters using days or larger units behave
exactly as before.
- Adding finer units does not alter existing stored data or workflow
definitions.

---

##  Issue Reference

Fixes: **twentyhq/twenty#15525**  

<img width="1909" height="896" alt="image"
src="https://github.com/user-attachments/assets/328d03dc-ca0b-4c3f-84e5-58961c178398"
/>

---------

Co-authored-by: Guillim <guillim@users.noreply.github.com>
Co-authored-by: guillim <guigloo@msn.com>
This commit is contained in:
Bhoomaahamso
2025-12-17 22:16:11 +05:30
committed by GitHub
parent 100d4f7f42
commit a560e8ac83
15 changed files with 616 additions and 6 deletions
@@ -15,12 +15,14 @@ export type FormRelativeDatePickerProps = {
defaultValue?: string;
onChange: (value: RelativeDateFilter) => void;
readonly?: boolean;
isDateTimeField?: boolean;
};
export const FormRelativeDatePicker = ({
defaultValue,
onChange,
readonly,
isDateTimeField,
}: FormRelativeDatePickerProps) => {
const instanceId = useId();
@@ -48,6 +50,7 @@ export const FormRelativeDatePicker = ({
isFormField={true}
readonly={readonly}
unitDropdownWidth={150}
allowIntraDayUnits={isDateTimeField}
/>
);
};
@@ -491,6 +491,7 @@ export const DateTimePicker = ({
amount={relativeDate?.amount}
unit={relativeDate?.unit ?? 'DAY'}
onChange={onRelativeDateChange}
allowIntraDayUnits={true}
/>
) : (
<DateTimePickerHeader
@@ -1,6 +1,7 @@
import { Select } from '@/ui/input/components/Select';
import { SettingsTextInput } from '@/ui/input/components/SettingsTextInput';
import { RELATIVE_DATE_DIRECTION_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateDirectionSelectOptions';
import { RELATIVE_DATETIME_UNITS_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateTimeUnitSelectOptions';
import { RELATIVE_DATE_UNITS_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateUnitSelectOptions';
import styled from '@emotion/styled';
@@ -30,6 +31,7 @@ type RelativeDatePickerHeaderProps = {
isFormField?: boolean;
readonly?: boolean;
unitDropdownWidth?: number;
allowIntraDayUnits?: boolean;
};
export const RelativeDatePickerHeader = ({
@@ -41,6 +43,7 @@ export const RelativeDatePickerHeader = ({
onChange,
readonly,
unitDropdownWidth,
allowIntraDayUnits,
}: RelativeDatePickerHeaderProps) => {
const amountString = amount?.toString() ?? '';
@@ -50,7 +53,10 @@ export const RelativeDatePickerHeader = ({
const [draftAmountValue, setDraftAmountValue] = useState(amountTextValue);
const isUnitPlural = amount && amount > 1 && direction !== 'THIS';
const unitSelectOptions = RELATIVE_DATE_UNITS_SELECT_OPTIONS.map((unit) => ({
const unitOptionsSource = allowIntraDayUnits
? RELATIVE_DATETIME_UNITS_SELECT_OPTIONS
: RELATIVE_DATE_UNITS_SELECT_OPTIONS;
const unitSelectOptions = unitOptionsSource.map((unit) => ({
...unit,
label: `${unit.label}${isUnitPlural ? 's' : ''}`,
}));
@@ -0,0 +1,15 @@
import { RELATIVE_DATE_UNITS_SELECT_OPTIONS } from '@/ui/input/components/internal/date/constants/RelativeDateUnitSelectOptions';
import { type RelativeDateFilterUnit } from 'twenty-shared/utils';
type RelativeDateUnitOption = {
value: RelativeDateFilterUnit;
label: string;
};
export const RELATIVE_DATETIME_UNITS_SELECT_OPTIONS: RelativeDateUnitOption[] =
[
...RELATIVE_DATE_UNITS_SELECT_OPTIONS,
{ value: 'HOUR', label: 'Hour' },
{ value: 'MINUTE', label: 'Minute' },
{ value: 'SECOND', label: 'Second' },
];
@@ -38,6 +38,21 @@ describe('stringifyRelativeDateFilter', () => {
});
it('should stringify with different units', () => {
const secondFilter: RelativeDateFilter = {
direction: 'PAST',
amount: 1,
unit: 'SECOND',
};
const minuteFilter: RelativeDateFilter = {
direction: 'PAST',
amount: 1,
unit: 'MINUTE',
};
const hourFilter: RelativeDateFilter = {
direction: 'PAST',
amount: 1,
unit: 'HOUR',
};
const dayFilter: RelativeDateFilter = {
direction: 'PAST',
amount: 1,
@@ -59,6 +74,9 @@ describe('stringifyRelativeDateFilter', () => {
unit: 'YEAR',
};
expect(stringifyRelativeDateFilter(secondFilter)).toBe('PAST_1_SECOND');
expect(stringifyRelativeDateFilter(minuteFilter)).toBe('PAST_1_MINUTE');
expect(stringifyRelativeDateFilter(hourFilter)).toBe('PAST_1_HOUR');
expect(stringifyRelativeDateFilter(dayFilter)).toBe('PAST_1_DAY');
expect(stringifyRelativeDateFilter(weekFilter)).toBe('PAST_1_WEEK');
expect(stringifyRelativeDateFilter(monthFilter)).toBe('PAST_1_MONTH');
@@ -134,6 +134,8 @@ export const WorkflowStepFilterValueInput = ({
variableType === FieldMetadataType.DATE_TIME ||
variableType === FieldMetadataType.DATE;
const isDateTimeField = variableType === FieldMetadataType.DATE_TIME;
const isRelativeDateFilter =
isDateField && stepFilter.operand === ViewFilterOperand.IS_RELATIVE;
@@ -201,6 +203,7 @@ export const WorkflowStepFilterValueInput = ({
defaultValue={relativeDateFilterValue}
onChange={handleRelativeDateFilterChange}
readonly={readonly}
isDateTimeField={isDateTimeField}
/>
);
}
@@ -1,10 +1,16 @@
import {
addDays,
addHours,
addMinutes,
addMonths,
addSeconds,
addWeeks,
addYears,
subDays,
subHours,
subMinutes,
subMonths,
subSeconds,
subWeeks,
subYears,
} from 'date-fns';
@@ -104,6 +110,133 @@ describe('Relative Date Filter Utils', () => {
describe('evaluateRelativeDateFilter', () => {
describe('NEXT direction', () => {
it('should return true for dates within the next N seconds', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'NEXT',
amount: 3,
unit: 'SECOND',
};
// Dates within the next 3 seconds should match
expect(
evaluateRelativeDateFilter({
dateToCheck: addSeconds(now, 1),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: addSeconds(now, 2),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: addSeconds(now, 3),
relativeDateFilterValue,
}),
).toBe(true);
// Dates outside the range should not match
expect(
evaluateRelativeDateFilter({
dateToCheck: addSeconds(now, 4),
relativeDateFilterValue,
}),
).toBe(false);
expect(
evaluateRelativeDateFilter({
dateToCheck: subSeconds(now, 1),
relativeDateFilterValue,
}),
).toBe(false);
});
it('should return true for dates within the next N minutes', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'NEXT',
amount: 3,
unit: 'MINUTE',
};
// Dates within the next 3 minutes should match
expect(
evaluateRelativeDateFilter({
dateToCheck: addMinutes(now, 1),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: addMinutes(now, 2),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: addMinutes(now, 3),
relativeDateFilterValue,
}),
).toBe(true);
// Dates outside the range should not match
expect(
evaluateRelativeDateFilter({
dateToCheck: addMinutes(now, 4),
relativeDateFilterValue,
}),
).toBe(false);
expect(
evaluateRelativeDateFilter({
dateToCheck: subMinutes(now, 1),
relativeDateFilterValue,
}),
).toBe(false);
});
it('should return true for dates within the next N hours', () => {
///
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'NEXT',
amount: 3,
unit: 'HOUR',
};
// Dates within the next 3 hours should match
expect(
evaluateRelativeDateFilter({
dateToCheck: addHours(now, 1),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: addHours(now, 2),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: addHours(now, 3),
relativeDateFilterValue,
}),
).toBe(true);
// Dates outside the range should not match
expect(
evaluateRelativeDateFilter({
dateToCheck: addHours(now, 4),
relativeDateFilterValue,
}),
).toBe(false);
expect(
evaluateRelativeDateFilter({
dateToCheck: subHours(now, 1),
relativeDateFilterValue,
}),
).toBe(false);
});
it('should return true for dates within the next N days', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'NEXT',
@@ -270,6 +403,132 @@ describe('Relative Date Filter Utils', () => {
});
describe('PAST direction', () => {
it('should return true for dates within the past N seconds', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'PAST',
amount: 3,
unit: 'SECOND',
};
// Dates within the past 3 seconds should match
expect(
evaluateRelativeDateFilter({
dateToCheck: subSeconds(now, 1),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: subSeconds(now, 2),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: subSeconds(now, 3),
relativeDateFilterValue,
}),
).toBe(true);
// Dates outside the range should not match
expect(
evaluateRelativeDateFilter({
dateToCheck: subSeconds(now, 4),
relativeDateFilterValue,
}),
).toBe(false);
expect(
evaluateRelativeDateFilter({
dateToCheck: addSeconds(now, 1),
relativeDateFilterValue,
}),
).toBe(false);
});
it('should return true for dates within the past N minutes', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'PAST',
amount: 3,
unit: 'MINUTE',
};
// Dates within the past 3 minutes should match
expect(
evaluateRelativeDateFilter({
dateToCheck: subMinutes(now, 1),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: subMinutes(now, 2),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: subMinutes(now, 3),
relativeDateFilterValue,
}),
).toBe(true);
// Dates outside the range should not match
expect(
evaluateRelativeDateFilter({
dateToCheck: subMinutes(now, 4),
relativeDateFilterValue,
}),
).toBe(false);
expect(
evaluateRelativeDateFilter({
dateToCheck: addMinutes(now, 1),
relativeDateFilterValue,
}),
).toBe(false);
});
it('should return true for dates within the past N hours', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'PAST',
amount: 3,
unit: 'HOUR',
};
// Dates within the past 3 hours should match
expect(
evaluateRelativeDateFilter({
dateToCheck: subHours(now, 1),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: subHours(now, 2),
relativeDateFilterValue,
}),
).toBe(true);
expect(
evaluateRelativeDateFilter({
dateToCheck: subHours(now, 3),
relativeDateFilterValue,
}),
).toBe(true);
// Dates outside the range should not match
expect(
evaluateRelativeDateFilter({
dateToCheck: subHours(now, 4),
relativeDateFilterValue,
}),
).toBe(false);
expect(
evaluateRelativeDateFilter({
dateToCheck: addHours(now, 1),
relativeDateFilterValue,
}),
).toBe(false);
});
it('should return true for dates within the past N days', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'PAST',
@@ -436,6 +695,93 @@ describe('Relative Date Filter Utils', () => {
});
describe('THIS direction', () => {
it('should return true for dates within this second', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'THIS',
unit: 'SECOND',
};
// Same second should match
expect(
evaluateRelativeDateFilter({
dateToCheck: now,
relativeDateFilterValue,
}),
).toBe(true);
// Different seconds should not match
expect(
evaluateRelativeDateFilter({
dateToCheck: new Date('2024-01-15T08:00:00Z'),
relativeDateFilterValue,
}),
).toBe(false);
expect(
evaluateRelativeDateFilter({
dateToCheck: subSeconds(now, 1),
relativeDateFilterValue,
}),
).toBe(false);
});
it('should return true for dates within this minute', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'THIS',
unit: 'MINUTE',
};
// Same minute should match
expect(
evaluateRelativeDateFilter({
dateToCheck: now,
relativeDateFilterValue,
}),
).toBe(true);
// Different minutes should not match
expect(
evaluateRelativeDateFilter({
dateToCheck: new Date('2024-01-15T08:00:00Z'),
relativeDateFilterValue,
}),
).toBe(false);
expect(
evaluateRelativeDateFilter({
dateToCheck: subMinutes(now, 1),
relativeDateFilterValue,
}),
).toBe(false);
});
it('should return true for dates within this hour', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'THIS',
unit: 'HOUR',
};
// Same hour should match
expect(
evaluateRelativeDateFilter({
dateToCheck: now,
relativeDateFilterValue,
}),
).toBe(true);
// Different hours should not match
expect(
evaluateRelativeDateFilter({
dateToCheck: new Date('2024-01-15T08:00:00Z'),
relativeDateFilterValue,
}),
).toBe(false);
expect(
evaluateRelativeDateFilter({
dateToCheck: subHours(now, 1),
relativeDateFilterValue,
}),
).toBe(false);
});
it('should return true for dates within this day', () => {
const relativeDateFilterValue: RelativeDateFilter = {
direction: 'THIS',
@@ -1,12 +1,18 @@
import { isNonEmptyString } from '@sniptt/guards';
import {
endOfDay,
endOfHour,
endOfSecond,
endOfMinute,
endOfMonth,
endOfWeek,
endOfYear,
isWithinInterval,
startOfDay,
startOfHour,
startOfMinute,
startOfMonth,
startOfSecond,
startOfWeek,
startOfYear,
} from 'date-fns';
@@ -122,6 +128,21 @@ function evaluateThisDirection(
: 1;
switch (unit) {
case 'SECOND':
return isWithinInterval(dateToCheck, {
start: startOfSecond(now),
end: endOfSecond(now),
});
case 'MINUTE':
return isWithinInterval(dateToCheck, {
start: startOfMinute(now),
end: endOfMinute(now),
});
case 'HOUR':
return isWithinInterval(dateToCheck, {
start: startOfHour(now),
end: endOfHour(now),
});
case 'DAY':
return isWithinInterval(dateToCheck, {
start: startOfDay(now),
@@ -3,6 +3,54 @@ import { safeParseRelativeDateFilterJSONStringified } from '@/utils/safeParseRel
describe('safeParseRelativeDateFilterJSONStringified', () => {
describe('valid inputs', () => {
describe('NEXT direction', () => {
it('should parse NEXT direction with SECOND unit', () => {
const input = JSON.stringify({
direction: 'NEXT',
amount: 30,
unit: 'SECOND',
});
const result = safeParseRelativeDateFilterJSONStringified(input);
expect(result).toEqual({
direction: 'NEXT',
amount: 30,
unit: 'SECOND',
});
});
it('should parse NEXT direction with MINUTE unit', () => {
const input = JSON.stringify({
direction: 'NEXT',
amount: 15,
unit: 'MINUTE',
});
const result = safeParseRelativeDateFilterJSONStringified(input);
expect(result).toEqual({
direction: 'NEXT',
amount: 15,
unit: 'MINUTE',
});
});
it('should parse NEXT direction with HOUR unit', () => {
const input = JSON.stringify({
direction: 'NEXT',
amount: 6,
unit: 'HOUR',
});
const result = safeParseRelativeDateFilterJSONStringified(input);
expect(result).toEqual({
direction: 'NEXT',
amount: 6,
unit: 'HOUR',
});
});
it('should parse NEXT direction with DAY unit', () => {
const input = JSON.stringify({
direction: 'NEXT',
@@ -69,6 +117,54 @@ describe('safeParseRelativeDateFilterJSONStringified', () => {
});
describe('PAST direction', () => {
it('should parse PAST direction with SECOND unit', () => {
const input = JSON.stringify({
direction: 'PAST',
amount: 45,
unit: 'SECOND',
});
const result = safeParseRelativeDateFilterJSONStringified(input);
expect(result).toEqual({
direction: 'PAST',
amount: 45,
unit: 'SECOND',
});
});
it('should parse PAST direction with MINUTE unit', () => {
const input = JSON.stringify({
direction: 'PAST',
amount: 20,
unit: 'MINUTE',
});
const result = safeParseRelativeDateFilterJSONStringified(input);
expect(result).toEqual({
direction: 'PAST',
amount: 20,
unit: 'MINUTE',
});
});
it('should parse PAST direction with HOUR unit', () => {
const input = JSON.stringify({
direction: 'PAST',
amount: 5,
unit: 'HOUR',
});
const result = safeParseRelativeDateFilterJSONStringified(input);
expect(result).toEqual({
direction: 'PAST',
amount: 5,
unit: 'HOUR',
});
});
it('should parse PAST direction with DAY unit', () => {
const input = JSON.stringify({
direction: 'PAST',
@@ -135,6 +231,48 @@ describe('safeParseRelativeDateFilterJSONStringified', () => {
});
describe('THIS direction', () => {
it('should parse THIS direction with SECOND unit (no amount)', () => {
const input = JSON.stringify({
direction: 'THIS',
unit: 'SECOND',
});
const result = safeParseRelativeDateFilterJSONStringified(input);
expect(result).toEqual({
direction: 'THIS',
unit: 'SECOND',
});
});
it('should parse THIS direction with MINUTE unit (no amount)', () => {
const input = JSON.stringify({
direction: 'THIS',
unit: 'MINUTE',
});
const result = safeParseRelativeDateFilterJSONStringified(input);
expect(result).toEqual({
direction: 'THIS',
unit: 'MINUTE',
});
});
it('should parse THIS direction with HOUR unit (no amount)', () => {
const input = JSON.stringify({
direction: 'THIS',
unit: 'HOUR',
});
const result = safeParseRelativeDateFilterJSONStringified(input);
expect(result).toEqual({
direction: 'THIS',
unit: 'HOUR',
});
});
it('should parse THIS direction with DAY unit (no amount)', () => {
const input = JSON.stringify({
direction: 'THIS',
@@ -1,5 +1,13 @@
import { type RelativeDateFilterUnit } from '@/utils/filter/dates/utils/relativeDateFilterUnitSchema';
import { addDays, addMonths, addWeeks, addYears } from 'date-fns';
import {
addDays,
addHours,
addMinutes,
addMonths,
addSeconds,
addWeeks,
addYears,
} from 'date-fns';
export const addUnitToDateTime = (
dateTime: Date,
@@ -7,6 +15,12 @@ export const addUnitToDateTime = (
unit: RelativeDateFilterUnit,
) => {
switch (unit) {
case 'SECOND':
return addSeconds(dateTime, amount);
case 'MINUTE':
return addMinutes(dateTime, amount);
case 'HOUR':
return addHours(dateTime, amount);
case 'DAY':
return addDays(dateTime, amount);
case 'WEEK':
@@ -3,7 +3,15 @@ import { type FirstDayOfTheWeek } from '@/utils/filter/dates/utils/firstDayOfWee
import { getFirstDayOfTheWeekAsANumberForDateFNS } from '@/utils/filter/dates/utils/getFirstDayOfTheWeekAsANumberForDateFNS';
import { type RelativeDateFilterUnit } from '@/utils/filter/dates/utils/relativeDateFilterUnitSchema';
import { isDefined } from '@/utils/validation';
import { endOfDay, endOfMonth, endOfWeek, endOfYear } from 'date-fns';
import {
endOfDay,
endOfHour,
endOfMinute,
endOfMonth,
endOfSecond,
endOfWeek,
endOfYear,
} from 'date-fns';
export const getEndUnitOfDateTime = (
dateTime: Date,
@@ -11,6 +19,12 @@ export const getEndUnitOfDateTime = (
firstDayOfTheWeek?: Nullable<FirstDayOfTheWeek>,
) => {
switch (unit) {
case 'SECOND':
return endOfSecond(dateTime);
case 'MINUTE':
return endOfMinute(dateTime);
case 'HOUR':
return endOfHour(dateTime);
case 'DAY':
return endOfDay(dateTime);
case 'WEEK': {
@@ -3,7 +3,15 @@ import { type FirstDayOfTheWeek } from '@/utils/filter/dates/utils/firstDayOfWee
import { getFirstDayOfTheWeekAsANumberForDateFNS } from '@/utils/filter/dates/utils/getFirstDayOfTheWeekAsANumberForDateFNS';
import { type RelativeDateFilterUnit } from '@/utils/filter/dates/utils/relativeDateFilterUnitSchema';
import { isDefined } from '@/utils/validation';
import { startOfDay, startOfMonth, startOfWeek, startOfYear } from 'date-fns';
import {
startOfDay,
startOfHour,
startOfMinute,
startOfMonth,
startOfSecond,
startOfWeek,
startOfYear,
} from 'date-fns';
export const getStartUnitOfDateTime = (
dateTime: Date,
@@ -11,6 +19,12 @@ export const getStartUnitOfDateTime = (
firstDayOfTheWeek?: Nullable<FirstDayOfTheWeek>,
) => {
switch (unit) {
case 'SECOND':
return startOfSecond(dateTime);
case 'MINUTE':
return startOfMinute(dateTime);
case 'HOUR':
return startOfHour(dateTime);
case 'DAY':
return startOfDay(dateTime);
case 'WEEK': {
@@ -3,7 +3,7 @@ import { isNonEmptyArray } from '@sniptt/guards';
import z from 'zod';
const REGEX_FOR_RELATIVE_DATE_FILTER_STRINGIFIED_PARSING =
/((?:THIS)|(?:PAST)|(?:NEXT))_(\d*)_(DAY|MONTH|YEAR|WEEK)(?:(?:;;([^;;]*);;)?(?:(MONDAY|SUNDAY|SATURDAY);;)?)?/;
/((?:THIS)|(?:PAST)|(?:NEXT))_(\d*)_(DAY|MONTH|YEAR|WEEK|HOUR|MINUTE|SECOND)(?:(?:;;([^;;]*);;)?(?:(MONDAY|SUNDAY|SATURDAY);;)?)?/;
export const relativeDateFilterStringifiedSchema = z
.string()
@@ -1,6 +1,9 @@
import z from 'zod';
export const relativeDateFilterUnitSchema = z.enum([
'SECOND',
'MINUTE',
'HOUR',
'DAY',
'WEEK',
'MONTH',
@@ -1,5 +1,13 @@
import { type RelativeDateFilterUnit } from '@/utils/filter/dates/utils/relativeDateFilterUnitSchema';
import { subDays, subMonths, subWeeks, subYears } from 'date-fns';
import {
subDays,
subHours,
subMinutes,
subMonths,
subSeconds,
subWeeks,
subYears,
} from 'date-fns';
export const subUnitFromDateTime = (
dateTime: Date,
@@ -7,6 +15,12 @@ export const subUnitFromDateTime = (
unit: RelativeDateFilterUnit,
) => {
switch (unit) {
case 'SECOND':
return subSeconds(dateTime, amount);
case 'MINUTE':
return subMinutes(dateTime, amount);
case 'HOUR':
return subHours(dateTime, amount);
case 'DAY':
return subDays(dateTime, amount);
case 'WEEK':