Files
dukang/packages/domain/src/shanghai-date.ts
T
jacy e26206b93c
CI / verify (pull_request) Waiting to run
v4.0.3版本
总部后端,开发计划-任务列表-来源工单支持链接
总部端-开发计划-任务列表-编辑任务-增加“开发中”状态
账单日期修正
2026-08-31 14:22:49 +08:00

77 lines
2.9 KiB
TypeScript

/** 财务账单日 / 账期一律按中国北京时间(Asia/Shanghai,无夏令时) */
export const SHANGHAI_TIME_ZONE = 'Asia/Shanghai';
function pad2(n: number): string {
return String(n).padStart(2, '0');
}
export function shanghaiYmd(d: Date): string {
return d.toLocaleDateString('sv-SE', { timeZone: SHANGHAI_TIME_ZONE });
}
export function parseShanghaiYmd(ymd: string): Date {
return new Date(`${ymd}T00:00:00+08:00`);
}
export function startOfShanghaiDay(d: Date = new Date()): Date {
return parseShanghaiYmd(shanghaiYmd(d));
}
export function addShanghaiDays(d: Date, days: number): Date {
const [y, m, day] = shanghaiYmd(startOfShanghaiDay(d)).split('-').map(Number);
const utc = new Date(Date.UTC(y, m - 1, day + days));
const ymd = `${utc.getUTCFullYear()}-${pad2(utc.getUTCMonth() + 1)}-${pad2(utc.getUTCDate())}`;
return new Date(`${ymd}T00:00:00+08:00`);
}
/** 门店 T+1:核销窗口 [昨日 00:00, 今日 00:00);出账日 = 今天 */
export function shanghaiT1DayWindow(anchor = new Date()) {
const billDate = startOfShanghaiDay(anchor);
const start = addShanghaiDays(billDate, -1);
return { start, end: billDate, billDate };
}
/**
* 酒厂 T+N:出账日 = 今天;纳入窗口为「今天 − lagDays」当天完成的订单
*/
export function shanghaiLaggedIssueWindow(anchor = new Date(), lagDays: number) {
const billDate = startOfShanghaiDay(anchor);
const start = addShanghaiDays(billDate, -lagDays);
const end = addShanghaiDays(start, 1);
return { start, end, billDate };
}
export function shanghaiMonthRange(year: number, month: number): { start: Date; endExclusive: Date } {
const start = new Date(`${year}-${pad2(month)}-01T00:00:00+08:00`);
const endMonth = month === 12 ? 1 : month + 1;
const endYear = month === 12 ? year + 1 : year;
const endExclusive = new Date(`${endYear}-${pad2(endMonth)}-01T00:00:00+08:00`);
return { start, endExclusive };
}
export function shanghaiMonthLastInstant(year: number, month: number): Date {
return new Date(shanghaiMonthRange(year, month).endExclusive.getTime() - 1);
}
export function previousShanghaiMonth(anchor = new Date()): { year: number; month: number } {
const [y, m] = shanghaiYmd(anchor).split('-').map(Number);
if (m === 1) return { year: y - 1, month: 12 };
return { year: y, month: m - 1 };
}
export function shanghaiYearMonth(anchor = new Date()): { year: number; month: number } {
const [y, m] = shanghaiYmd(anchor).split('-').map(Number);
return { year: y, month: m };
}
/** 账期展示:以 periodStart 所在北京月的首末日,避免 UTC 23:59:59 滚到下月 */
export function shanghaiPeriodYmds(periodStart: Date): { periodStart: string; periodEnd: string } {
const [y, m] = shanghaiYmd(periodStart).split('-').map(Number);
const { start, endExclusive } = shanghaiMonthRange(y, m);
return {
periodStart: shanghaiYmd(start),
periodEnd: shanghaiYmd(new Date(endExclusive.getTime() - 1)),
};
}