This commit is contained in:
Looly 2023-03-14 19:07:24 +08:00
parent f502342611
commit e4999ca6f6
4 changed files with 87 additions and 108 deletions

View File

@ -363,7 +363,7 @@ public class CollUtil {
* 例如集合1[a, b, c, c, c]集合2[a, b, c, c]<br>
* 结果[a, b, c]此结果中只保留了一个c
*
* @param <T> 集合元素类型
* @param <T> 集合元素类型
* @param colls 集合列表
* @return 交集的集合返回 {@link LinkedHashSet}
* @since 5.3.9
@ -2015,7 +2015,7 @@ public class CollUtil {
}
/**
* 根据元素的指定字段分组非Bean都放在第一个分组中
* 根据元素的指定字段分组非Bean都放在第一个分组中
*
* @param <T> 元素类型
* @param collection 集合
@ -2026,7 +2026,19 @@ public class CollUtil {
return groupByFunc(collection, t -> BeanUtil.getFieldValue(t, fieldName));
}
public static <T,D> List<List<T>> groupByFunc(final Collection<T> collection, final Function<T,D> getter) {
/**
* 根据元素的指定字段值分组非Bean都放在第一个分组中<br>
* 例如{@code
* CollUtil.groupByFunc(list, TestBean::getAge)
* }
*
* @param <T> 元素类型
* @param collection 集合
* @param getter getter方法引用
* @return 分组列表
* @since 6.0.0
*/
public static <T> List<List<T>> groupByFunc(final Collection<T> collection, final Function<T, ?> getter) {
return group(collection, new Hash32<T>() {
private final List<Object> hashValList = new ArrayList<>();
@ -2036,14 +2048,13 @@ public class CollUtil {
// 非Bean放在同一子分组中
return 0;
}
final D value = getter.apply(t);
final int hash = hashValList.indexOf(value);
final Object value = getter.apply(t);
int hash = hashValList.indexOf(value);
if (hash < 0) {
hashValList.add(value);
return hashValList.size() - 1;
} else {
return hash;
hash = hashValList.size() - 1;
}
return hash;
}
});
}

View File

@ -2,12 +2,12 @@ package cn.hutool.core.date;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.NumberChineseFormatter;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.date.format.parser.DateParser;
import cn.hutool.core.date.format.parser.FastDateParser;
import cn.hutool.core.date.format.GlobalCustomFormat;
import cn.hutool.core.date.format.parser.PositionDateParser;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.text.StrUtil;
import cn.hutool.core.util.ObjUtil;
import javax.xml.datatype.XMLGregorianCalendar;
import java.text.ParsePosition;
@ -15,7 +15,6 @@ import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.TimeZone;
@ -74,7 +73,7 @@ public class CalendarUtil {
/**
* 转换为Calendar对象
*
* @param millis 时间戳
* @param millis 时间戳
* @param timeZone 时区
* @return Calendar对象
* @since 5.7.22
@ -105,6 +104,8 @@ public class CalendarUtil {
return Calendar.PM == calendar.get(Calendar.AM_PM);
}
// region ----- modify 时间修改
/**
* 修改日期为某个时间字段起始时间
*
@ -355,6 +356,7 @@ public class CalendarUtil {
public static Calendar endOfYear(final Calendar calendar) {
return ceiling(calendar, DateField.YEAR);
}
// endregion
/**
* 比较两个日期是否为同一天
@ -375,8 +377,8 @@ public class CalendarUtil {
/**
* 比较两个日期是否为同一周
*
* @param cal1 日期1
* @param cal2 日期2
* @param cal1 日期1
* @param cal2 日期2
* @param isMon 是否为周一国内第一天为星期一国外第一天为星期日
* @return 是否为同一周
* @since 5.7.21
@ -443,28 +445,6 @@ public class CalendarUtil {
return date1.getTimeInMillis() == date2.getTimeInMillis();
}
/**
* 获得指定日期区间内的年份和季度<br>
*
* @param startDate 起始日期包含
* @param endDate 结束日期包含
* @return 季度列表 元素类似于 20132
* @since 4.1.15
*/
public static LinkedHashSet<String> yearAndQuarter(long startDate, final long endDate) {
final LinkedHashSet<String> quarters = new LinkedHashSet<>();
final Calendar cal = calendar(startDate);
while (startDate <= endDate) {
// 如果开始时间超出结束时间让结束时间为开始时间处理完后结束循环
quarters.add(yearAndQuarter(cal));
cal.add(Calendar.MONTH, 3);
startDate = cal.getTimeInMillis();
}
return quarters;
}
/**
* 获得指定日期年份和季度<br>
* 格式[20131]表示2013年第一季度
@ -637,51 +617,7 @@ public class CalendarUtil {
return result.toString();
}
/**
* 计算相对于dateToCompare的年龄长用于计算指定生日在某年的年龄
*
* @param birthday 生日
* @param dateToCompare 需要对比的日期
* @return 年龄
*/
protected static int age(final long birthday, final long dateToCompare) {
if (birthday > dateToCompare) {
throw new IllegalArgumentException("Birthday is after dateToCompare!");
}
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(dateToCompare);
final int year = cal.get(Calendar.YEAR);
final int month = cal.get(Calendar.MONTH);
final int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
final boolean isLastDayOfMonth = dayOfMonth == cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.setTimeInMillis(birthday);
int age = year - cal.get(Calendar.YEAR);
//当前日期则为0岁
if (age == 0){
return 0;
}
final int monthBirth = cal.get(Calendar.MONTH);
if (month == monthBirth) {
final int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
final boolean isLastDayOfMonthBirth = dayOfMonthBirth == cal.getActualMaximum(Calendar.DAY_OF_MONTH);
// issue#I6E6ZG法定生日当天不算年龄从第二天开始计算
if ((false == isLastDayOfMonth || false == isLastDayOfMonthBirth) && dayOfMonth <= dayOfMonthBirth) {
// 如果生日在当月但是未达到生日当天的日期年龄减一
age--;
}
} else if (month < monthBirth) {
// 如果当前月份未达到生日的月份年龄计算减一
age--;
}
return age;
}
// region ----- parse
/**
* 通过给定的日期格式解析日期时间字符串<br>
* 传入的日期格式会逐个尝试直到解析成功返回{@link Calendar}对象否则抛出{@link DateException}异常
@ -782,4 +718,50 @@ public class CalendarUtil {
return parser.parse(StrUtil.str(str), new ParsePosition(0), calendar) ? calendar : null;
}
// endregion
/**
* 计算相对于dateToCompare的年龄长用于计算指定生日在某年的年龄
*
* @param birthday 生日
* @param dateToCompare 需要对比的日期
* @return 年龄
*/
protected static int age(final long birthday, final long dateToCompare) {
if (birthday > dateToCompare) {
throw new IllegalArgumentException("Birthday is after dateToCompare!");
}
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(dateToCompare);
final int year = cal.get(Calendar.YEAR);
final int month = cal.get(Calendar.MONTH);
final int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
final boolean isLastDayOfMonth = dayOfMonth == cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.setTimeInMillis(birthday);
int age = year - cal.get(Calendar.YEAR);
//当前日期则为0岁
if (age == 0) {
return 0;
}
final int monthBirth = cal.get(Calendar.MONTH);
if (month == monthBirth) {
final int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
final boolean isLastDayOfMonthBirth = dayOfMonthBirth == cal.getActualMaximum(Calendar.DAY_OF_MONTH);
// issue#I6E6ZG法定生日当天不算年龄从第二天开始计算
if ((false == isLastDayOfMonth || false == isLastDayOfMonthBirth) && dayOfMonth <= dayOfMonthBirth) {
// 如果生日在当月但是未达到生日当天的日期年龄减一
age--;
}
} else if (month < monthBirth) {
// 如果当前月份未达到生日的月份年龄计算减一
age--;
}
return age;
}
}

View File

@ -513,21 +513,7 @@ public class DateUtil extends CalendarUtil {
return yearAndQuarter(calendar(date));
}
/**
* 获得指定日期区间内的年份和季节<br>
*
* @param startDate 起始日期包含
* @param endDate 结束日期包含
* @return 季度列表 元素类似于 20132
*/
public static LinkedHashSet<String> yearAndQuarter(final Date startDate, final Date endDate) {
if (startDate == null || endDate == null) {
return new LinkedHashSet<>(0);
}
return yearAndQuarter(startDate.getTime(), endDate.getTime());
}
// ------------------------------------ Format start ----------------------------------------------
// region ----- format
/**
* 格式化日期时间<br>
* 格式 yyyy-MM-dd HH:mm:ss
@ -696,10 +682,9 @@ public class DateUtil extends CalendarUtil {
return CalendarUtil.formatChineseDate(CalendarUtil.calendar(date), withTime);
}
// ------------------------------------ Format end ----------------------------------------------
// ------------------------------------ Parse start ----------------------------------------------
// endregion
// region ----- parse
/**
* 构建DateTime对象
*
@ -853,10 +838,9 @@ public class DateUtil extends CalendarUtil {
// 没有更多匹配的时间格式
throw new DateException("No format fit for date String [{}] !", dateStr);
}
// ------------------------------------ Parse end ----------------------------------------------
// ------------------------------------ Offset start ----------------------------------------------
// endregion
// region ----- offset
/**
* 修改日期为某个时间字段起始时间
*
@ -1096,7 +1080,6 @@ public class DateUtil extends CalendarUtil {
public static DateTime endOfYear(final Date date) {
return new DateTime(endOfYear(calendar(date)));
}
// --------------------------------------------------- Offset for now
/**
* 昨天
@ -1243,9 +1226,9 @@ public class DateUtil extends CalendarUtil {
public static DateTime offset(final Date date, final DateField dateField, final int offset) {
return dateNew(date).offset(dateField, offset);
}
// endregion
// ------------------------------------ Offset end ----------------------------------------------
// region ----- between
/**
* 判断两个日期相差的时长只保留绝对值
*
@ -1351,7 +1334,9 @@ public class DateUtil extends CalendarUtil {
public static long betweenYear(final Date beginDate, final Date endDate, final boolean isReset) {
return new DateBetween(beginDate, endDate).betweenYear(isReset);
}
// endregion
// region ----- formatBetween
/**
* 格式化日期间隔输出
*
@ -1397,6 +1382,7 @@ public class DateUtil extends CalendarUtil {
public static String formatBetween(final long betweenMs) {
return new BetweenFormatter(betweenMs, BetweenFormatter.Level.MILLISECOND).format();
}
// endregion
/**
* 当前日期是否在日期指定范围内<br>
@ -1992,7 +1978,7 @@ public class DateUtil extends CalendarUtil {
* @return 单位简写名称
* @since 5.7.16
*/
public static String getShotName(final TimeUnit unit) {
public static String getShortName(final TimeUnit unit) {
switch (unit) {
case NANOSECONDS:
return "ns";

View File

@ -352,7 +352,7 @@ public class StopWatch {
unit = TimeUnit.NANOSECONDS;
}
return StrUtil.format("StopWatch '{}': running time = {} {}",
this.id, getTotal(unit), DateUtil.getShotName(unit));
this.id, getTotal(unit), DateUtil.getShortName(unit));
}
/**
@ -382,7 +382,7 @@ public class StopWatch {
sb.append("No task info kept");
} else {
sb.append("---------------------------------------------").append(FileUtil.getLineSeparator());
sb.append(DateUtil.getShotName(unit)).append(" % Task name").append(FileUtil.getLineSeparator());
sb.append(DateUtil.getShortName(unit)).append(" % Task name").append(FileUtil.getLineSeparator());
sb.append("---------------------------------------------").append(FileUtil.getLineSeparator());
final NumberFormat nf = NumberFormat.getNumberInstance();