first commit
This commit is contained in:
51
backend/src/services/recurrence.ts
Normal file
51
backend/src/services/recurrence.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import type { RecurrenceRule } from "@prisma/client";
|
||||
|
||||
const clampDay = (year: number, monthIndex: number, day: number) => {
|
||||
const lastDay = new Date(Date.UTC(year, monthIndex + 1, 0)).getUTCDate();
|
||||
return Math.min(day, lastDay);
|
||||
};
|
||||
|
||||
export const addMonthsWithClamp = (date: Date, months: number) => {
|
||||
const year = date.getUTCFullYear();
|
||||
const month = date.getUTCMonth();
|
||||
const day = date.getUTCDate();
|
||||
const hour = date.getUTCHours();
|
||||
const minute = date.getUTCMinutes();
|
||||
const second = date.getUTCSeconds();
|
||||
|
||||
const targetMonth = month + months;
|
||||
const targetYear = year + Math.floor(targetMonth / 12);
|
||||
const normalizedMonth = ((targetMonth % 12) + 12) % 12;
|
||||
const clampedDay = clampDay(targetYear, normalizedMonth, day);
|
||||
|
||||
return new Date(Date.UTC(targetYear, normalizedMonth, clampedDay, hour, minute, second));
|
||||
};
|
||||
|
||||
export const addYearsWithClamp = (date: Date, years: number) => {
|
||||
const targetYear = date.getUTCFullYear() + years;
|
||||
const month = date.getUTCMonth();
|
||||
const day = date.getUTCDate();
|
||||
const hour = date.getUTCHours();
|
||||
const minute = date.getUTCMinutes();
|
||||
const second = date.getUTCSeconds();
|
||||
const clampedDay = clampDay(targetYear, month, day);
|
||||
return new Date(Date.UTC(targetYear, month, clampedDay, hour, minute, second));
|
||||
};
|
||||
|
||||
export const nextDueAt = (dueAt: Date, rule: RecurrenceRule) => {
|
||||
const interval = rule.interval ?? 1;
|
||||
switch (rule.type) {
|
||||
case "hourly":
|
||||
return new Date(dueAt.getTime() + interval * 60 * 60 * 1000);
|
||||
case "daily":
|
||||
return new Date(dueAt.getTime() + interval * 24 * 60 * 60 * 1000);
|
||||
case "weekly":
|
||||
return new Date(dueAt.getTime() + interval * 7 * 24 * 60 * 60 * 1000);
|
||||
case "monthly":
|
||||
return addMonthsWithClamp(dueAt, interval);
|
||||
case "yearly":
|
||||
return addYearsWithClamp(dueAt, interval);
|
||||
default:
|
||||
return dueAt;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user