Browse Source

add method

Looly 5 years ago
parent
commit
d5192d8f61

+ 2 - 0
CHANGELOG.md

@@ -22,6 +22,7 @@
 * 【core   】     Assert增加函数接口(pr#1166@Github)
 * 【core   】     新增AtomicIntegerArray、AtomicLongArray转换
 * 【extra  】     PinyinUtil新增Bopomofo4j支持
+* 【core   】     新增TemporalUtil工具类,新增时间相关方法
 
 ### Bug修复
 * 【core   】     解决农历判断节日未判断大小月导致的问题(issue#I1XHSF@Gitee)
@@ -30,6 +31,7 @@
 * 【core   】     修复CaseInsensitiveMap的remove等方法并没有忽略大小写的问题(pr#1163@Gitee)
 * 【poi    】     修复合并单元格值读取错误的问题
 * 【poi    】     修复NamedSql解析形如col::numeric出错问题(issue#I1YHBX@Gitee)
+* 【core   】     修复计算相差天数导致的问题
 
 -------------------------------------------------------------------------------------------------------------
 

+ 6 - 5
hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java

@@ -21,7 +21,9 @@ public class ChineseDate {
 	/**
 	 * 1900-01-31
 	 */
-	private static final long BASE_DATE = -2206425943000L;
+//	private static final long BASE_DATE = -2206425943000L;
+	private static final long BASE_DAY = -25538;
+
 	//农历年
 	private final int year;
 	//农历月
@@ -46,13 +48,12 @@ public class ChineseDate {
 	 */
 	public ChineseDate(Date date) {
 		// 求出和1900年1月31日相差的天数
-		int offset = (int) ((date.getTime() - BASE_DATE) / DateUnit.DAY.getMillis());
+		int offset = (int) ((date.getTime() / DateUnit.DAY.getMillis()) - BASE_DAY);
 		// 计算农历年份
 		// 用offset减去每农历年的天数,计算当天是农历第几天,offset是当年的第几天
 		int daysOfYear;
 		int iYear = LunarInfo.BASE_YEAR;
-		final int maxYear = LunarInfo.getMaxYear();
-		for (; iYear <= maxYear; iYear++) {
+		for (; iYear <= LunarInfo.MAX_YEAR; iYear++) {
 			daysOfYear = LunarInfo.yearDays(iYear);
 			if (offset < daysOfYear) {
 				break;
@@ -299,7 +300,7 @@ public class ChineseDate {
 		if (D >= firstNode) {
 			gzM = GanZhi.cyclicalm((Y - LunarInfo.BASE_YEAR) * 12 + M + 12);
 		}
-		int dayCyclical = (int) ((DateUtil.parseDate(Y + "-" + M + "-" + "1").getTime() - BASE_DATE + 2592000000L) / DateUnit.DAY.getMillis()) + 10;
+		int dayCyclical = (int) ((DateUtil.parseDate(Y + "-" + M + "-" + "1").getTime() / DateUnit.DAY.getMillis() - BASE_DAY + 30)) + 10;
 		String gzD = GanZhi.cyclicalm(dayCyclical + D - 1);
 		return gzyear + "年" + gzM + "月" + gzD + "日";
 	}

+ 2 - 2
hutool-core/src/main/java/cn/hutool/core/date/DateBetween.java

@@ -26,7 +26,7 @@ public class DateBetween implements Serializable{
 	 * 
 	 * @param begin 起始时间
 	 * @param end 结束时间
-	 * @return {@link DateBetween}
+	 * @return DateBetween
 	 * @since 3.2.3
 	 */
 	public static DateBetween create(Date begin, Date end) {
@@ -40,7 +40,7 @@ public class DateBetween implements Serializable{
 	 * @param begin 起始时间
 	 * @param end 结束时间
 	 * @param isAbs 日期间隔是否只保留绝对值正数
-	 * @return {@link DateBetween}
+	 * @return DateBetween
 	 * @since 3.2.3
 	 */
 	public static DateBetween create(Date begin, Date end, boolean isAbs) {

+ 88 - 13
hutool-core/src/main/java/cn/hutool/core/date/DateUnit.java

@@ -1,33 +1,108 @@
 package cn.hutool.core.date;
 
+import java.time.temporal.ChronoUnit;
+
 /**
  * 日期时间单位,每个单位都是以毫秒为基数
- * @author Looly
  *
+ * @author Looly
  */
 public enum DateUnit {
-	/** 一毫秒 */
-	MS(1), 
-	/** 一秒的毫秒数 */
-	SECOND(1000), 
-	/**一分钟的毫秒数 */
+	/**
+	 * 一毫秒
+	 */
+	MS(1),
+	/**
+	 * 一秒的毫秒数
+	 */
+	SECOND(1000),
+	/**
+	 * 一分钟的毫秒数
+	 */
 	MINUTE(SECOND.getMillis() * 60),
-	/**一小时的毫秒数 */
+	/**
+	 * 一小时的毫秒数
+	 */
 	HOUR(MINUTE.getMillis() * 60),
-	/**一天的毫秒数 */
+	/**
+	 * 一天的毫秒数
+	 */
 	DAY(HOUR.getMillis() * 24),
-	/**一周的毫秒数 */
+	/**
+	 * 一周的毫秒数
+	 */
 	WEEK(DAY.getMillis() * 7);
-	
+
 	private final long millis;
-	DateUnit(long millis){
+
+	DateUnit(long millis) {
 		this.millis = millis;
 	}
-	
+
 	/**
 	 * @return 单位对应的毫秒数
 	 */
-	public long getMillis(){
+	public long getMillis() {
 		return this.millis;
 	}
+
+	/**
+	 * 单位兼容转换,将DateUnit转换为对应的{@link ChronoUnit}
+	 *
+	 * @return {@link ChronoUnit}
+	 * @since 5.4.5
+	 */
+	public ChronoUnit toChronoUnit() {
+		return DateUnit.toChronoUnit(this);
+	}
+
+	/**
+	 * 单位兼容转换,将{@link ChronoUnit}转换为对应的DateUnit
+	 *
+	 * @param unit {@link ChronoUnit}
+	 * @return DateUnit,null表示不支持此单位
+	 * @since 5.4.5
+	 */
+	public static DateUnit of(ChronoUnit unit) {
+		switch (unit) {
+			case MICROS:
+				return DateUnit.MS;
+			case SECONDS:
+				return DateUnit.SECOND;
+			case MINUTES:
+				return DateUnit.MINUTE;
+			case HOURS:
+				return DateUnit.HOUR;
+			case DAYS:
+				return DateUnit.DAY;
+			case WEEKS:
+				return DateUnit.WEEK;
+		}
+		return null;
+	}
+
+	/**
+	 * 单位兼容转换,将DateUnit转换为对应的{@link ChronoUnit}
+	 *
+	 * @param unit DateUnit
+	 * @return {@link ChronoUnit}
+	 * @since 5.4.5
+	 */
+	public static ChronoUnit toChronoUnit(DateUnit unit) {
+		switch (unit) {
+			case MS:
+				return ChronoUnit.MICROS;
+			case SECOND:
+				return ChronoUnit.SECONDS;
+			case MINUTE:
+				return ChronoUnit.MINUTES;
+			case HOUR:
+				return ChronoUnit.HOURS;
+			case DAY:
+				return ChronoUnit.DAYS;
+			case WEEK:
+				return ChronoUnit.WEEKS;
+		}
+		return null;
+	}
 }

+ 36 - 4
hutool-core/src/main/java/cn/hutool/core/date/LocalDateTimeUtil.java

@@ -9,11 +9,14 @@ import java.time.Instant;
 import java.time.LocalDate;
 import java.time.LocalDateTime;
 import java.time.LocalTime;
+import java.time.Period;
 import java.time.ZoneId;
 import java.time.ZonedDateTime;
 import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeFormatterBuilder;
 import java.time.temporal.ChronoField;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
 import java.time.temporal.TemporalAccessor;
 import java.time.temporal.TemporalUnit;
 import java.util.Date;
@@ -412,14 +415,43 @@ public class LocalDateTimeUtil {
 	 * <p>
 	 * 返回结果为{@link Duration}对象,通过调用toXXX方法返回相差单位
 	 *
-	 * @param startTime 开始时间
-	 * @param endTime   结束时间
+	 * @param startTimeInclude 开始时间(包含)
+	 * @param endTimeExclude   结束时间(不包含)
 	 * @return 时间差 {@link Duration}对象
+	 * @see TemporalUtil#between(Temporal, Temporal)
 	 */
-	public static Duration between(LocalDateTime startTime, LocalDateTime endTime) {
-		return Duration.between(startTime, endTime);
+	public static Duration between(LocalDateTime startTimeInclude, LocalDateTime endTimeExclude) {
+		return TemporalUtil.between(startTimeInclude, endTimeExclude);
 	}
 
+	/**
+	 * 获取两个日期的差,如果结束时间早于开始时间,获取结果为负。
+	 * <p>
+	 * 返回结果为时间差的long值
+	 *
+	 * @param startTimeInclude 开始时间(包括)
+	 * @param endTimeExclude   结束时间(不包括)
+	 * @param unit             时间差单位
+	 * @return 时间差
+	 * @since 5.4.5
+	 */
+	public static long between(LocalDateTime startTimeInclude, LocalDateTime endTimeExclude, ChronoUnit unit) {
+		return TemporalUtil.between(startTimeInclude, endTimeExclude, unit);
+	}
+
+	/**
+	 * 获取两个日期的表象时间差,如果结束时间早于开始时间,获取结果为负。
+	 * <p>
+	 * 比如2011年2月1日,和2021年8月11日,日相差了10天,月相差6月
+	 *
+	 * @param startTimeInclude 开始时间(包括)
+	 * @param endTimeExclude   结束时间(不包括)
+	 * @return 时间差
+	 * @since 5.4.5
+	 */
+	public static Period betweenPeriod(LocalDate startTimeInclude, LocalDate endTimeExclude) {
+		return Period.between(startTimeInclude, endTimeExclude);
+	}
 
 	/**
 	 * 修改为一天的开始时间,例如:2020-02-02 00:00:00,000

+ 1 - 1
hutool-core/src/main/java/cn/hutool/core/date/TemporalAccessorUtil.java

@@ -20,7 +20,7 @@ import java.time.temporal.TemporalField;
  * @author looly
  * @since 5.3.9
  */
-public class TemporalAccessorUtil {
+public class TemporalAccessorUtil extends TemporalUtil{
 
 	/**
 	 * 安全获取时间的某个属性,属性不存在返回0

+ 41 - 0
hutool-core/src/main/java/cn/hutool/core/date/TemporalUtil.java

@@ -0,0 +1,41 @@
+package cn.hutool.core.date;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
+
+/**
+ * {@link Temporal} 工具类封装
+ *
+ * @author looly
+ * @since 5.4.5
+ */
+public class TemporalUtil {
+
+	/**
+	 * 获取两个日期的差,如果结束时间早于开始时间,获取结果为负。
+	 * <p>
+	 * 返回结果为{@link Duration}对象,通过调用toXXX方法返回相差单位
+	 *
+	 * @param startTimeInclude 开始时间(包含)
+	 * @param endTimeExclude   结束时间(不包含)
+	 * @return 时间差 {@link Duration}对象
+	 */
+	public static Duration between(Temporal startTimeInclude, Temporal endTimeExclude) {
+		return Duration.between(startTimeInclude, endTimeExclude);
+	}
+
+	/**
+	 * 获取两个日期的差,如果结束时间早于开始时间,获取结果为负。
+	 * <p>
+	 * 返回结果为时间差的long值
+	 *
+	 * @param startTimeInclude 开始时间(包括)
+	 * @param endTimeExclude   结束时间(不包括)
+	 * @param unit             时间差单位
+	 * @return 时间差
+	 */
+	public static long between(Temporal startTimeInclude, Temporal endTimeExclude, ChronoUnit unit) {
+		return unit.between(startTimeInclude, endTimeExclude);
+	}
+}

+ 6 - 1
hutool-core/src/main/java/cn/hutool/core/date/chinese/LunarInfo.java

@@ -40,13 +40,18 @@ public class LunarInfo {
 			0x0e968, 0x0d520, 0x0daa0, 0x16aa6, 0x056d0, 0x04ae0, 0x0a9d4, 0x0a2d0, 0x0d150, 0x0f252,//2090-2099
 	};
 
+	// 支持的最大年限
+	public static final int MAX_YEAR = BASE_YEAR + LUNAR_CODE.length - 1;
+
 	/**
 	 * 获取支持的最大年(包括)
 	 *
 	 * @return 最大年(包括)
+	 * @deprecated 使用 {@link #MAX_YEAR}
 	 */
+	@Deprecated
 	public static int getMaxYear() {
-		return BASE_YEAR + LUNAR_CODE.length - 1;
+		return MAX_YEAR;
 	}
 
 	/**

+ 10 - 0
hutool-core/src/test/java/cn/hutool/core/date/ChineseDateTest.java

@@ -85,4 +85,14 @@ public class ChineseDateTest {
 		ChineseDate chineseDate = new ChineseDate(DateUtil.parseDate("2023-01-20"));
 		Assert.assertTrue(StrUtil.isEmpty(chineseDate.getFestivals()));
 	}
+
+	@Test
+	public void dateTest(){
+		// 修复这两个日期不正确的问题
+		// 问题出在计算与1900-01-31相差天数的问题上了,相差天数非整天
+		ChineseDate date = new ChineseDate(DateUtil.parseDate("1991-09-14"));
+		Assert.assertEquals("辛未羊年 八月初七", date.toString());
+		date = new ChineseDate(DateUtil.parseDate("1991-09-15"));
+		Assert.assertEquals("辛未羊年 八月初八", date.toString());
+	}
 }