fix(server): 时间戳→业务日期/时间全部统一为中国时区(UTC+8)
此前仅'今天'默认值统一为中国日期,Date→字符串的转换仍是 UTC: - sync 考勤同步窗口 lastSyncAt 时间戳按 UTC 取日期,凌晨会偏一天 - 考勤导出 punchTime/createdAt 显示 UTC 时间 - normalizeDateOnly 把 ISO datetime 按 UTC 归一化,业务日期少一天 - getCourseClock/getChinaDateParts 用 dayjs.utc(date).add(8h) 隐式转换 统一为 dayjs(date).utcOffset(8),纯日期字符串运算(shiftDate/addDays/ daysInMonth/nextMonth)保留 dayjs.utc;date-normalization 测试断言 同步更新为北京时间语义。
This commit is contained in:
@@ -76,7 +76,7 @@ export class AttendanceCalendarService {
|
||||
const start = new Date(weekStart);
|
||||
const end = new Date(start);
|
||||
end.setDate(start.getDate() + 6);
|
||||
const endStr = dayjs(end).utc().format('YYYY-MM-DD');
|
||||
const endStr = dayjs(end).utcOffset(8).format('YYYY-MM-DD');
|
||||
|
||||
const records = await this.attendanceRepo.find({
|
||||
where: {
|
||||
|
||||
@@ -97,7 +97,7 @@ export class AttendanceGenerationService {
|
||||
const entities: AttendanceRecord[] = [];
|
||||
const end = new Date(dateTo);
|
||||
for (let d = new Date(dateFrom); d <= end; d.setDate(d.getDate() + 1)) {
|
||||
const dateStr = dayjs(d).utc().format('YYYY-MM-DD');
|
||||
const dateStr = dayjs(d).utcOffset(8).format('YYYY-MM-DD');
|
||||
const weekDay = d.getDay() === 0 ? 7 : d.getDay();
|
||||
|
||||
for (const sched of schedules) {
|
||||
@@ -158,7 +158,7 @@ export class AttendanceGenerationService {
|
||||
}
|
||||
|
||||
private getCourseClock(date: Date): { date: string; minutes: number } {
|
||||
const c = dayjs.utc(date).add(8, 'hour');
|
||||
const c = dayjs(date).utcOffset(8);
|
||||
return {
|
||||
date: c.format('YYYY-MM-DD'),
|
||||
minutes: c.hour() * 60 + c.minute(),
|
||||
|
||||
@@ -239,7 +239,7 @@ export class AttendanceImportService {
|
||||
}
|
||||
|
||||
private formatDate(value: Date): string {
|
||||
return dayjs.utc(value).format('YYYY-MM-DD');
|
||||
return dayjs(value).utcOffset(8).format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -153,7 +153,7 @@ export class AttendanceLeaveSyncService {
|
||||
}
|
||||
|
||||
private formatDate(value: Date): string {
|
||||
return dayjs.utc(value).format('YYYY-MM-DD');
|
||||
return dayjs(value).utcOffset(8).format('YYYY-MM-DD');
|
||||
}
|
||||
|
||||
private async resolveStudentName(dingUserId: string): Promise<string> {
|
||||
|
||||
@@ -196,11 +196,11 @@ export class AttendanceRecordsController extends AttendanceControllerBase {
|
||||
source: record.source || '',
|
||||
punchDevice: record.punchDeviceName || record.punchDeviceId || '',
|
||||
punchTime: record.punchTime
|
||||
? dayjs(record.punchTime).utc().format('YYYY-MM-DD HH:mm:ss')
|
||||
? dayjs(record.punchTime).utcOffset(8).format('YYYY-MM-DD HH:mm:ss')
|
||||
: '',
|
||||
remark: record.remark || '',
|
||||
createdAt: record.createdAt
|
||||
? dayjs(record.createdAt).utc().format('YYYY-MM-DD HH:mm:ss')
|
||||
? dayjs(record.createdAt).utcOffset(8).format('YYYY-MM-DD HH:mm:ss')
|
||||
: '',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ export class AttendanceReportService {
|
||||
async getAlerts(days: number = 14, threshold: number = 3, accessibleClassIds?: number[]) {
|
||||
const cutoff = new Date();
|
||||
cutoff.setDate(cutoff.getDate() - days);
|
||||
const cutoffStr = dayjs(cutoff).utc().format('YYYY-MM-DD');
|
||||
const cutoffStr = dayjs(cutoff).utcOffset(8).format('YYYY-MM-DD');
|
||||
|
||||
const qb = this.attendanceRepo
|
||||
.createQueryBuilder('a')
|
||||
|
||||
@@ -285,7 +285,7 @@ export class AttendanceSettlementService {
|
||||
|
||||
private getCourseClock(date: Date): { date: string; weekDay: number; minutes: number } {
|
||||
// Asia/Shanghai 无夏令时,固定 UTC+8 与 Intl 时区格式化等价
|
||||
const c = dayjs.utc(date).add(8, 'hour');
|
||||
const c = dayjs(date).utcOffset(8);
|
||||
const weekDay = c.day() === 0 ? 7 : c.day();
|
||||
return {
|
||||
date: c.format('YYYY-MM-DD'),
|
||||
|
||||
Reference in New Issue
Block a user