133 lines
5.0 KiB
TypeScript
133 lines
5.0 KiB
TypeScript
/** 中国星期名称 */
|
||
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`,
|
||
};
|
||
}
|