Files
BYW-VoiceHub/VoiceHub-main/app/utils/timeUtils.ts
T
Henry_Du 4ce4649aaf
Build VoiceHub FPK / build-fpk (push) Failing after 56m5s
Build and Push Docker Image / build-and-push (push) Canceled after 1h9m35s
初次提交
2026-09-06 08:19:02 +08:00

158 lines
4.6 KiB
TypeScript

import dayjs from 'dayjs'
import utc from 'dayjs/plugin/utc.js'
import timezone from 'dayjs/plugin/timezone.js'
dayjs.extend(utc)
dayjs.extend(timezone)
const BEIJING_TIMEZONE = 'Asia/Shanghai'
/**
* 时间工具函数
* 使用 dayjs 处理北京时间(UTC+8)相关逻辑
*
* 核心原则:
* 1. 系统内部传递的 Date 对象保持为真实的 UTC 时间 (new Date())。
* 2. 数据库中存储的 Timestamp 字段应为真实 UTC 时间。
* 3. 只有在需要"显示"或"按北京时间逻辑计算(如每日限额)"时,才转换为北京时间处理。
*
* 注意:此前版本可能使用了"偏移后的 Date 对象"(即 UTC 读数等于北京时间的 Date),
* 本次重构将其纠正为标准模式,以避免混淆和潜在的 Bug。
*/
/**
* 获取当前时间 (真实 UTC)
* 用于替代 new Date(),方便统一管理
*/
export function getBeijingTime(): Date {
return new Date()
}
/**
* 转换时间 (保留函数签名以兼容旧代码)
* 直接返回输入的时间,不再进行偏移处理
*/
export function toBeijingTime(date: Date): Date {
return date
}
/**
* 创建北京时间对应的 UTC Date
* 例如:传入 2023, 0, 1, 0, 0, 0 (北京时间 2023-01-01 00:00:00)
* 返回:UTC 2022-12-31 16:00:00
*/
export function createBeijingTime(
year: number,
month: number, // 0-11
day: number,
hour: number = 0,
minute: number = 0,
second: number = 0
): Date {
return dayjs()
.tz(BEIJING_TIMEZONE)
.set('year', year)
.set('month', month)
.set('date', day)
.set('hour', hour)
.set('minute', minute)
.set('second', second)
.set('millisecond', 0)
.toDate()
}
/**
* 格式化时间为北京时间字符串
* @param date 真实 UTC 时间
* @param format 格式字符串
*/
export function formatDateTime(date: Date, format: string = 'YYYY/M/D H:mm:ss'): string {
return dayjs(date).tz(BEIJING_TIMEZONE).format(format)
}
/**
* 获取时间戳 (真实 UTC)
*/
export function getBeijingTimestamp(): Date {
return new Date()
}
/**
* 解析北京时间字符串为真实 UTC Date
*/
export function parseToBeijingTime(dateString: string): Date {
return dayjs.tz(dateString, BEIJING_TIMEZONE).toDate()
}
/**
* 获取当前北京时间的 ISO 字符串 (YYYY-MM-DDTHH:mm:ss)
* 用于与数据库中存储的字符串比较 (requestTimes 表)
*/
export function getBeijingTimeISOString(): string {
return dayjs().tz(BEIJING_TIMEZONE).format('YYYY-MM-DDTHH:mm:ss')
}
/**
* 获取北京时间的小时 (0-23)
*/
export function getBeijingHour(date: Date): number {
return dayjs(date).tz(BEIJING_TIMEZONE).hour()
}
/**
* 获取“北京时间某天开始”对应的真实 UTC 时间
* 例如:北京时间 2023-01-02 00:00:00 -> 返回 UTC 2023-01-01 16:00:00
* @param date 参考日期 (真实 UTC),默认为当前时间
*/
export function getBeijingStartOfDay(date?: Date): Date {
const target = date ? dayjs(date).tz(BEIJING_TIMEZONE) : dayjs().tz(BEIJING_TIMEZONE)
return target.startOf('day').toDate()
}
/**
* 获取“北京时间某天结束”对应的真实 UTC 时间
*/
export function getBeijingEndOfDay(date?: Date): Date {
const target = date ? dayjs(date).tz(BEIJING_TIMEZONE) : dayjs().tz(BEIJING_TIMEZONE)
return target.endOf('day').toDate()
}
/**
* 获取“北京时间本周开始”对应的真实 UTC 时间
* (周一 00:00:00)
*/
export function getBeijingStartOfWeek(date?: Date): Date {
const target = date ? dayjs(date).tz(BEIJING_TIMEZONE) : dayjs().tz(BEIJING_TIMEZONE)
// 处理周一开始 (dayjs 默认周日为 0)
const day = target.day()
const diff = day === 0 ? 6 : day - 1
return target.subtract(diff, 'day').startOf('day').toDate()
}
/**
* 获取“北京时间本周结束”对应的真实 UTC 时间
* (周日 23:59:59)
*/
export function getBeijingEndOfWeek(date?: Date): Date {
// 获取本周开始,然后加 6 天并取结束
// 注意:这里需要再次转回 dayjs 对象处理
const startOfWeek = dayjs(getBeijingStartOfWeek(date)).tz(BEIJING_TIMEZONE)
return startOfWeek.add(6, 'day').endOf('day').toDate()
}
/**
* 获取“北京时间本月开始”对应的真实 UTC 时间
*/
export function getBeijingStartOfMonth(date?: Date): Date {
const target = date ? dayjs(date).tz(BEIJING_TIMEZONE) : dayjs().tz(BEIJING_TIMEZONE)
return target.startOf('month').toDate()
}
/**
* 获取“北京时间本月结束”对应的真实 UTC 时间
*/
export function getBeijingEndOfMonth(date?: Date): Date {
const target = date ? dayjs(date).tz(BEIJING_TIMEZONE) : dayjs().tz(BEIJING_TIMEZONE)
return target.endOf('month').toDate()
}