<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.0.4</version>
</dependency>
package cn.wzq.utils;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.LinkedHashSet;
import java.util.List;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.*;
import cn.hutool.core.date.format.DateParser;
import cn.hutool.core.date.format.DatePrinter;
import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.StrUtil;
/**
* @ClassName DateUtil
* @Description: TODO
* @Author wzq
* @Date 2019/11/4
* @Version V1.0
**/
public class DateUtils {
/**
* 轉換爲{@link DateTime}對象
*
* @return 當前時間
*/
public static DateTime date() {
return new DateTime();
}
/**
* {@link Date}類型時間轉爲{@link DateTime}
*
* @param date Long類型Date(Unix時間戳)
* @return 時間對象
* @since 3.0.7
*/
public static DateTime date(Date date) {
if (date instanceof DateTime) {
return (DateTime) date;
}
return new DateTime(date);
}
/**
* Long類型時間轉爲{@link DateTime}<br>
* 只支持毫秒級別時間戳,如果需要秒級別時間戳,請自行×1000
*
* @param date Long類型Date(Unix時間戳)
* @return 時間對象
*/
public static DateTime date(long date) {
return new DateTime(date);
}
/**
* {@link Calendar}類型時間轉爲{@link DateTime}
*
* @param calendar {@link Calendar}
* @return 時間對象
*/
public static DateTime date(Calendar calendar) {
return new DateTime(calendar);
}
/**
* 轉換爲Calendar對象
*
* @param date 日期對象
* @return Calendar對象
*/
public static Calendar calendar(Date date) {
return calendar(date.getTime());
}
/**
* 轉換爲Calendar對象
*
* @param millis 時間戳
* @return Calendar對象
*/
public static Calendar calendar(long millis) {
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(millis);
return cal;
}
/**
* 當前時間,格式 yyyy-MM-dd HH:mm:ss
*
* @return 當前時間的標準形式字符串
*/
public static String now() {
return formatDateTime(new DateTime());
}
/**
* 當前時間的時間戳
*
* @param isNano 是否爲高精度時間
* @return 時間
*/
public static long current(boolean isNano) {
return isNano ? System.nanoTime() : System.currentTimeMillis();
}
/**
* 當前時間的時間戳(秒)
*
* @return 當前時間秒數
* @since 4.0.0
*/
public static long currentSeconds() {
return System.currentTimeMillis() / 1000;
}
/**
* 當前日期,格式 yyyy-MM-dd
*
* @return 當前日期的標準形式字符串
*/
public static String today() {
return formatDate(new DateTime());
}
// -------------------------------------------------------------- Part of Date start
/**
* 獲得年的部分
*
* @param date 日期
* @return 年的部分
*/
public static int year(Date date) {
return DateTime.of(date).year();
}
/**
* 獲得指定日期所屬季度
*
* @param date 日期
* @return 第幾個季度
* @deprecated 請使用{@link #quarter(Date)}
*/
@Deprecated
public static int season(Date date) {
return quarter(date);
}
/**
* 獲得指定日期所屬季度,從1開始計數
*
* @param date 日期
* @return 第幾個季度
* @since 4.1.0
*/
public static int quarter(Date date) {
return DateTime.of(date).quarter();
}
/**
* 獲得指定日期所屬季度
*
* @param date 日期
* @return 第幾個季度枚舉
* @since 4.1.0
*/
public static Quarter quarterEnum(Date date) {
return DateTime.of(date).quarterEnum();
}
/**
* 獲得月份,從0開始計數
*
* @param date 日期
* @return 月份,從0開始計數
*/
public static int month(Date date) {
return DateTime.of(date).month();
}
/**
* 獲得月份
*
* @param date 日期
* @return {@link Month}
*/
public static Month monthEnum(Date date) {
return DateTime.of(date).monthEnum();
}
/**
* 獲得指定日期是所在年份的第幾周<br>
*
* @param date 日期
* @return 周
*/
public static int weekOfYear(Date date) {
return DateTime.of(date).weekOfYear();
}
/**
* 獲得指定日期是所在月份的第幾周<br>
*
* @param date 日期
* @return 周
*/
public static int weekOfMonth(Date date) {
return DateTime.of(date).weekOfMonth();
}
/**
* 獲得指定日期是這個日期所在月份的第幾天<br>
*
* @param date 日期
* @return 天
*/
public static int dayOfMonth(Date date) {
return DateTime.of(date).dayOfMonth();
}
/**
* 獲得指定日期是星期幾,1表示週日,2表示週一
*
* @param date 日期
* @return 天
*/
public static int dayOfWeek(Date date) {
return DateTime.of(date).dayOfWeek();
}
/**
* 獲得指定日期是星期幾
*
* @param date 日期
* @return {@link Week}
*/
public static Week dayOfWeekEnum(Date date) {
return DateTime.of(date).dayOfWeekEnum();
}
/**
* 獲得指定日期的小時數部分<br>
*
* @param date 日期
* @param is24HourClock 是否24小時制
* @return 小時數
*/
public static int hour(Date date, boolean is24HourClock) {
return DateTime.of(date).hour(is24HourClock);
}
/**
* 獲得指定日期的分鐘數部分<br>
* 例如:10:04:15.250 =》 4
*
* @param date 日期
* @return 分鐘數
*/
public static int minute(Date date) {
return DateTime.of(date).minute();
}
/**
* 獲得指定日期的秒數部分<br>
*
* @param date 日期
* @return 秒數
*/
public static int second(Date date) {
return DateTime.of(date).second();
}
/**
* 獲得指定日期的毫秒數部分<br>
*
* @param date 日期
* @return 毫秒數
*/
public static int millsecond(Date date) {
return DateTime.of(date).millsecond();
}
/**
* 是否爲上午
*
* @param date 日期
* @return 是否爲上午
*/
public static boolean isAM(Date date) {
return DateTime.of(date).isAM();
}
/**
* 是否爲下午
*
* @param date 日期
* @return 是否爲下午
*/
public static boolean isPM(Date date) {
return DateTime.of(date).isPM();
}
/**
* @return 今年
*/
public static int thisYear() {
return year(date());
}
/**
* @return 當前月份
*/
public static int thisMonth() {
return month(date());
}
/**
* @return 當前月份 {@link Month}
*/
public static Month thisMonthEnum() {
return monthEnum(date());
}
/**
* @return 當前日期所在年份的第幾周
*/
public static int thisWeekOfYear() {
return weekOfYear(date());
}
/**
* @return 當前日期所在年份的第幾周
*/
public static int thisWeekOfMonth() {
return weekOfMonth(date());
}
/**
* @return 當前日期是這個日期所在月份的第幾天
*/
public static int thisDayOfMonth() {
return dayOfMonth(date());
}
/**
* @return 當前日期是星期幾
*/
public static int thisDayOfWeek() {
return dayOfWeek(date());
}
/**
* @return 當前日期是星期幾 {@link Week}
*/
public static Week thisDayOfWeekEnum() {
return dayOfWeekEnum(date());
}
/**
* @param is24HourClock 是否24小時制
* @return 當前日期的小時數部分<br>
*/
public static int thisHour(boolean is24HourClock) {
return hour(date(), is24HourClock);
}
/**
* @return 當前日期的分鐘數部分<br>
*/
public static int thisMinute() {
return minute(date());
}
/**
* @return 當前日期的秒數部分<br>
*/
public static int thisSecond() {
return second(date());
}
/**
* @return 當前日期的毫秒數部分<br>
*/
public static int thisMillsecond() {
return millsecond(date());
}
// -------------------------------------------------------------- Part of Date end
/**
* 獲得指定日期年份和季節<br>
* 格式:[20131]表示2013年第一季度
*
* @param date 日期
* @return Season ,類似於 20132
* @deprecated 請使用{@link #yearAndQuarter} 代替
*/
@Deprecated
public static String yearAndSeason(Date date) {
return yearAndSeason(calendar(date));
}
/**
* 獲得指定日期年份和季節<br>
* 格式:[20131]表示2013年第一季度
*
* @param date 日期
* @return Quarter ,類似於 20132
*/
public static String yearAndQuarter(Date date) {
return yearAndQuarter(calendar(date));
}
/**
* 獲得指定日期區間內的年份和季節<br>
*
* @param startDate 起始日期(包含)
* @param endDate 結束日期(包含)
* @return Season列表 ,元素類似於 20132
* @deprecated 請使用{@link #yearAndQuarter} 代替
*/
@Deprecated
public static LinkedHashSet<String> yearAndSeasons(Date startDate, Date endDate) {
return yearAndQuarter(startDate, endDate);
}
/**
* 獲得指定日期區間內的年份和季節<br>
*
* @param startDate 起始日期(包含)
* @param endDate 結束日期(包含)
* @return 季度列表 ,元素類似於 20132
*/
public static LinkedHashSet<String> yearAndQuarter(Date startDate, Date endDate) {
if (startDate == null || endDate == null) {
return new LinkedHashSet<String>(0);
}
return yearAndQuarter(startDate.getTime(), endDate.getTime());
}
/**
* 獲得指定日期區間內的年份和季節<br>
*
* @param startDate 起始日期(包含)
* @param endDate 結束日期(包含)
* @return 季度列表 ,元素類似於 20132
* @since 4.1.15
*/
public static LinkedHashSet<String> yearAndQuarter(long startDate, long endDate) {
LinkedHashSet<String> quarters = new LinkedHashSet<String>();
final Calendar cal = calendar(startDate);
while (startDate <= endDate) {
// 如果開始時間超出結束時間,讓結束時間爲開始時間,處理完後結束循環
quarters.add(yearAndQuarter(cal));
cal.add(Calendar.MONTH, 3);
startDate = cal.getTimeInMillis();
}
return quarters;
}
// ------------------------------------ Format start ----------------------------------------------
/**
* 根據特定格式格式化日期
*
* @param date 被格式化的日期
* @param format 日期格式,常用格式見: {@link DatePattern}
* @return 格式化後的字符串
*/
public static String format(Date date, String format) {
if (null == date || StrUtil.isBlank(format)) {
return null;
}
return format(date, FastDateFormat.getInstance(format));
}
/**
* 根據特定格式格式化日期
*
* @param date 被格式化的日期
* @param format {@link DatePrinter} 或 {@link FastDateFormat}
* @return 格式化後的字符串
*/
public static String format(Date date, DatePrinter format) {
if (null == format || null == date) {
return null;
}
return format.format(date);
}
/**
* 根據特定格式格式化日期
*
* @param date 被格式化的日期
* @param format {@link SimpleDateFormat}
* @return 格式化後的字符串
*/
public static String format(Date date, DateFormat format) {
if (null == format || null == date) {
return null;
}
return format.format(date);
}
/**
* 格式化日期時間<br>
* 格式 yyyy-MM-dd HH:mm:ss
*
* @param date 被格式化的日期
* @return 格式化後的日期
*/
public static String formatDateTime(Date date) {
if (null == date) {
return null;
}
return DatePattern.NORM_DATETIME_FORMAT.format(date);
}
/**
* 格式化日期部分(不包括時間)<br>
* 格式 yyyy-MM-dd
*
* @param date 被格式化的日期
* @return 格式化後的字符串
*/
public static String formatDate(Date date) {
if (null == date) {
return null;
}
return DatePattern.NORM_DATE_FORMAT.format(date);
}
/**
* 格式化時間<br>
* 格式 HH:mm:ss
*
* @param date 被格式化的日期
* @return 格式化後的字符串
* @since 3.0.1
*/
public static String formatTime(Date date) {
if (null == date) {
return null;
}
return DatePattern.NORM_TIME_FORMAT.format(date);
}
/**
* 格式化爲Http的標準日期格式
*
* @param date 被格式化的日期
* @return HTTP標準形式日期字符串
*/
public static String formatHttpDate(Date date) {
if (null == date) {
return null;
}
return DatePattern.HTTP_DATETIME_FORMAT.format(date);
}
/**
* 格式化爲中文日期格式,如果isUppercase爲false,則返回類似:2018年10月24日,否則返回二〇一八年十月二十四日
*
* @param date 被格式化的日期
* @param isUppercase 是否採用大寫形式
* @return 中文日期字符串
* @since 4.1.19
*/
public static String formatChineseDate(Date date, boolean isUppercase) {
if (null == date) {
return null;
}
String format = DatePattern.CHINESE_DATE_FORMAT.format(date);
if (isUppercase) {
final StringBuilder builder = StrUtil.builder(format.length());
builder.append(Convert.numberToChinese(Integer.parseInt(format.substring(0, 1)), false));
builder.append(Convert.numberToChinese(Integer.parseInt(format.substring(1, 2)), false));
builder.append(Convert.numberToChinese(Integer.parseInt(format.substring(2, 3)), false));
builder.append(Convert.numberToChinese(Integer.parseInt(format.substring(3, 4)), false));
builder.append(format.substring(4, 5));
builder.append(Convert.numberToChinese(Integer.parseInt(format.substring(5, 7)), false));
builder.append(format.substring(7, 8));
builder.append(Convert.numberToChinese(Integer.parseInt(format.substring(8, 10)), false));
builder.append(format.substring(10));
format = builder.toString().replace('零', '〇');
}
return format;
}
// ------------------------------------ Format end ----------------------------------------------
// ------------------------------------ Parse start ----------------------------------------------
/**
* 構建DateTime對象
*
* @param dateStr Date字符串
* @param dateFormat 格式化器 {@link SimpleDateFormat}
* @return DateTime對象
*/
public static DateTime parse(String dateStr, DateFormat dateFormat) {
return new DateTime(dateStr, dateFormat);
}
/**
* 構建DateTime對象
*
* @param dateStr Date字符串
* @param parser 格式化器,{@link FastDateFormat}
* @return DateTime對象
*/
public static DateTime parse(String dateStr, DateParser parser) {
return new DateTime(dateStr, parser);
}
/**
* 將特定格式的日期轉換爲Date對象
*
* @param dateStr 特定格式的日期
* @param format 格式,例如yyyy-MM-dd
* @return 日期對象
*/
public static DateTime parse(String dateStr, String format) {
return new DateTime(dateStr, format);
}
/**
* 格式yyyy-MM-dd HH:mm:ss
*
* @param dateString 標準形式的時間字符串
* @return 日期對象
*/
public static DateTime parseDateTime(String dateString) {
dateString = normalize(dateString);
return parse(dateString, DatePattern.NORM_DATETIME_FORMAT);
}
/**
* 格式yyyy-MM-dd
*
* @param dateString 標準形式的日期字符串
* @return 日期對象
*/
public static DateTime parseDate(String dateString) {
dateString = normalize(dateString);
return parse(dateString, DatePattern.NORM_DATE_FORMAT);
}
/**
* 解析時間,格式HH:mm:ss,默認爲1970-01-01
*
* @param timeString 標準形式的日期字符串
* @return 日期對象
*/
public static DateTime parseTime(String timeString) {
timeString = normalize(timeString);
return parse(timeString, DatePattern.NORM_TIME_FORMAT);
}
/**
* 解析時間,格式HH:mm:ss,日期默認爲今天
*
* @param timeString 標準形式的日期字符串
* @return 日期對象
* @since 3.1.1
*/
public static DateTime parseTimeToday(String timeString) {
timeString = StrUtil.format("{} {}", today(), timeString);
return parse(timeString, DatePattern.NORM_DATETIME_FORMAT);
}
/**
* 解析UTC時間,格式爲:yyyy-MM-dd'T'HH:mm:ss'Z
*
* @param utcString UTC時間
* @return 日期對象
* @since 4.1.14
*/
public static DateTime parseUTC(String utcString) {
return parse(utcString, DatePattern.UTC_FORMAT);
}
/**
* 將日期字符串轉換爲{@link DateTime}對象,格式:<br>
* <ol>
* <li>yyyy-MM-dd HH:mm:ss</li>
* <li>yyyy/MM/dd HH:mm:ss</li>
* <li>yyyy.MM.dd HH:mm:ss</li>
* <li>yyyy年MM月dd日 HH時mm分ss秒</li>
* <li>yyyy-MM-dd</li>
* <li>yyyy/MM/dd</li>
* <li>yyyy.MM.dd</li>
* <li>HH:mm:ss</li>
* <li>HH時mm分ss秒</li>
* <li>yyyy-MM-dd HH:mm</li>
* <li>yyyy-MM-dd HH:mm:ss.SSS</li>
* <li>yyyyMMddHHmmss</li>
* <li>yyyyMMddHHmmssSSS</li>
* <li>yyyyMMdd</li>
* <li>EEE, dd MMM yyyy HH:mm:ss z</li>
* <li>EEE MMM dd HH:mm:ss zzz yyyy</li>
* </ol>
*
* @param dateStr 日期字符串
* @return 日期
*/
public static DateTime parse(String dateStr) {
if (null == dateStr) {
return null;
}
// 去掉兩邊空格並去掉中文日期中的“日”,以規範長度
dateStr = dateStr.trim().replace("日", "");
int length = dateStr.length();
if (Validator.isNumber(dateStr)) {
// 純數字形式
if (length == DatePattern.PURE_DATETIME_PATTERN.length()) {
return parse(dateStr, DatePattern.PURE_DATETIME_FORMAT);
} else if (length == DatePattern.PURE_DATETIME_MS_PATTERN.length()) {
return parse(dateStr, DatePattern.PURE_DATETIME_MS_FORMAT);
} else if (length == DatePattern.PURE_DATE_PATTERN.length()) {
return parse(dateStr, DatePattern.PURE_DATE_FORMAT);
} else if (length == DatePattern.PURE_TIME_PATTERN.length()) {
return parse(dateStr, DatePattern.PURE_TIME_FORMAT);
}
}
if (length == DatePattern.NORM_DATETIME_PATTERN.length() || length == DatePattern.NORM_DATETIME_PATTERN.length() + 1) {
if(dateStr.contains("T")) {
//UTC時間格式:類似2018-09-13T05:34:31
return parseUTC(dateStr);
}
return parseDateTime(dateStr);
} else if (length == DatePattern.NORM_DATE_PATTERN.length()) {
return parseDate(dateStr);
} else if (length == DatePattern.NORM_TIME_PATTERN.length() || length == DatePattern.NORM_TIME_PATTERN.length() + 1) {
return parseTimeToday(dateStr);
} else if (length == DatePattern.NORM_DATETIME_MINUTE_PATTERN.length() || length == DatePattern.NORM_DATETIME_MINUTE_PATTERN.length() + 1) {
return parse(normalize(dateStr), DatePattern.NORM_DATETIME_MINUTE_FORMAT);
} else if (length >= DatePattern.NORM_DATETIME_MS_PATTERN.length() - 2) {
return parse(normalize(dateStr), DatePattern.NORM_DATETIME_MS_FORMAT);
}
// 沒有更多匹配的時間格式
throw new DateException("No format fit for date String [{}] !", dateStr);
}
// ------------------------------------ Parse end ----------------------------------------------
// ------------------------------------ Offset start ----------------------------------------------
/**
* 獲取某天的開始時間
*
* @param date 日期
* @return {@link DateTime}
*/
public static DateTime beginOfDay(Date date) {
return new DateTime(beginOfDay(calendar(date)));
}
/**
* 獲取某天的結束時間
*
* @param date 日期
* @return {@link DateTime}
*/
public static DateTime endOfDay(Date date) {
return new DateTime(endOfDay(calendar(date)));
}
/**
* 獲取某天的開始時間
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfDay(Calendar calendar) {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar;
}
/**
* 獲取某天的結束時間
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfDay(Calendar calendar) {
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
return calendar;
}
/**
* 獲取某周的開始時間
*
* @param date 日期
* @return {@link DateTime}
*/
public static DateTime beginOfWeek(Date date) {
return new DateTime(beginOfWeek(calendar(date)));
}
/**
* 獲取某周的結束時間
*
* @param date 日期
* @return {@link DateTime}
*/
public static DateTime endOfWeek(Date date) {
return new DateTime(endOfWeek(calendar(date)));
}
/**
* 獲取某周的開始時間
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfWeek(Calendar calendar) {
return beginOfWeek(calendar, true);
}
/**
* 獲取某周的開始時間,週一定爲一週的開始時間
*
* @param calendar 日期 {@link Calendar}
* @param isMondayAsFirstDay 是否週一做爲一週的第一天(false表示週日做爲第一天)
* @return {@link Calendar}
* @since 3.1.2
*/
public static Calendar beginOfWeek(Calendar calendar, boolean isMondayAsFirstDay) {
if (isMondayAsFirstDay) {
// 設置週一爲一週開始
calendar.setFirstDayOfWeek(Week.MONDAY.getValue());
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
} else {
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
}
return beginOfDay(calendar);
}
/**
* 獲取某周的結束時間,週日定爲一週的結束
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfWeek(Calendar calendar) {
return endOfWeek(calendar, true);
}
/**
* 獲取某周的結束時間
*
* @param calendar 日期 {@link Calendar}
* @param isSundayAsLastDay 是否週日做爲一週的最後一天(false表示週六做爲最後一天)
* @return {@link Calendar}
* @since 3.1.2
*/
public static Calendar endOfWeek(Calendar calendar, boolean isSundayAsLastDay) {
if (isSundayAsLastDay) {
// 設置週一爲一週開始
calendar.setFirstDayOfWeek(Week.MONDAY.getValue());
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
} else {
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SATURDAY);
}
return endOfDay(calendar);
}
/**
* 獲取某月的開始時間
*
* @param date 日期
* @return {@link DateTime}
*/
public static DateTime beginOfMonth(Date date) {
return new DateTime(beginOfMonth(calendar(date)));
}
/**
* 獲取某月的結束時間
*
* @param date 日期
* @return {@link DateTime}
*/
public static DateTime endOfMonth(Date date) {
return new DateTime(endOfMonth(calendar(date)));
}
/**
* 獲取某月的開始時間
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfMonth(Calendar calendar) {
calendar.set(Calendar.DAY_OF_MONTH, 1);
return beginOfDay(calendar);
}
/**
* 獲取某月的結束時間
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfMonth(Calendar calendar) {
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
return endOfDay(calendar);
}
/**
* 獲取某季度的開始時間
*
* @param date 日期
* @return {@link DateTime}
*/
public static DateTime beginOfQuarter(Date date) {
return new DateTime(beginOfQuarter(calendar(date)));
}
/**
* 獲取某季度的結束時間
*
* @param date 日期
* @return {@link DateTime}
*/
public static DateTime endOfQuarter(Date date) {
return new DateTime(endOfQuarter(calendar(date)));
}
/**
* 獲取某季度的開始時間
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.1.0
*/
public static Calendar beginOfQuarter(Calendar calendar) {
calendar.set(Calendar.MONTH, calendar.get(DateField.MONTH.getValue()) / 3 * 3);
calendar.set(Calendar.DAY_OF_MONTH, 1);
return beginOfDay(calendar);
}
/**
* 獲取某季度的結束時間
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.1.0
*/
public static Calendar endOfQuarter(Calendar calendar) {
calendar.set(Calendar.MONTH, calendar.get(DateField.MONTH.getValue()) / 3 * 3 + 2);
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
return endOfDay(calendar);
}
/**
* 獲取某年的開始時間
*
* @param date 日期
* @return {@link DateTime}
*/
public static DateTime beginOfYear(Date date) {
return new DateTime(beginOfYear(calendar(date)));
}
/**
* 獲取某年的結束時間
*
* @param date 日期
* @return {@link DateTime}
*/
public static DateTime endOfYear(Date date) {
return new DateTime(endOfYear(calendar(date)));
}
/**
* 獲取某年的開始時間
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfYear(Calendar calendar) {
calendar.set(Calendar.MONTH, Calendar.JANUARY);
return beginOfMonth(calendar);
}
/**
* 獲取某年的結束時間
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfYear(Calendar calendar) {
calendar.set(Calendar.MONTH, Calendar.DECEMBER);
return endOfMonth(calendar);
}
// --------------------------------------------------- Offset for now
/**
* 昨天
*
* @return 昨天
*/
public static DateTime yesterday() {
return offsetDay(new DateTime(), -1);
}
/**
* 明天
*
* @return 明天
* @since 3.0.1
*/
public static DateTime tomorrow() {
return offsetDay(new DateTime(), 1);
}
/**
* 上週
*
* @return 上週
*/
public static DateTime lastWeek() {
return offsetWeek(new DateTime(), -1);
}
/**
* 下週
*
* @return 下週
* @since 3.0.1
*/
public static DateTime nextWeek() {
return offsetWeek(new DateTime(), 1);
}
/**
* 上個月
*
* @return 上個月
*/
public static DateTime lastMonth() {
return offsetMonth(new DateTime(), -1);
}
/**
* 下個月
*
* @return 下個月
* @since 3.0.1
*/
public static DateTime nextMonth() {
return offsetMonth(new DateTime(), 1);
}
/**
* 偏移毫秒數
*
* @param date 日期
* @param offset 偏移毫秒數,正數向未來偏移,負數向歷史偏移
* @return 偏移後的日期
*/
public static DateTime offsetMillisecond(Date date, int offset) {
return offset(date, DateField.MILLISECOND, offset);
}
/**
* 偏移秒數
*
* @param date 日期
* @param offset 偏移秒數,正數向未來偏移,負數向歷史偏移
* @return 偏移後的日期
*/
public static DateTime offsetSecond(Date date, int offset) {
return offset(date, DateField.SECOND, offset);
}
/**
* 偏移分鐘
*
* @param date 日期
* @param offset 偏移分鐘數,正數向未來偏移,負數向歷史偏移
* @return 偏移後的日期
*/
public static DateTime offsetMinute(Date date, int offset) {
return offset(date, DateField.MINUTE, offset);
}
/**
* 偏移小時
*
* @param date 日期
* @param offset 偏移小時數,正數向未來偏移,負數向歷史偏移
* @return 偏移後的日期
*/
public static DateTime offsetHour(Date date, int offset) {
return offset(date, DateField.HOUR_OF_DAY, offset);
}
/**
* 偏移天
*
* @param date 日期
* @param offset 偏移天數,正數向未來偏移,負數向歷史偏移
* @return 偏移後的日期
*/
public static DateTime offsetDay(Date date, int offset) {
return offset(date, DateField.DAY_OF_YEAR, offset);
}
/**
* 偏移周
*
* @param date 日期
* @param offset 偏移週數,正數向未來偏移,負數向歷史偏移
* @return 偏移後的日期
*/
public static DateTime offsetWeek(Date date, int offset) {
return offset(date, DateField.WEEK_OF_YEAR, offset);
}
/**
* 偏移月
*
* @param date 日期
* @param offset 偏移月數,正數向未來偏移,負數向歷史偏移
* @return 偏移後的日期
*/
public static DateTime offsetMonth(Date date, int offset) {
return offset(date, DateField.MONTH, offset);
}
/**
* 獲取指定日期偏移指定時間後的時間
*
* @param date 基準日期
* @param dateField 偏移的粒度大小(小時、天、月等){@link DateField}
* @param offset 偏移量,正數爲向後偏移,負數爲向前偏移
* @return 偏移後的日期
*/
public static DateTime offset(Date date, DateField dateField, int offset) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(dateField.getValue(), offset);
return new DateTime(cal.getTime());
}
/**
* 獲取指定日期偏移指定時間後的時間
*
* @param date 基準日期
* @param dateField 偏移的粒度大小(小時、天、月等){@link DateField}
* @param offset 偏移量,正數爲向後偏移,負數爲向前偏移
* @return 偏移後的日期
* @deprecated please use {@link DateUtil#offset(Date, DateField, int)}
*/
@Deprecated
public static DateTime offsetDate(Date date, DateField dateField, int offset) {
return offset(date, dateField, offset);
}
// ------------------------------------ Offset end ----------------------------------------------
/**
* 判斷兩個日期相差的時長,只保留絕對值
*
* @param beginDate 起始日期
* @param endDate 結束日期
* @param unit 相差的單位:相差 天{@link DateUnit#DAY}、小時{@link DateUnit#HOUR} 等
* @return 日期差
*/
public static long between(Date beginDate, Date endDate, DateUnit unit) {
return between(beginDate, endDate, unit, true);
}
/**
* 判斷兩個日期相差的時長
*
* @param beginDate 起始日期
* @param endDate 結束日期
* @param unit 相差的單位:相差 天{@link DateUnit#DAY}、小時{@link DateUnit#HOUR} 等
* @param isAbs 日期間隔是否只保留絕對值正數
* @return 日期差
* @since 3.3.1
*/
public static long between(Date beginDate, Date endDate, DateUnit unit, boolean isAbs) {
return new DateBetween(beginDate, endDate, isAbs).between(unit);
}
/**
* 判斷兩個日期相差的毫秒數
*
* @param beginDate 起始日期
* @param endDate 結束日期
* @return 日期差
* @since 3.0.1
*/
public static long betweenMs(Date beginDate, Date endDate) {
return new DateBetween(beginDate, endDate).between(DateUnit.MS);
}
/**
* 判斷兩個日期相差的天數<br>
*
* <pre>
* 有時候我們計算相差天數的時候需要忽略時分秒。
* 比如:2016-02-01 23:59:59和2016-02-02 00:00:00相差一秒
* 如果isReset爲<code>false</code>相差天數爲0。
* 如果isReset爲<code>true</code>相差天數將被計算爲1
* </pre>
*
* @param beginDate 起始日期
* @param endDate 結束日期
* @param isReset 是否重置時間爲起始時間
* @return 日期差
* @since 3.0.1
*/
public static long betweenDay(Date beginDate, Date endDate, boolean isReset) {
if (isReset) {
beginDate = beginOfDay(beginDate);
endDate = beginOfDay(endDate);
}
return between(beginDate, endDate, DateUnit.DAY);
}
/**
* 計算兩個日期相差月數<br>
* 在非重置情況下,如果起始日期的天小於結束日期的天,月數要少算1(不足1個月)
*
* @param beginDate 起始日期
* @param endDate 結束日期
* @param isReset 是否重置時間爲起始時間(重置天時分秒)
* @return 相差月數
* @since 3.0.8
*/
public static long betweenMonth(Date beginDate, Date endDate, boolean isReset) {
return new DateBetween(beginDate, endDate).betweenMonth(isReset);
}
/**
* 計算兩個日期相差年數<br>
* 在非重置情況下,如果起始日期的月小於結束日期的月,年數要少算1(不足1年)
*
* @param beginDate 起始日期
* @param endDate 結束日期
* @param isReset 是否重置時間爲起始時間(重置月天時分秒)
* @return 相差年數
* @since 3.0.8
*/
public static long betweenYear(Date beginDate, Date endDate, boolean isReset) {
return new DateBetween(beginDate, endDate).betweenYear(isReset);
}
/**
* 格式化日期間隔輸出
*
* @param beginDate 起始日期
* @param endDate 結束日期
* @param level 級別,按照天、小時、分、秒、毫秒分爲5個等級
* @return XX天XX小時XX分XX秒
*/
public static String formatBetween(Date beginDate, Date endDate, BetweenFormater.Level level) {
return formatBetween(between(beginDate, endDate, DateUnit.MS), level);
}
/**
* 格式化日期間隔輸出,精確到毫秒
*
* @param beginDate 起始日期
* @param endDate 結束日期
* @return XX天XX小時XX分XX秒
* @since 3.0.1
*/
public static String formatBetween(Date beginDate, Date endDate) {
return formatBetween(between(beginDate, endDate, DateUnit.MS));
}
/**
* 格式化日期間隔輸出
*
* @param betweenMs 日期間隔
* @param level 級別,按照天、小時、分、秒、毫秒分爲5個等級
* @return XX天XX小時XX分XX秒XX毫秒
*/
public static String formatBetween(long betweenMs, BetweenFormater.Level level) {
return new BetweenFormater(betweenMs, level).format();
}
/**
* 格式化日期間隔輸出,精確到毫秒
*
* @param betweenMs 日期間隔
* @return XX天XX小時XX分XX秒XX毫秒
* @since 3.0.1
*/
public static String formatBetween(long betweenMs) {
return new BetweenFormater(betweenMs, BetweenFormater.Level.MILLSECOND).format();
}
/**
* 當前日期是否在日期指定範圍內<br>
* 起始日期和結束日期可以互換
*
* @param date 被檢查的日期
* @param beginDate 起始日期
* @param endDate 結束日期
* @return 是否在範圍內
* @since 3.0.8
*/
public static boolean isIn(Date date, Date beginDate, Date endDate) {
if (date instanceof DateTime) {
return ((DateTime) date).isIn(beginDate, endDate);
} else {
return new DateTime(date).isIn(beginDate, endDate);
}
}
/**
* 是否爲相同時間
*
* @param date1 日期1
* @param date2 日期2
* @return 是否爲相同時間
* @since 4.1.13
*/
public static boolean isSameTime(Date date1, Date date2) {
return date1.compareTo(date2) == 0;
}
/**
* 比較兩個日期是否爲同一天
*
* @param date1 日期1
* @param date2 日期2
* @return 是否爲同一天
* @since 4.1.13
*/
public static boolean isSameDay(final Date date1, final Date date2) {
if (date1 == null || date2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
return isSameDay(calendar(date1), calendar(date2));
}
/**
* 比較兩個日期是否爲同一天
*
* @param cal1 日期1
* @param cal2 日期2
* @return 是否爲同一天
* @since 4.1.13
*/
public static boolean isSameDay(Calendar cal1, Calendar cal2) {
if (cal1 == null || cal2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
return cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) && //
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && //
cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA);
}
/**
* 計時,常用於記錄某段代碼的執行時間,單位:納秒
*
* @param preTime 之前記錄的時間
* @return 時間差,納秒
*/
public static long spendNt(long preTime) {
return System.nanoTime() - preTime;
}
/**
* 計時,常用於記錄某段代碼的執行時間,單位:毫秒
*
* @param preTime 之前記錄的時間
* @return 時間差,毫秒
*/
public static long spendMs(long preTime) {
return System.currentTimeMillis() - preTime;
}
/**
* 格式化成yyMMddHHmm後轉換爲int型
*
* @param date 日期
* @return int
*/
public static int toIntSecond(Date date) {
return Integer.parseInt(DateUtil.format(date, "yyMMddHHmm"));
}
/**
* 計算指定指定時間區間內的週數
*
* @param start 開始時間
* @param end 結束時間
* @return 週數
*/
public static int weekCount(Date start, Date end) {
final Calendar startCalendar = Calendar.getInstance();
startCalendar.setTime(start);
final Calendar endCalendar = Calendar.getInstance();
endCalendar.setTime(end);
final int startWeekofYear = startCalendar.get(Calendar.WEEK_OF_YEAR);
final int endWeekofYear = endCalendar.get(Calendar.WEEK_OF_YEAR);
int count = endWeekofYear - startWeekofYear + 1;
if (Calendar.SUNDAY != startCalendar.get(Calendar.DAY_OF_WEEK)) {
count--;
}
return count;
}
/**
* 計時器<br>
* 計算某個過程花費的時間,精確到毫秒
*
* @return Timer
*/
public static TimeInterval timer() {
return new TimeInterval();
}
/**
* 生日轉爲年齡,計算法定年齡
*
* @param birthDay 生日,標準日期字符串
* @return 年齡
*/
public static int ageOfNow(String birthDay) {
return ageOfNow(parse(birthDay));
}
/**
* 生日轉爲年齡,計算法定年齡
*
* @param birthDay 生日
* @return 年齡
*/
public static int ageOfNow(Date birthDay) {
return age(birthDay, date());
}
/**
* 計算相對於dateToCompare的年齡,長用於計算指定生日在某年的年齡
*
* @param birthDay 生日
* @param dateToCompare 需要對比的日期
* @return 年齡
*/
public static int age(Date birthDay, Date dateToCompare) {
Calendar cal = Calendar.getInstance();
cal.setTime(dateToCompare);
if (cal.before(birthDay)) {
throw new IllegalArgumentException(StrUtil.format("Birthday is after date {}!", formatDate(dateToCompare)));
}
int year = cal.get(Calendar.YEAR);
int month = cal.get(Calendar.MONTH);
int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
cal.setTime(birthDay);
int age = year - cal.get(Calendar.YEAR);
int monthBirth = cal.get(Calendar.MONTH);
if (month == monthBirth) {
int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
if (dayOfMonth < dayOfMonthBirth) {
// 如果生日在當月,但是未達到生日當天的日期,年齡減一
age--;
}
} else if (month < monthBirth) {
// 如果當前月份未達到生日的月份,年齡計算減一
age--;
}
return age;
}
/**
* 是否閏年
*
* @param year 年
* @return 是否閏年
*/
public static boolean isLeapYear(int year) {
return new GregorianCalendar().isLeapYear(year);
}
/**
* 判定給定開始時間經過某段時間後是否過期
*
* @param startDate 開始時間
* @param dateField 時間單位
* @param timeLength 時長
* @param checkedDate 被比較的時間。如果經過時長後的時間晚於被檢查的時間,就表示過期
* @return 是否過期
* @since 3.1.1
*/
public static boolean isExpired(Date startDate, DateField dateField, int timeLength, Date checkedDate) {
final Date endDate = offset(startDate, dateField, timeLength);
return endDate.after(checkedDate);
}
/**
* HH:mm:ss 時間格式字符串轉爲秒數<br>
* 參考:https://github.com/iceroot
*
* @param timeStr 字符串時分秒(HH:mm:ss)格式
* @return 時分秒轉換後的秒數
* @since 3.1.2
*/
public static int timeToSecond(String timeStr) {
if (StrUtil.isEmpty(timeStr)) {
return 0;
}
final List<String> hms = StrUtil.splitTrim(timeStr, StrUtil.C_COLON, 3);
int lastIndex = hms.size() - 1;
int result = 0;
for (int i = lastIndex; i >= 0; i--) {
result += Integer.parseInt(hms.get(i)) * Math.pow(60, (lastIndex - i));
}
return result;
}
/**
* 秒數轉爲時間格式(HH:mm:ss)<br>
* 參考:https://github.com/iceroot
*
* @param seconds 需要轉換的秒數
* @return 轉換後的字符串
* @since 3.1.2
*/
public static String secondToTime(int seconds) {
if (seconds < 0) {
throw new IllegalArgumentException("Seconds must be a positive number!");
}
int hour = seconds / 3600;
int other = seconds % 3600;
int minute = other / 60;
int second = other % 60;
final StringBuilder sb = new StringBuilder();
if (hour < 10) {
sb.append("0");
}
sb.append(hour);
sb.append(":");
if (minute < 10) {
sb.append("0");
}
sb.append(minute);
sb.append(":");
if (second < 10) {
sb.append("0");
}
sb.append(second);
return sb.toString();
}
/**
* 創建日期範圍生成器
*
* @param start 起始日期時間
* @param end 結束日期時間
* @param unit 步進單位
* @return {@link DateRange}
*/
public static DateRange range(Date start, Date end, final DateField unit) {
return new DateRange(start, end, unit);
}
/**
* 創建日期範圍生成器
*
* @param start 起始日期時間
* @param end 結束日期時間
* @param unit 步進單位
* @return {@link DateRange}
*/
public static List<DateTime> rangeToList(Date start, Date end, final DateField unit) {
return CollUtil.newArrayList((Iterable<DateTime>) range(start, end, unit));
}
// Private method start
/**
* 獲得指定日期年份和季節<br>
* 格式:[20131]表示2013年第一季度
*
* @param cal 日期
* @deprecated 請使用{@link yearAndQuarter}
*/
@Deprecated
private static String yearAndSeason(Calendar cal) {
return new StringBuilder().append(cal.get(Calendar.YEAR)).append(cal.get(Calendar.MONTH) / 3 + 1).toString();
}
/**
* 獲得指定日期年份和季節<br>
* 格式:[20131]表示2013年第一季度
*
* @param cal 日期
*/
private static String yearAndQuarter(Calendar cal) {
return new StringBuilder().append(cal.get(Calendar.YEAR)).append(cal.get(Calendar.MONTH) / 3 + 1).toString();
}
/**
* 標準化日期,默認處理以空格區分的日期時間格式,空格前爲日期,空格後爲時間:<br>
* 將以下字符替換爲"-"
*
* <pre>
* "."
* "/"
* "年"
* "月"
* </pre>
*
* 將以下字符去除
*
* <pre>
* "日"
* </pre>
*
* 將以下字符替換爲":"
*
* <pre>
* "時"
* "分"
* "秒"
* </pre>
*
* 當末位是":"時去除之(不存在毫秒時)
*
* @param dateStr 日期時間字符串
* @return 格式化後的日期字符串
*/
private static String normalize(String dateStr) {
if (StrUtil.isBlank(dateStr)) {
return dateStr;
}
// 日期時間分開處理
final List<String> dateAndTime = StrUtil.splitTrim(dateStr, ' ');
final int size = dateAndTime.size();
if (size < 1 || size > 2) {
// 非可被標準處理的格式
return dateStr;
}
final StringBuilder builder = StrUtil.builder();
// 日期部分("\"、"/"、"."、"年"、"月"都替換爲"-")
String datePart = dateAndTime.get(0).replaceAll("[\\/.年月]", "-");
datePart = StrUtil.removeSuffix(datePart, "日");
builder.append(datePart);
// 時間部分
if (size == 2) {
builder.append(' ');
String timePart = dateAndTime.get(1).replaceAll("[時分秒]", ":");
timePart = StrUtil.removeSuffix(timePart, ":");
builder.append(timePart);
}
return builder.toString();
}
// Private method end
}