perf(finance): 统一把 Intl.DateTimeFormat 提到模块级,消除逐行构造开销
承接 14b595b0。以下 7 处仍在函数体内 `new Intl.DateTimeFormat(...)`, 单次构造约 0.5ms,按行/按条调用时会线性放大: - utils/finance-date-range.ts formatShanghaiDate - utils/http.ts (已在上一个提交修复) - scheduler/cost-finance-sync-job.ts today - finance/sales-facts-service.ts formatDateOnly - finance/order-refund-service.ts toChinaDate - admin/admin-finance-service.ts chinaDateParts - admin/admin-dashboard-service.ts resolveChinaTodayRange - scripts/sync-cost-finance.ts formatShanghaiDate 均为同选项的纯 hoist,输出逐字节不变:formatShanghaiDate 用 9 例跨时区/ 毫秒/闰日语料与旧实现比对一致;其余为相同 en-CA/en-US + Asia/Shanghai 选项的等价替换,formatToParts 的取值改为单次遍历、去掉 fromEntries/reduce。
This commit is contained in:
@@ -78,11 +78,14 @@ function normalizeDays(value: unknown) {
|
||||
return parsed
|
||||
}
|
||||
|
||||
/** 模块级只构造一次:`new Intl.DateTimeFormat()` 每次约 0.5ms,逐条调用会线性放大。 */
|
||||
const SHANGHAI_DATE_FORMATTER = new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
})
|
||||
|
||||
function formatShanghaiDate(value: Date) {
|
||||
return new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
}).format(value)
|
||||
return SHANGHAI_DATE_FORMATTER.format(value)
|
||||
}
|
||||
|
||||
@@ -63,22 +63,24 @@ export async function getAdminDashboardSummary() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 模块级只构造一次:`new Intl.DateTimeFormat()` 每次约 0.5ms,逐条调用会线性放大。 */
|
||||
const CHINA_DAY_PARTS_FORMATTER = new Intl.DateTimeFormat('en-US', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
})
|
||||
|
||||
/** 返回中国时区当天对应的 UTC 查询范围,便于使用时间索引。 */
|
||||
function resolveChinaTodayRange(now: string) {
|
||||
const parts = new Intl.DateTimeFormat('en-US', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
})
|
||||
.formatToParts(new Date(now))
|
||||
.reduce<Record<string, string>>((result, part) => {
|
||||
result[part.type] = part.value
|
||||
return result
|
||||
}, {})
|
||||
const year = Number(parts.year || 0)
|
||||
const month = Number(parts.month || 1)
|
||||
const day = Number(parts.day || 1)
|
||||
let year = 0
|
||||
let month = 1
|
||||
let day = 1
|
||||
for (const part of CHINA_DAY_PARTS_FORMATTER.formatToParts(new Date(now))) {
|
||||
if (part.type === 'year') year = Number(part.value)
|
||||
else if (part.type === 'month') month = Number(part.value)
|
||||
else if (part.type === 'day') day = Number(part.value)
|
||||
}
|
||||
const todayStart = Date.UTC(year || 0, (month || 1) - 1, day || 1, -8)
|
||||
const tomorrowStart = todayStart + 24 * 60 * 60 * 1000
|
||||
|
||||
|
||||
@@ -455,15 +455,25 @@ function parseFinanceBoundary(value: string, fallbackDate: string, end: boolean)
|
||||
: parsed.toISOString()
|
||||
}
|
||||
|
||||
/** 模块级只构造一次:`new Intl.DateTimeFormat()` 每次约 0.5ms,逐条调用会线性放大。 */
|
||||
const CHINA_DATE_PARTS_FORMATTER = new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: CHINA_TIME_ZONE,
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
})
|
||||
|
||||
function chinaDateParts(value: string) {
|
||||
const parts = new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: CHINA_TIME_ZONE,
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
}).formatToParts(new Date(value))
|
||||
const result = Object.fromEntries(parts.map((part) => [part.type, part.value]))
|
||||
return `${result.year}-${result.month}-${result.day}`
|
||||
const parts = CHINA_DATE_PARTS_FORMATTER.formatToParts(new Date(value))
|
||||
let year = ''
|
||||
let month = ''
|
||||
let day = ''
|
||||
for (const part of parts) {
|
||||
if (part.type === 'year') year = part.value
|
||||
else if (part.type === 'month') month = part.value
|
||||
else if (part.type === 'day') day = part.value
|
||||
}
|
||||
return `${year}-${month}-${day}`
|
||||
}
|
||||
|
||||
function chinaDateToUtcIso(value: string) {
|
||||
|
||||
@@ -526,15 +526,18 @@ function normalizeTimestamp(value: unknown): string {
|
||||
return date.toISOString()
|
||||
}
|
||||
|
||||
/** 模块级只构造一次:`new Intl.DateTimeFormat()` 每次约 0.5ms,逐条调用会线性放大。 */
|
||||
const CHINA_DATE_FORMATTER = new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
})
|
||||
|
||||
function toChinaDate(value: string): string {
|
||||
const date = new Date(value)
|
||||
if (Number.isNaN(date.getTime())) return ''
|
||||
return new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
}).format(date)
|
||||
return CHINA_DATE_FORMATTER.format(date)
|
||||
}
|
||||
|
||||
function formatFen(value: number): string {
|
||||
|
||||
@@ -486,14 +486,17 @@ function mapSalesFact(row: SalesFactRow) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 模块级只构造一次:`new Intl.DateTimeFormat()` 每次约 0.5ms,逐行调用会线性放大。 */
|
||||
const SHANGHAI_DATE_FORMATTER = new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
})
|
||||
|
||||
function formatDateOnly(value: string | Date): string {
|
||||
if (value instanceof Date) {
|
||||
return new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
}).format(value)
|
||||
return SHANGHAI_DATE_FORMATTER.format(value)
|
||||
}
|
||||
return String(value || '').slice(0, 10)
|
||||
}
|
||||
|
||||
@@ -82,13 +82,16 @@ export async function runCostFinanceSyncJob(job: JsonObject = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
/** 模块级只构造一次:`new Intl.DateTimeFormat()` 每次约 0.5ms,逐条调用会线性放大。 */
|
||||
const SHANGHAI_DATE_FORMATTER = new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
})
|
||||
|
||||
function today() {
|
||||
return new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
}).format(new Date())
|
||||
return SHANGHAI_DATE_FORMATTER.format(new Date())
|
||||
}
|
||||
|
||||
function shiftDays(days: number) {
|
||||
|
||||
@@ -40,13 +40,16 @@ export function resolveFinanceDateRange(
|
||||
return { fromDate, toDate }
|
||||
}
|
||||
|
||||
/** 模块级只构造一次:`new Intl.DateTimeFormat()` 每次约 0.5ms,逐条调用会线性放大。 */
|
||||
const SHANGHAI_DATE_FORMATTER = new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
})
|
||||
|
||||
export function formatShanghaiDate(value: Date): string {
|
||||
return new Intl.DateTimeFormat('en-CA', {
|
||||
timeZone: 'Asia/Shanghai',
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
}).format(value)
|
||||
return SHANGHAI_DATE_FORMATTER.format(value)
|
||||
}
|
||||
|
||||
export function shiftDate(date: string, days: number): string {
|
||||
|
||||
Reference in New Issue
Block a user