Looly 5 years ago
parent
commit
93d91699c1

+ 3 - 1
CHANGELOG.md

@@ -3,7 +3,7 @@
 
 -------------------------------------------------------------------------------------------------------------
 
-## 5.3.9 (2020-07-07)
+## 5.3.9 (2020-07-12)
 
 ### 新特性
 * 【core   】     DateUtil增加formatChineseDate(pr#932@Github)
@@ -11,6 +11,7 @@
 * 【core   】     增强StrUtil中空判断后返回数据性能(pr#949@Github)
 * 【core   】     deprecate掉millsecond,改为millisecond(issue#I1M9P8@Gitee)
 * 【core   】     增加LocalDateTimeUtil(issue#I1KUVC@Gitee)
+* 【core   】     Month增加getLastDay方法
 
 ### Bug修复
 * 【core   】     修复NumberUtil.partValue有余数问题(issue#I1KX66@Gitee)
@@ -22,6 +23,7 @@
 * 【extra  】     修复Ftp中ArrayList长度为负问题(pr#136@Github)
 * 【core   】     修复Dict中putAll大小写问题(issue#I1MU5B@Gitee)
 * 【core   】     修复POI中sax读取数字判断错误问题(issue#931@Github)
+* 【core   】     修复DateUtil.endOfQuarter错误问题(issue#I1NGZ7@Gitee)
 
 -------------------------------------------------------------------------------------------------------------
 ## 5.3.8 (2020-06-16)

+ 8 - 4
hutool-core/src/main/java/cn/hutool/core/date/CalendarUtil.java

@@ -237,11 +237,15 @@ public class CalendarUtil {
 	 * @return {@link Calendar}
 	 * @since 4.1.0
 	 */
+	@SuppressWarnings({"MagicConstant", "ConstantConditions"})
 	public static Calendar endOfQuarter(Calendar calendar) {
-		//noinspection MagicConstant
-		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);
+		final int year = calendar.get(Calendar.YEAR);
+		final int month = calendar.get(DateField.MONTH.getValue()) / 3 * 3 + 2;
+
+		final Calendar resultCal = Calendar.getInstance(calendar.getTimeZone());
+		resultCal.set(year, month, Month.of(month).getLastDay(DateUtil.isLeapYear(year)));
+
+		return endOfDay(resultCal);
 	}
 
 	/**

+ 23 - 15
hutool-core/src/main/java/cn/hutool/core/date/ChineseDate.java

@@ -16,7 +16,11 @@ import java.util.List;
  */
 public class ChineseDate {
 
-	private static final Date baseDate = DateUtil.parseDate("1900-01-31");
+//	private static final Date baseDate = DateUtil.parseDate("1900-01-31");
+	/**
+	 * 1900-01-31
+	 */
+	private static final long baseDate = -2206425943000L;
 
 	//农历年
 	private final int year;
@@ -28,6 +32,12 @@ public class ChineseDate {
 	private boolean leap;
 	private final String[] chineseNumber = {"一", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "十二"};
 	private final String[] chineseNumberName = {"正", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "腊"};
+	/**
+	 *农历表示:
+	 * 1.  表示当年有无闰年,有的话,为闰月的月份,没有的话,为0。
+	 * 2-4.为除了闰月外的正常月份是大月还是小月,1为30天,0为29天。
+	 * 5.  表示闰月是大月还是小月,仅当存在闰月的情况下有意义。
+	 */
 	private final long[] lunarInfo = new long[]{0x04bd8, 0x04ae0, 0x0a570,
 			0x054d5, 0x0d260, 0x0d950, 0x16554, 0x056a0, 0x09ad0, 0x055d2,
 			0x04ae0, 0x0a5b6, 0x0a4d0, 0x0d250, 0x1d255, 0x0b540, 0x0d6a0,
@@ -66,33 +76,30 @@ public class ChineseDate {
 	 * @param date 日期
 	 */
 	public ChineseDate(Date date) {
-		// -------------------- private --------------------
 		int yearCyl;
 		int monCyl;
 		int dayCyl;
-		int leapMonth;
 		// 求出和1900年1月31日相差的天数
-		int offset = (int) ((date.getTime() - baseDate.getTime()) / 86400000L);
+		int offset = (int) ((date.getTime() - baseDate) / DateUnit.DAY.getMillis());
 		monCyl = 14;
 		// 用offset减去每农历年的天数
 		// 计算当天是农历第几天
 		// i最终结果是农历的年份
 		// offset是当年的第几天
 		int iYear;
-		int daysOfYear = 0;
-		for (iYear = 1900; iYear < 2050 && offset > 0; iYear++) {
+		int daysOfYear;
+		for (iYear = 1900; iYear < 2050; iYear++) {
 			daysOfYear = yearDays(iYear);
+			if (offset < daysOfYear) {
+				break;
+			}
 			offset -= daysOfYear;
 			monCyl += 12;
 		}
-		if (offset < 0) {
-			offset += daysOfYear;
-			iYear--;
-			monCyl -= 12;
-		}
+
 		// 农历年份
 		year = iYear;
-		leapMonth = leapMonth(iYear); // 闰哪个月,1-12
+		int leapMonth = leapMonth(iYear); // 闰哪个月,1-12
 		leap = false;
 		// 用当年的天数offset,逐个减去每月(农历)的天数,求出当天是本月的第几天
 		int iMonth, daysOfMonth = 0;
@@ -270,7 +277,7 @@ public class ChineseDate {
 	 * @return 标准的日期格式
 	 * @since 5.2.4
 	 */
-	public String toStringNormal(){
+	public String toStringNormal() {
 		return String.format("%04d-%02d-%02d", this.year, this.month, this.day);
 	}
 
@@ -314,8 +321,9 @@ public class ChineseDate {
 	private int leapDays(int y) {
 		if (leapMonth(y) != 0) {
 			return (lunarInfo[y - 1900] & 0x10000) != 0 ? 30 : 29;
-		} else
-			return 0;
+		}
+
+		return 0;
 	}
 
 

+ 73 - 22
hutool-core/src/main/java/cn/hutool/core/date/Month.java

@@ -5,7 +5,8 @@ import java.util.Calendar;
 /**
  * 月份枚举<br>
  * 与Calendar中的月份int值对应
- * 
+ *
+ * @author Looly
  * @see Calendar#JANUARY
  * @see Calendar#FEBRUARY
  * @see Calendar#MARCH
@@ -19,53 +20,106 @@ import java.util.Calendar;
  * @see Calendar#NOVEMBER
  * @see Calendar#DECEMBER
  * @see Calendar#UNDECIMBER
- * 
- * @author Looly
- *
  */
 public enum Month {
-
-	/** 一月 */
+	/**
+	 * 一月
+	 */
 	JANUARY(Calendar.JANUARY),
-	/** 二月 */
+	/**
+	 * 二月
+	 */
 	FEBRUARY(Calendar.FEBRUARY),
-	/** 三月 */
+	/**
+	 * 三月
+	 */
 	MARCH(Calendar.MARCH),
-	/** 四月 */
+	/**
+	 * 四月
+	 */
 	APRIL(Calendar.APRIL),
-	/** 五月 */
+	/**
+	 * 五月
+	 */
 	MAY(Calendar.MAY),
-	/** 六月 */
+	/**
+	 * 六月
+	 */
 	JUNE(Calendar.JUNE),
-	/** 七月 */
+	/**
+	 * 七月
+	 */
 	JULY(Calendar.JULY),
-	/** 八月 */
+	/**
+	 * 八月
+	 */
 	AUGUST(Calendar.AUGUST),
-	/** 九月 */
+	/**
+	 * 九月
+	 */
 	SEPTEMBER(Calendar.SEPTEMBER),
-	/** 十月 */
+	/**
+	 * 十月
+	 */
 	OCTOBER(Calendar.OCTOBER),
-	/** 十一月 */
+	/**
+	 * 十一月
+	 */
 	NOVEMBER(Calendar.NOVEMBER),
-	/** 十二月 */
+	/**
+	 * 十二月
+	 */
 	DECEMBER(Calendar.DECEMBER),
-	/** 十三月,仅用于农历 */
+	/**
+	 * 十三月,仅用于农历
+	 */
 	UNDECIMBER(Calendar.UNDECIMBER);
 
 	// ---------------------------------------------------------------
+	private static final int[] DAYS_OF_MONTH = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, -1};
+
+	/**
+	 * 对应值,见{@link Calendar}
+	 */
 	private final int value;
 
+	/**
+	 * 构造
+	 *
+	 * @param value 对应值,见{@link Calendar}
+	 */
 	Month(int value) {
 		this.value = value;
 	}
 
+	/**
+	 * 获取{@link Calendar}中的对应值
+	 *
+	 * @return {@link Calendar}中的对应值
+	 */
 	public int getValue() {
 		return this.value;
 	}
 
 	/**
+	 * 获取此月份最后一天的值,不支持的月份(例如UNDECIMBER)返回-1
+	 *
+	 * @param isLeapYear 是否闰年
+	 * @return 此月份最后一天的值
+	 */
+	public int getLastDay(boolean isLeapYear) {
+		int lastDay = DAYS_OF_MONTH[value];
+		if (isLeapYear && Calendar.FEBRUARY == value){
+			lastDay += 1;
+		}
+		return lastDay;
+	}
+
+	/**
 	 * 将 {@link Calendar}月份相关值转换为Month枚举对象<br>
-	 * 
+	 *
+	 * @param calendarMonthIntValue Calendar中关于Month的int值
+	 * @return {@link Month}
 	 * @see Calendar#JANUARY
 	 * @see Calendar#FEBRUARY
 	 * @see Calendar#MARCH
@@ -79,9 +133,6 @@ public enum Month {
 	 * @see Calendar#NOVEMBER
 	 * @see Calendar#DECEMBER
 	 * @see Calendar#UNDECIMBER
-	 * 
-	 * @param calendarMonthIntValue Calendar中关于Month的int值
-	 * @return {@link Month}
 	 */
 	public static Month of(int calendarMonthIntValue) {
 		switch (calendarMonthIntValue) {

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

@@ -36,4 +36,13 @@ public class ChineseDateTest {
 		ChineseDate date = new ChineseDate(DateUtil.parseDate("2020-03-1"));
 		Assert.assertEquals("2020-02-08", date.toStringNormal());
 	}
+
+	@Test
+	public void parseTest(){
+		ChineseDate date = new ChineseDate(DateUtil.parseDate("1996-07-14"));
+		Assert.assertEquals("丙子鼠年 五月廿九", date.toString());
+
+		date = new ChineseDate(DateUtil.parseDate("1996-07-15"));
+		Assert.assertEquals("丙子鼠年 五月三十", date.toString());
+	}
 }

+ 15 - 1
hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java

@@ -73,7 +73,7 @@ public class DateUtilTest {
 
 	@Test
 	public void beginAndEndTest() {
-		String dateStr = "2017-03-01 22:33:23";
+		String dateStr = "2017-03-01 00:33:23";
 		Date date = DateUtil.parse(dateStr);
 
 		// 一天的开始
@@ -85,6 +85,12 @@ public class DateUtilTest {
 	}
 
 	@Test
+	public void endOfDayTest() {
+		final DateTime parse = DateUtil.parse("2020-05-31 00:00:00");
+		Assert.assertEquals("2020-05-31 23:59:59", DateUtil.endOfDay(parse).toString());
+	}
+
+	@Test
 	public void truncateTest(){
 		String dateStr2 = "2020-02-29 12:59:34";
 		Date date2 = DateUtil.parse(dateStr2);
@@ -588,6 +594,14 @@ public class DateUtilTest {
 	}
 
 	@Test
+	public void endOfQuarterTest() {
+		Date date = DateUtil.endOfQuarter(
+				DateUtil.parse("2020-05-31 00:00:00"));
+
+		Assert.assertEquals("2020-06-30 23:59:59", DateUtil.format(date,"yyyy-MM-dd HH:mm:ss"));
+	}
+
+	@Test
 	public void endOfWeekTest() {
 		// 周日
 		DateTime now = DateUtil.parse("2019-09-15 13:00");

+ 40 - 0
hutool-core/src/test/java/cn/hutool/core/date/MonthTest.java

@@ -0,0 +1,40 @@
+package cn.hutool.core.date;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Calendar;
+
+public class MonthTest {
+
+	@SuppressWarnings("ConstantConditions")
+	@Test
+	public void getLastDayTest(){
+		int lastDay = Month.of(Calendar.JANUARY).getLastDay(false);
+		Assert.assertEquals(31, lastDay);
+		lastDay = Month.of(Calendar.FEBRUARY).getLastDay(false);
+		Assert.assertEquals(28, lastDay);
+		lastDay = Month.of(Calendar.FEBRUARY).getLastDay(true);
+		Assert.assertEquals(29, lastDay);
+		lastDay = Month.of(Calendar.MARCH).getLastDay(true);
+		Assert.assertEquals(31, lastDay);
+		lastDay = Month.of(Calendar.APRIL).getLastDay(true);
+		Assert.assertEquals(30, lastDay);
+		lastDay = Month.of(Calendar.MAY).getLastDay(true);
+		Assert.assertEquals(31, lastDay);
+		lastDay = Month.of(Calendar.JUNE).getLastDay(true);
+		Assert.assertEquals(30, lastDay);
+		lastDay = Month.of(Calendar.JULY).getLastDay(true);
+		Assert.assertEquals(31, lastDay);
+		lastDay = Month.of(Calendar.AUGUST).getLastDay(true);
+		Assert.assertEquals(31, lastDay);
+		lastDay = Month.of(Calendar.SEPTEMBER).getLastDay(true);
+		Assert.assertEquals(30, lastDay);
+		lastDay = Month.of(Calendar.OCTOBER).getLastDay(true);
+		Assert.assertEquals(31, lastDay);
+		lastDay = Month.of(Calendar.NOVEMBER).getLastDay(true);
+		Assert.assertEquals(30, lastDay);
+		lastDay = Month.of(Calendar.DECEMBER).getLastDay(true);
+		Assert.assertEquals(31, lastDay);
+	}
+}