cal.pub0.org/packages/lib/parse-dates.ts

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())];
};