212 lines
5.6 KiB
TypeScript
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);
|
|
}
|
|
}
|