Files
timi-utils/src/main/java/com/imyeyu/utils/Time.java
2025-10-24 14:19:38 +08:00

463 lines
10 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.imyeyu.utils;
import com.imyeyu.java.TimiJava;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 时间转换相关
*
* @author 夜雨
* @version 2021-06-10 20:07
*/
public class Time {
// ---------- 格式化 ----------
/** 格式化 yy */
public static final SimpleDateFormat year = new SimpleDateFormat("yy");
/** 格式化 yyyy */
public static final SimpleDateFormat yearFull = new SimpleDateFormat("yyyy");
/** 格式化 M */
public static final SimpleDateFormat month = new SimpleDateFormat("M");
/** 格式化 MM */
public static final SimpleDateFormat monthFull = new SimpleDateFormat("MM");
/** 格式化 d */
public static final SimpleDateFormat day = new SimpleDateFormat("d");
/** 格式化 dd */
public static final SimpleDateFormat dayFull = new SimpleDateFormat("dd");
/** 格式化 HH */
public static final SimpleDateFormat hour = new SimpleDateFormat("HH");
/** 格式化 mm */
public static final SimpleDateFormat minute = new SimpleDateFormat("mm");
/** 格式化 ss */
public static final SimpleDateFormat second = new SimpleDateFormat("ss");
/** 格式化 hh:mm */
public static final SimpleDateFormat hhmm = new SimpleDateFormat("HH:mm");
/** 格式化 mm:ss */
public static final SimpleDateFormat mmss = new SimpleDateFormat("mm:ss");
/** 格式化 yyyyMMdd */
public static final SimpleDateFormat ymd = new SimpleDateFormat("yyyyMMdd");
/** 格式化 HH:mm:ss.SSS */
public static final SimpleDateFormat log = new SimpleDateFormat("[HH:mm:ss.SSS]");
/** 格式化 HH:mm:ss.SSS */
public static final SimpleDateFormat longLog = new SimpleDateFormat("[yyyy-MM-dd HH:mm:ss.SSS]");
/** 格式化 yyyy-MM-dd */
public static final SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
/** 格式化 HH:mm:ss */
public static final SimpleDateFormat time = new SimpleDateFormat("HH:mm:ss");
/** 格式化 yyyy-MM-dd HH:mm:ss */
public static final SimpleDateFormat dateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/** 格式化 yyyy-MM-dd'T'HH:mm:ss */
public static final SimpleDateFormat dateTimeT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
// ---------- 长整型时间戳 ----------
/** 1 秒时间戳 */
public static final long S = 1000;
/** 1 分钟时间戳 */
public static final long M = S * 60;
/** 1 小时时间戳 */
public static final long H = M * 60;
/** 1 天时间戳 */
public static final long D = H * 24;
// ---------- 整型时间戳 ----------
/** 1 秒时间戳(整型) */
public static final int SI = 1000;
/** 1 分钟时间戳(整型) */
public static final int MI = SI * 60;
/** 1 小时时间戳(整型) */
public static final int HI = MI * 60;
/** 1 天时间戳(整型) */
public static final int DI = HI * 24;
/**
* 计算两个时间戳精确的日期时间差
*
* @param begin 开始时间戳
* @param end 结束时间戳
* @return 时差
*/
public static Between between(long begin, long end) {
if (end < begin) {
throw new IllegalArgumentException("end time must greater than begin time" + end + " < " + begin);
}
LocalDateTime ldtBegin = toLocalDateTime(begin);
LocalDateTime ldtEnd = toLocalDateTime(end);
Between between = new Between();
between.year = (int) ChronoUnit.YEARS.between(ldtBegin, ldtEnd);
between.month = (int) ChronoUnit.MONTHS.between(ldtBegin, ldtEnd) % 12;
between.day = (int) ChronoUnit.DAYS.between(ldtBegin.plusMonths(between.year * 12L + between.month), ldtEnd);
between.hour = (int) (ChronoUnit.HOURS.between(ldtBegin, ldtEnd) - ChronoUnit.DAYS.between(ldtBegin, ldtEnd) * 24);
between.minute = (int) ChronoUnit.MINUTES.between(ldtBegin, ldtEnd) % 60;
between.second = (int) ChronoUnit.SECONDS.between(ldtBegin, ldtEnd) % 60;
between.millis = (int) ((end - begin) % 1000);
return between;
}
/**
* 获取此刻毫秒
*
* @return 毫秒
*/
public static long now() {
return System.currentTimeMillis();
}
/**
* 获取当前时间 yyyy-MM-dd HH:mm:ss
*
* @return 当前时间
*/
public static String nowString() {
return toDateTime(new Date());
}
/**
* 获取昨天零时时间戳
*
* @return 昨天零时时间戳
*/
public static long yesterday() {
return today() - D;
}
/**
* 获取今天零时时间戳
*
* @return 今天零时时间戳
*/
public static long today() {
long now = now();
final long H8 = H * 8;
return ((now + H8 - (now + H8) % (H * 24)) - H8);
}
/**
* 获取明天零时时间戳
*
* @return 明天零时时间戳
*/
public static long tomorrow() {
return today() + D;
}
/**
* 转义为日期 yyyy-MM-dd
*
* @param unixTime 时间戳
* @return 日期字符串
*/
public static String toDate(long unixTime) {
return date.format(unixTime);
}
/**
* 转义为时间 HH:mm:ss
*
* @param unixTime 时间戳
* @return 时间字符串
*/
public static String toTime(long unixTime) {
return time.format(unixTime);
}
/**
* 转义为日期时间 yyyy-MM-dd HH:mm:ss
*
* @param unixTime 时间戳
* @return 日期时间字符串
*/
public static String toDateTime(long unixTime) {
return dateTime.format(unixTime);
}
/**
* 转义为日期时间 yyyy-MM-dd HH:mm:ss
*
* @param date 时间对象
* @return 日期时间字符串
*/
public static String toDateTime(Date date) {
return dateTime.format(date);
}
/**
* 本地时间对象转时间戳(本地时区)
*
* @param date 本地日期对象
* @return 时间戳
*/
public static Long fromLocalDate(LocalDate date) {
if (date == null) {
return null;
}
return date.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
/**
* 本地时间对象转时间戳(本地时区)
*
* @param dateTime 本地日期对象
* @return 时间戳
*/
public static Long fromLocalDateTime(LocalDateTime dateTime) {
if (dateTime == null) {
return null;
}
return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
}
/**
* 时间戳转本地日期(本地时区)
*
* @param unixTime 时间戳
* @return 本地日期对象
*/
public static LocalDateTime toLocalDateTime(Long unixTime) {
if (unixTime == null) {
return null;
}
return Instant.ofEpochMilli(unixTime).atZone(ZoneId.systemDefault()).toLocalDateTime();
}
/**
* 将时间字符串解析为毫秒值
*
* <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 IllegalArgumentException 输入格式无效
*/
public static long parseToMS(String timeStr) {
if (TimiJava.isEmpty(timeStr)) {
throw new IllegalArgumentException("not found timeStr");
}
String normalized = timeStr.replaceAll("\\s+", "").toLowerCase();
Pattern pattern = Pattern.compile("^(\\d+(?:\\.\\d+)?)(ms|[dhms])?$");
Matcher matcher = pattern.matcher(normalized);
if (!matcher.matches()) {
throw new IllegalArgumentException("invalid format: " + timeStr);
}
double value = Double.parseDouble(matcher.group(1));
String unit = matcher.group(2);
if (TimiJava.isEmpty(unit) || unit.equals("ms")) {
return Math.round(value);
}
double multiplier = switch (unit) {
case "s" -> Time.S;
case "m" -> Time.M;
case "h" -> Time.H;
case "d" -> Time.D;
default -> throw new IllegalArgumentException("invalid format unit: " + unit);
};
return Math.round(value * multiplier);
}
/**
* 媒体时间操作
*
* @author 夜雨
* @version 2023-01-24 01:10
*/
public static class Media {
private static final Pattern PATTERN = Pattern.compile("(\\d*):?([0-5]\\d):([0-5]\\d)\\.?(\\d{1,3})?");
/**
* 解析字符串为毫秒,匹配 999:59:59.999 格式,兼容 999:59:59
*
* @param time 时间字符串
* @return 毫秒
*/
public static long fromString(String time) {
if (TimiJava.isEmpty(time)) {
return 0;
}
Matcher matcher = PATTERN.matcher(time);
if (matcher.find()) {
long h = 0;
if (TimiJava.isNotEmpty(matcher.group(1))) {
h = Long.parseLong(matcher.group(1));
}
long m = Long.parseLong(matcher.group(2));
long s = Long.parseLong(matcher.group(3));
long ms = 0;
if (TimiJava.isNotEmpty(matcher.group(4))) {
String gms = matcher.group(4);
ms = Long.parseLong(gms);
if (gms.length() == 2) {
ms *= 10;
}
}
return h * Time.H + m * Time.M + s * Time.S + ms;
}
return 0;
}
/**
* 秒转媒体时间00:00:00
*
* @param second 秒
* @return 时间字符串
*/
public static String toString(double second) {
return toString((int) second);
}
/**
* 秒转媒体时间00:00:00
*
* @param second 秒
* @return 时间字符串
*/
public static String toString(int second) {
int h = second / 60 / 60;
if (0 < h) {
return String.format("%d:%02d:%02d", h, second / 60 - h * 60, second % 60);
} else {
return String.format("%02d:%02d", second / 60, second % 60);
}
}
/**
* 毫秒转媒体时间音视频播放时间00:00:00.000
*
* @param millis 毫秒
* @return 时间字符串
*/
public static String toString(long millis) {
long s = millis / 1000;
long h = s / 60 / 60;
return String.format("%d:%02d:%02d.%03d", h, s / 60 - h * 60, s % 60, millis % 1000);
}
}
/**
* 时差
*
* @author 夜雨
* @version 2022-10-12 14:46
*/
public static class Between {
int year;
int month;
int day;
int hour;
int minute;
int second;
int millis;
/**
* 获取年数
*
* @return 年数
*/
public int getYear() {
return year;
}
/**
* 获取月数
*
* @return 月数
*/
public int getMonth() {
return month;
}
/**
* 获取天数
*
* @return 天数
*/
public int getDay() {
return day;
}
/**
* 获取小时
*
* @return 小时
*/
public int getHour() {
return hour;
}
/**
* 获取分钟
*
* @return 分钟
*/
public int getMinute() {
return minute;
}
/**
* 获取秒
*
* @return 秒
*/
public int getSecond() {
return second;
}
/**
* 获取毫秒
*
* @return 毫秒
*/
public int getMillis() {
return millis;
}
}
}