/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import I18n from '@ohos.i18n';
import Intl from '@ohos.intl';
import { LogUtil } from './LogUtil';
type TimeStampType = string | number | Date;
const TAG: string = 'TimeUtil: ';
/**
* 时间工具类
*/
export class TimeUtil {
/**
* 获取格式化时间字符串
*
* @param timestamp 精确到毫秒的时间戳
* @param format 格式化样式 {@link TimeFormat}
* @param timeZone 时区,如8,-2
* @returns 格式化时间字符串
*/
public static obtainFormatTime(timestamp: TimeStampType,
format: TimeFormat, timeZone?: number): string {
let formatString = '';
let date: Date = new Date(timestamp);
let timeZoneStr = timeZone ? TimeUtil.parseZoneNumberToStr(timeZone) :
TimeUtil.parseZoneNumberToStr(TimeUtil.getTimeZone());
LogUtil.info(`${TAG} obtainFormatTime timeZone: ${timeZone}, timeZoneStr: ${timeZoneStr}`);
switch (format) {
case TimeFormat.MONTH_DAY_NUMERIC:
formatString = TimeUtil.formatTime(date, { month: 'numeric', day: 'numeric', timeZone: timeZoneStr });
break;
case TimeFormat.HOUR_MINUTE:
formatString = TimeUtil.formatTime(date, {
hour: '2-digit',
minute: '2-digit',
timeZone: timeZoneStr,
dayPeriod: 'long',
});
break;
case TimeFormat.HOUR_MINUTE_SHORT:
formatString = TimeUtil.formatTime(date, {
hour: '2-digit',
minute: '2-digit',
timeZone: timeZoneStr
});
break;
case TimeFormat.MOTH_DAY_HOUR_MINUTE_SYSTEM:
formatString = TimeUtil.formatTime(date, { month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' });
break;
case TimeFormat.HALF_BLOCK_HOUR_MINUTE:
formatString = TimeUtil.formatTime(date, { timeStyle: 'short', hour12: true });
break;
default:
LogUtil.warn('missing format implement.');
formatString = '';
break;
}
return formatString;
}
/**
* 格式化时间戳
* @param timestamp 时间戳
* @param options 格式化选项
* @returns
*/
private static dateTimeFormatCache: Map<string, Intl.DateTimeFormat> = new Map();
public static formatTime(timestamp: TimeStampType, options: Intl.DateTimeOptions): string {
if (!timestamp) {
return '';
}
const local = options.locale ?? TimeUtil.getLocalId();
if (options.hour12 === undefined) {
options.hour12 = !TimeUtil.getIs24HourClock();
}
const cacheKey = `${local}-${options?.month}-${options?.day}-${options?.timeZone}-${options?.hour}
-${options?.minute}-${options?.timeStyle}-${options?.hour12}`;
let dateTimeFormat = TimeUtil.dateTimeFormatCache.get(cacheKey);
if (!dateTimeFormat) {
LogUtil.info('call DateTimeFormat');
dateTimeFormat = new Intl.DateTimeFormat(local, options);
TimeUtil.dateTimeFormatCache.set(cacheKey, dateTimeFormat);
}
return dateTimeFormat.format(new Date(timestamp));
}
/**
* 获取系统当前locale
* @returns 系统当前locale。如中文环境返回 zh-CN
*/
public static getLocalId(): string {
let locale = new Intl.Locale();
let localeID = locale.toString();
return localeID;
}
/**
* 判断系统时间是否为24小时制。
* @returns true表示是24小时制
*/
public static getIs24HourClock(): boolean {
let is24HourClock: boolean = true;
try {
is24HourClock = I18n.System.is24HourClock(); // 系统24小时开关是否开启
} catch (error) {
LogUtil.error(`call System.is24HourClock failed, error code: ${error.code}, message: ${error.message}.`);
}
return is24HourClock;
}
/**
* sleep休眠
*
* @param ms
* @returns
*/
public static async sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms))
}
/**
* 获取当前时区偏移量
*
* @return 当前时区偏移量
*/
public static getTimeZone(): number {
// 获取与0时区的时间差(单位:分钟)
let offsetGmt: number = new Date().getTimezoneOffset();
// 当前时区与0时区的偏移量(单位:小时)
return 0 - offsetGmt / TimeEnum.MINUTE_TO_SECONDS;
}
/**
* 转换number格式时区信息为string形式
*
* @param timeZone number时区信息
* @returns string时区信息
*/
public static parseZoneNumberToStr(timeZone: number): string {
let operator: string = timeZone >= 0 ? '+' : '';
return `GMT${operator}${String(timeZone)}:00`;
}
/**
* 判断时间戳是否为当天
* @param timestamp
* @returns
*/
public static isToday(timestamp: number): boolean {
return new Date(timestamp).toDateString() === new Date().toDateString();
}
/**
* 根据HHmm格式的时间字符串,获取Date
*
* @param timeStr HHmm格式的时间字符串
* @returns Date
*/
public static getDateByTimeStr(timeStr: string): Date {
let date: Date = new Date();
if (timeStr.length !== TimeEnum.HHMM_TIME_LENGTH || Number.isNaN(Number(timeStr))) {
LogUtil.info('getDateByTimeStr data is abnormal!');
return date;
}
date.setHours(Number(timeStr.slice(0, TimeEnum.HOURS_STR_LENGTH)));
date.setMinutes(Number(timeStr.slice(TimeEnum.HOURS_STR_LENGTH)));
return date;
}
/**
* 根据yyyyMMdd格式的日期字符串,获取Date
* @param dateStr yyyyMMdd格式的日期字符串
* @returns
*/
public static getDateByDateStr(dateStr: string): Date {
let date: Date = new Date();
if (dateStr.length !== TimeEnum.YYYYMMDD_DATE_LENGTH || Number.isNaN(Number(dateStr))) {
LogUtil.info('getDateByDateStr data is abnormal!');
return date;
}
let year = Number(dateStr.slice(0, TimeEnum.YEAR_STR_LENGTH));
let month = Number(dateStr.slice(TimeEnum.YEAR_STR_LENGTH, TimeEnum.YEAR_MONTH_STR_LENGTH)) - 1;
let day = Number(dateStr.slice(TimeEnum.YEAR_MONTH_STR_LENGTH));
date.setFullYear(year, month, day);
return date;
}
/**
* 根据Date,获取HHmm格式的时间字符串
*
* @param date Date
* @returns HHmm格式的时间字符串
*/
public static getTimeStrByDate(date: Date): string {
let timeStr: string = '';
if (date === undefined) {
LogUtil.warn('getTimeStrByDate data is undefined!');
return timeStr;
}
let hours: number = date.getHours();
let minutes: number = date.getMinutes();
timeStr = hours?.toString().padStart(TimeEnum.HOURS_STR_LENGTH, '0') ?? '00';
timeStr += minutes?.toString().padStart(TimeEnum.MINUTE_STR_LENGTH, '0') ?? '00';
return timeStr;
}
/**
* 时间字符串转换
* HHmm → HH:mm
*
* @param timeStr HHmm 格式的时间字符串
* @returns HH:mm 格式的时间字符串
*/
public static getTimeStr(timeStr: string): string {
let date: Date = TimeUtil.getDateByTimeStr(timeStr);
return TimeUtil.obtainFormatTime(date, TimeFormat.HOUR_MINUTE);
}
public static getDateByTimestamp(timestamp: string): Date {
let time: number = Number.parseInt(timestamp);
return new Date(time)
}
public static getTimeStrbyTimestamp(timestamp: string): string {
let date = new Date(Number.parseInt(timestamp))
return TimeUtil.obtainFormatTime(date, TimeFormat.HOUR_MINUTE);
}
/**
* 分钟数转化为对应的当天的时间点
*
* @param minutes 分钟数
* @returns 日期
*/
public static minutesToDate(minutes: number | undefined): Date {
if (!minutes || minutes <= 0) {
return new Date();
}
const hours = Math.floor(minutes / TimeEnum.HOUR_TO_MINUTES);
const remainderMinutes = minutes % TimeEnum.HOUR_TO_MINUTES;
const timeStr = hours.toString().padStart(2, '0') + remainderMinutes.toString().padStart(2, '0');
return TimeUtil.getDateByTimeStr(timeStr);
}
}
/**
* 日期格式
*/
export enum TimeFormat {
/**
* 年月日 时分秒 YYYY/MM/DD HH:mm:ss
*/
YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = 'YYYY/MM/DD HH:mm:ss',
/**
* 年月日 时分 YYYY/MM/DD HH:mm
*/
YEAR_MONTH_DAY_HOUR_MINUTE = 'YYYY/MM/DD HH:mm',
/**
* 年月日 YYYY/MM/DD
*/
YEAR_MONTH_DAY_NUMERIC = 'YYYY/MM/DD',
/**
* 年月日 月日一位数前不加0 YYYY年M月D日
*/
YEAR_MONTH_DAY_MEDIUM = 'YYYY年M月D日',
/**
* 年月日 年取后两位 YY年M月D日
*/
YEAR_MONTH_DAY_2_DIGIT = 'YY年M月D日',
/**
* 年月 年取后两位 YY年M月
*/
YEAR_MONTH_2_DIGIT = 'YY年M月',
/**
* 年月 YYYY/MM
*/
YEAR_MONTH_NUMERIC = 'YYYY/MM',
/**
* 年月 YYYY年M月
*/
YEAR_MONTH = 'YYYY年M月',
/**
* 年 YYYY年
*/
YEAR = 'YYYY年',
/**
* 月日 一位数前不加0 M/D
*/
MONTH_DAY_NUMERIC = 'M/D',
/**
* 月日 一位数前不加0 M月D日
*/
MONTH_DAY_SHORT = 'M月D日',
/**
* 月 一位数前不加0 M月
*/
MONTH_SHORT = 'M月',
/**
* 时分秒 HH:mm:ss
*/
HOUR_MINUTE_SECOND = 'HH:mm:ss',
/**
* 时分 HH:mm
*/
HOUR_MINUTE = 'HH:mm',
/**
* HH:mm AM/PM
*/
HOUR_MINUTE_SHORT = 'HH:mm AM',
/**
* 上午/下午 HH:mm
*/
HALF_BLOCK_HOUR_MINUTE = '上午HH:mm',
/**
* 时分 HH:mm 跟随系统的时间来显示24或者12小时制
*/
HOUR_MINUTE_SYSTEM = 'HH:mm sys',
/**
* 月天时分 HH:mm 跟随系统的时间来显示24或者12小时制
*/
MOTH_DAY_HOUR_MINUTE_SYSTEM = 'M月D日 HH:mm',
}
/**
* 时间相关枚举
*/
export enum TimeEnum {
/**
* 1秒: 1000毫秒
*/
SECOND_TO_MILLISECONDS = 1000,
/**
* 30秒: 30* 1000毫秒
*/
THIRTY_SECOND_TO_MILLISECONDS = 30 * 1000,
/**
* 1分钟:60s
*/
MINUTE_TO_SECONDS = 60,
/**
* 5分钟:5*60*1000毫秒
*/
FIVE_MINUTE_TO_MILLISECONDS = 5 * 60 * 1000,
/**
* 1小时:60min
*/
HOUR_TO_MINUTES = 60,
/**
* 1分钟毫秒数
*/
ONE_MINUTE_MILLS = 60000,
/**
* 1小时毫秒数
*/
ONE_HOUR_MILLS = 3600000,
/**
* 1天毫秒数
*/
ONE_DAY_MILLS = 86400000,
/**
* 1天: 24小时
*/
HOURS = 24,
/**
* 1周: 7天
*/
WEEK_TO_DAYS = 7,
/**
* 1年: 12个月
*/
YEAR_TO_MONTHS = 12,
/**
* 1天: 86,400,000毫秒
*/
DAY_TO_MILLISECONDS = 86400000,
/**
* HHmm格式的 时间字符串 长度
*/
HHMM_TIME_LENGTH = 4,
/**
* 时间字符串中,小时的长度
*/
HOURS_STR_LENGTH = 2,
/**
* 时间字符串中,分钟的长度
*/
MINUTE_STR_LENGTH = 2,
/**
* yyyyMMdd格式的 日期字符串 长度
*/
YYYYMMDD_DATE_LENGTH = 8,
/**
* 日期字符串中,年的长度
*/
YEAR_STR_LENGTH = 4,
/**
* 日期字符串中,年月的长度
*/
YEAR_MONTH_STR_LENGTH = 6
}