Files
2026-03-18 02:01:48 -05:00

133 lines
5.0 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** 中国星期名称 */
const WEEKDAY_CN = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"] as const;
/** 中国时区 */
const TZ = "Asia/Shanghai";
/**
* 获取中国时区下的日期数字(月、日、星期)
* 无论服务器/客户端在何地,均返回中国公历
*/
function getChinaDateParts(): { year: number; month: number; day: number; weekday: number } {
const now = new Date();
const formatter = new Intl.DateTimeFormat("en-CA", {
timeZone: TZ,
year: "numeric",
month: "numeric",
day: "numeric",
weekday: "short",
});
const parts = formatter.formatToParts(now);
const get = (type: string) => parseInt(parts.find((p) => p.type === type)?.value ?? "0", 10);
const weekdayStr = parts.find((p) => p.type === "weekday")?.value ?? "Sun";
const weekdayMap: Record<string, number> = { Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 };
return {
year: get("year"),
month: get("month"),
day: get("day"),
weekday: weekdayMap[weekdayStr] ?? 0,
};
}
/**
* 获取当前中国公历时间字符串,用于上传
* 格式YYYY-MM-DD HH:mm:ss中国时区
*/
export function getNowChinaStr(): string {
const formatter = new Intl.DateTimeFormat("en-CA", {
timeZone: TZ,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hour12: false,
});
const parts = formatter.formatToParts(new Date());
const pad = (s: string) => s.padStart(2, "0");
const get = (type: string) => parts.find((p) => p.type === type)?.value ?? "0";
return `${get("year")}-${pad(get("month"))}-${pad(get("day"))} ${pad(get("hour"))}:${pad(get("minute"))}:${pad(get("second"))}`;
}
/**
* 格式化为中文日期M月D日 周X
*/
function formatDateCN(month: number, day: number, weekday: number): string {
return `${month}${day}${WEEKDAY_CN[weekday]}`;
}
/**
* 获取下一个周六、周日的日期(中国公历)
* 使用 +08:00 显式构造,避免服务器/客户端时区影响
*/
export function getNextWeekendDates(): { saturday: string; sunday: string } {
const { year, month, day, weekday } = getChinaDateParts();
const pad = (n: number) => String(n).padStart(2, "0");
const todayStr = `${year}-${pad(month)}-${pad(day)}T12:00:00+08:00`;
const today = new Date(todayStr);
const daysToSat = weekday === 0 ? 6 : weekday === 6 ? 0 : 6 - weekday;
const saturday = new Date(today);
saturday.setUTCDate(saturday.getUTCDate() + daysToSat);
const sunday = new Date(saturday);
sunday.setUTCDate(sunday.getUTCDate() + 1);
return {
saturday: formatDateCN(saturday.getUTCMonth() + 1, saturday.getUTCDate(), 6),
sunday: formatDateCN(sunday.getUTCMonth() + 1, sunday.getUTCDate(), 0),
};
}
/**
* 获取中国公历本周一 00:00 至周日 23:59:59 的 UTC 时间范围
* 用于 PocketBase created 过滤。PocketBase 要求 Y-m-d H:i:s.uZ 格式(空格非 T
*/
export function getThisWeekRangeISO(): { start: string; end: string } {
const { year, month, day, weekday } = getChinaDateParts();
const pad = (n: number) => String(n).padStart(2, "0");
const todayStr = `${year}-${pad(month)}-${pad(day)}T12:00:00+08:00`;
const today = new Date(todayStr);
const daysToMonday = weekday === 0 ? 6 : weekday - 1;
const monday = new Date(today);
monday.setUTCDate(monday.getUTCDate() - daysToMonday);
const sunday = new Date(monday);
sunday.setUTCDate(sunday.getUTCDate() + 6);
const mondayStr = `${monday.getUTCFullYear()}-${pad(monday.getUTCMonth() + 1)}-${pad(monday.getUTCDate())}T00:00:00+08:00`;
const sundayStr = `${sunday.getUTCFullYear()}-${pad(sunday.getUTCMonth() + 1)}-${pad(sunday.getUTCDate())}T23:59:59.999+08:00`;
const startDate = new Date(mondayStr);
const endDate = new Date(sundayStr);
const fmt = (d: Date, ms: string) => {
const y = d.getUTCFullYear();
const m = pad(d.getUTCMonth() + 1);
const day = pad(d.getUTCDate());
const h = pad(d.getUTCHours());
const min = pad(d.getUTCMinutes());
const s = pad(d.getUTCSeconds());
return `${y}-${m}-${day} ${h}:${min}:${s}.${ms}Z`;
};
return {
start: fmt(startDate, "000"),
end: fmt(endDate, "999"),
};
}
/**
* 获取中国公历本周一、周日的日期字符串YYYY-MM-DD用于 submitted_at_cn 过滤
*/
export function getThisWeekRangeChinaStr(): { start: string; end: string } {
const { year, month, day, weekday } = getChinaDateParts();
const pad = (n: number) => String(n).padStart(2, "0");
const todayStr = `${year}-${pad(month)}-${pad(day)}T12:00:00+08:00`;
const today = new Date(todayStr);
const daysToMonday = weekday === 0 ? 6 : weekday - 1;
const monday = new Date(today);
monday.setUTCDate(monday.getUTCDate() - daysToMonday);
const sunday = new Date(monday);
sunday.setUTCDate(sunday.getUTCDate() + 6);
return {
start: `${monday.getUTCFullYear()}-${pad(monday.getUTCMonth() + 1)}-${pad(monday.getUTCDate())} 00:00:00`,
end: `${sunday.getUTCFullYear()}-${pad(sunday.getUTCMonth() + 1)}-${pad(sunday.getUTCDate())} 23:59:59`,
};
}