106 lines
3.2 KiB
TypeScript
106 lines
3.2 KiB
TypeScript
import { RRule } from "rrule";
|
|
|
|
import type { Dayjs } from "@calcom/dayjs";
|
|
import dayjs from "@calcom/dayjs";
|
|
import { detectBrowserTimeFormat, TimeFormat } from "@calcom/lib/timeFormat";
|
|
import type { RecurringEvent } from "@calcom/types/Calendar";
|
|
|
|
import { parseZone } from "./parse-zone";
|
|
|
|
type ExtraOptions = { withDefaultTimeFormat?: boolean; selectedTimeFormat?: TimeFormat };
|
|
|
|
const processDate = (date: string | null | Dayjs, language: string, options?: ExtraOptions) => {
|
|
const parsedZone = parseZone(date);
|
|
if (!parsedZone?.isValid()) return "Invalid date";
|
|
const formattedTime = parsedZone?.format(
|
|
options?.withDefaultTimeFormat
|
|
? TimeFormat.TWELVE_HOUR
|
|
: options?.selectedTimeFormat || detectBrowserTimeFormat
|
|
);
|
|
return formattedTime + ", " + dayjs(date).toDate().toLocaleString(language, { dateStyle: "full" });
|
|
};
|
|
|
|
export const parseDate = (date: string | null | Dayjs, language: string, options?: ExtraOptions) => {
|
|
if (!date) return ["No date"];
|
|
return processDate(date, language, options);
|
|
};
|
|
|
|
const timeOptions: Intl.DateTimeFormatOptions = {
|
|
hour12: true,
|
|
hourCycle: "h12",
|
|
hour: "numeric",
|
|
minute: "numeric",
|
|
};
|
|
|
|
const dateOptions: Intl.DateTimeFormatOptions = {
|
|
weekday: "long",
|
|
year: "numeric",
|
|
month: "long",
|
|
day: "numeric",
|
|
};
|
|
|
|
export const parseDateTimeWithTimeZone = (
|
|
date: Date,
|
|
language: string,
|
|
timezone: string,
|
|
options?: ExtraOptions
|
|
): string => {
|
|
timeOptions.timeZone = timezone;
|
|
dateOptions.timeZone = timezone;
|
|
|
|
if (options?.withDefaultTimeFormat) {
|
|
timeOptions.hourCycle = "h12";
|
|
} else if (options?.selectedTimeFormat) {
|
|
timeOptions.hourCycle = options.selectedTimeFormat === TimeFormat.TWELVE_HOUR ? "h12" : "h24";
|
|
if (timeOptions.hourCycle === "h24") {
|
|
delete timeOptions.hour12;
|
|
}
|
|
}
|
|
const formattedDate = new Date(date).toLocaleDateString(language, dateOptions);
|
|
const formattedTime = new Date(date)
|
|
.toLocaleTimeString(language, timeOptions)
|
|
.replace(" ", "")
|
|
.toLowerCase();
|
|
return `${formattedTime}, ${formattedDate}`;
|
|
};
|
|
|
|
export const parseRecurringDates = (
|
|
{
|
|
startDate,
|
|
timeZone,
|
|
recurringEvent,
|
|
recurringCount,
|
|
selectedTimeFormat,
|
|
withDefaultTimeFormat,
|
|
}: {
|
|
startDate: string | null | Dayjs;
|
|
timeZone?: string;
|
|
recurringEvent: RecurringEvent | null;
|
|
recurringCount: number;
|
|
selectedTimeFormat?: TimeFormat;
|
|
withDefaultTimeFormat?: boolean;
|
|
},
|
|
language: string
|
|
): [string[], Date[]] => {
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
const { count, ...restRecurringEvent } = recurringEvent || {};
|
|
const rule = new RRule({
|
|
...restRecurringEvent,
|
|
count: recurringCount,
|
|
dtstart: new Date(dayjs(startDate).valueOf()),
|
|
});
|
|
|
|
const startUtcOffset = dayjs(startDate).utcOffset();
|
|
// UTC still need to have DST applied, rrule does not do this.
|
|
const times = rule.all().map((t) => {
|
|
// applying the DST offset.
|
|
return dayjs.utc(t).add(startUtcOffset - dayjs(t).utcOffset(), "minute");
|
|
});
|
|
const dateStrings = times.map((t) => {
|
|
// finally; show in local timeZone again
|
|
return processDate(t.tz(timeZone), language, { selectedTimeFormat, withDefaultTimeFormat });
|
|
});
|
|
|
|
return [dateStrings, times.map((t) => t.toDate())];
|
|
};
|