Files
timi-web/src/utils/Time.ts
T
2026-07-31 15:28:13 +08:00

212 lines
5.6 KiB
TypeScript

import Toolkit from "./Toolkit";
import Text from "./Text";
export default class Time {
/** 1 秒时间戳 */
public static S = 1E3;
/** 1 分钟时间戳 */
public static M = Time.S * 60;
/** 1 小时时间戳 */
public static H = Time.M * 60;
/** 1 天时间戳 */
public static D = Time.H * 24;
public static now(): number {
return new Date().getTime();
}
public static toTimestamp(date: Date): number {
return date.getTime();
}
public static toDateObject(unix?: number): Date | undefined {
if (!unix) {
return undefined;
}
return new Date(unix);
}
public static formatDate(date: Date): string {
return `${date.getFullYear()}-${Text.pad(date.getMonth() + 1)}-${Text.pad(date.getDate())}`;
}
public static formatDateTime(date: Date): string {
return `${this.formatDate(date)} ${Text.pad(date.getHours())}:${Text.pad(date.getMinutes())}`;
}
/**
* Unix 时间戳转日期
*
* @param unix 时间戳
*/
public static toDate(unix?: number): string {
if (!unix) return "";
return this.formatDate(new Date(unix));
}
/**
* Unix 时间戳转时间
*
* @param unix 时间戳
*/
public static toTime(unix?: number): string {
if (!unix) return "";
const d = new Date(unix);
return `${Text.pad(d.getHours())}:${Text.pad(d.getMinutes())}`;
}
public static toShortTime(unix?: number): string {
if (!unix) return "";
const d = new Date(unix);
return `${Text.pad(d.getMinutes())}:${Text.pad(d.getSeconds())}`;
}
/**
* Unix 时间戳转日期和时间
*
* @param unix 时间戳
*/
public static toDateTime(unix?: number): string {
if (!unix) return "";
return `${this.toDate(unix)} ${this.toTime(unix)}`;
}
public static toPassedDate(unix?: number): string {
return this.toPassedDateTime(unix, false);
}
public static toPassedDateTime(unix?: number, withDetailTime = true): string {
if (!unix) {
return "";
}
const now = new Date().getTime();
const between = now - unix;
if (Time.D * 4 <= between) {
return withDetailTime ? this.toDateTime(unix) : this.toDate(unix);
} else if (Time.D < between) {
return `${Math.floor(between / Time.D)} 天前`;
} else if (Time.H < between) {
return `${Math.floor(between / Time.H)} 小时前`;
} else if (Time.M < between) {
return `${Math.floor(between / Time.M)} 分钟前`;
} else {
return "刚刚";
}
}
public static between(begin: Date, end?: Date) : any {
if (!end) {
end = new Date();
}
const cs = 1000, cm = 6E4, ch = 36E5, cd = 864E5, cy = 31536E6;
const l = end.getTime() - begin.getTime();
const y = Math.floor(l / cy),
d = Math.floor((l / cd) - y * 365),
h = Math.floor((l - (y * 365 + d) * cd) / ch),
m = Math.floor((l - (y * 365 + d) * cd - h * ch) / cm),
s = Math.floor((l - (y * 365 + d) * cd - h * ch - m * cm) / cs),
ms = Math.floor(((l - (y * 365 + d) * cd - h * ch - m * cm) / cs - s) * cs);
return { l, y, d, h, m, s, ms };
}
public static duration(totalMs?: number | null | undefined, ms?: boolean): string {
if (totalMs === null || totalMs === undefined) {
return "";
}
let remain = Math.floor(totalMs);
const yearMs = Time.D * 365;
const dayMs = Time.D;
const hourMs = Time.H;
const minuteMs = Time.M;
const secondMs = Time.S;
const years = Math.floor(remain / yearMs);
remain %= yearMs;
const days = Math.floor(remain / dayMs);
remain %= dayMs;
const hours = Math.floor(remain / hourMs);
remain %= hourMs;
const minutes = Math.floor(remain / minuteMs);
remain %= minuteMs;
const seconds = Math.floor(remain / secondMs);
remain %= secondMs;
const milliseconds = remain;
const parts: string[] = [];
Toolkit.doWhere(0 < years, () => parts.push(`${years} 年`));
Toolkit.doWhere(0 < days, () => parts.push(`${days} 天`));
Toolkit.doWhere(0 < hours, () => parts.push(`${hours} 小时`));
Toolkit.doWhere(0 < minutes, () => parts.push(`${minutes} 分钟`));
Toolkit.doWhere(0 < seconds, () => parts.push(`${seconds} 秒`));
Toolkit.doWhere(!!ms && 0 < milliseconds, () => parts.push(`${milliseconds} 毫秒`));
return parts.join(" ");
}
public static toMediaTime(seconds: number): string {
seconds = Math.floor(seconds);
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const second = seconds % 60;
if (0 < hours) {
return `${hours}:${Text.pad(minutes)}:${Text.pad(second)}`;
}
return `${Text.pad(minutes)}:${Text.pad(second)}`;
}
/**
* 将时间字符串解析为毫秒值
*
* <p>支持的格式示例:
* <pre>
* 10 = 10
* 10ms = 10
* 10s = 10,000
* 10m = 600,000
* 10h = 36,000,000
* 10d = 10D = 10 d = 864,000,000
* 10.5d = 907,200,000
* </pre>
*
* @param timeStr 时间字符串
* @return 毫秒
* @throws Error 输入格式无效
*/
public static parseToMS(timeStr: string): number {
if (!timeStr || timeStr.trim() === "") {
throw new Error("not found timeStr");
}
const normalized = timeStr.replace(/\s+/g, "").toLowerCase();
const pattern = /^(\d+(?:\.\d+)?)(ms|[dhms])?$/;
const matcher = pattern.exec(normalized);
if (!matcher) {
throw new Error("invalid format: " + timeStr);
}
const value = parseFloat(matcher[1]);
const unit = matcher[2];
if (!unit || unit === "ms") {
return Math.round(value);
}
let multiplier: number;
switch (unit) {
case "s":
multiplier = Time.S;
break;
case "m":
multiplier = Time.M;
break;
case "h":
multiplier = Time.H;
break;
case "d":
multiplier = Time.D;
break;
default:
throw new Error("invalid format unit: " + unit);
}
return Math.round(value * multiplier);
}
}