完善季度相关 API(pr#1324@Gitee)

This commit is contained in:
Looly 2025-03-31 10:04:32 +08:00
parent 6496cd20cf
commit 1b29100fb3
4 changed files with 70 additions and 104 deletions

View File

@ -2,7 +2,7 @@
# 🚀Changelog # 🚀Changelog
------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------
# 5.8.37(2025-03-24) # 5.8.37(2025-03-31)
### 🐣新特性 ### 🐣新特性
* 【json 】 ObjectMapper删除重复trimpr#3859@Github * 【json 】 ObjectMapper删除重复trimpr#3859@Github
@ -16,6 +16,7 @@
* 【core 】 改进`PropDesc`中去除Transient引用避免NoClassDefFoundErrorissue#3901@Github * 【core 】 改进`PropDesc`中去除Transient引用避免NoClassDefFoundErrorissue#3901@Github
* 【core 】 `StrUtil.isBlank`增加`\u200c`判断issue#3903@Github * 【core 】 `StrUtil.isBlank`增加`\u200c`判断issue#3903@Github
* 【core 】 优化`CombinationAnnotationElement`注解数组性能pr#1323@Gitee * 【core 】 优化`CombinationAnnotationElement`注解数组性能pr#1323@Gitee
* 【core 】 完善季度相关 APIpr#1324@Gitee
### 🐞Bug修复 ### 🐞Bug修复
* 【setting】 修复`SettingLoader`load未抛出异常导致配置文件无法正常遍历的问题pr#3868@Github * 【setting】 修复`SettingLoader`load未抛出异常导致配置文件无法正常遍历的问题pr#3868@Github

View File

@ -1,11 +1,11 @@
package cn.hutool.core.date; package cn.hutool.core.date;
import cn.hutool.core.lang.Assert;
import java.time.DateTimeException; import java.time.DateTimeException;
import java.time.MonthDay; import java.time.MonthDay;
import java.time.temporal.ChronoField; import java.time.temporal.ChronoField;
import cn.hutool.core.lang.Assert;
/** /**
* 季度枚举 * 季度枚举
* *
@ -41,6 +41,11 @@ public enum Quarter {
this.firstMonth = lastMonth - 2; this.firstMonth = lastMonth - 2;
} }
/**
* 获取季度值
*
* @return 季度值
*/
public int getValue() { public int getValue() {
return this.value; return this.value;
} }
@ -54,7 +59,7 @@ public enum Quarter {
* @see #Q4 * @see #Q4
* *
* @param intValue 季度int表示 * @param intValue 季度int表示
* @return {@link Quarter} * @return {@code Quarter}
*/ */
public static Quarter of(int intValue) { public static Quarter of(int intValue) {
switch (intValue) { switch (intValue) {
@ -116,20 +121,11 @@ public enum Quarter {
* @param quarters 所添加的季度数量 * @param quarters 所添加的季度数量
* @return 计算结果 * @return 计算结果
*/ */
public Quarter plus(long quarters) { public Quarter plus(int quarters) {
final int amount = (int) ((quarters % 4) + 4); final int amount = (quarters % 4) + 4;
return Quarter.values()[(ordinal() + amount) % 4]; return Quarter.values()[(ordinal() + amount) % 4];
} }
/**
* 减去指定数量的季度
* @param quarters 所减去的季度数量
* @return 计算结果
*/
public Quarter minus(long quarters) {
return plus(-(quarters % 4));
}
// computes end // computes end
// Getters // Getters

View File

@ -1,7 +1,5 @@
package cn.hutool.core.date; package cn.hutool.core.date;
import static java.time.temporal.ChronoField.YEAR;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.YearMonth; import java.time.YearMonth;
@ -10,21 +8,32 @@ import java.util.Calendar;
import java.util.Date; import java.util.Date;
import java.util.Objects; import java.util.Objects;
import static java.time.temporal.ChronoField.YEAR;
/** /**
* 表示年份与季度 * 表示年份与季度
* *
* @author ZhouXY * @author ZhouXY
* @since 5.8.37
*/ */
public final class YearQuarter implements Comparable<YearQuarter>, Serializable { public final class YearQuarter implements Comparable<YearQuarter>, Serializable {
private static final long serialVersionUID = 3804145964419489753L; private static final long serialVersionUID = 3804145964419489753L;
/** 年份 */ /**
* 年份
*/
private final int year; private final int year;
/** 季度 */ /**
* 季度
*/
private final Quarter quarter; private final Quarter quarter;
/** 季度开始日期 */ /**
* 季度开始日期
*/
private final LocalDate firstDate; private final LocalDate firstDate;
/** 季度结束日期 */ /**
* 季度结束日期
*/
private final LocalDate lastDate; private final LocalDate lastDate;
private YearQuarter(int year, Quarter quarter) { private YearQuarter(int year, Quarter quarter) {
@ -37,34 +46,34 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
// #region - StaticFactory // #region - StaticFactory
/** /**
* 根据指定年份与季度创建 {@link YearQuarter} 实例 * 根据指定年份与季度创建 {@code YearQuarter} 实例
* *
* @param year 年份 * @param year 年份
* @param quarter 季度 * @param quarter 季度
* @return {@link YearQuarter} 实例 * @return {@code YearQuarter} 实例
*/ */
public static YearQuarter of(int year, int quarter) { public static YearQuarter of(int year, int quarter) {
int yearValue = YEAR.checkValidIntValue(year); int yearValue = YEAR.checkValidIntValue(year);
int quarterValue = Quarter.checkValidIntValue(quarter); int quarterValue = Quarter.checkValidIntValue(quarter);
return new YearQuarter(yearValue, Quarter.of(quarterValue)); return new YearQuarter(yearValue, Objects.requireNonNull(Quarter.of(quarterValue)));
} }
/** /**
* 根据指定年份与季度创建 {@link YearQuarter} 实例 * 根据指定年份与季度创建 {@code YearQuarter} 实例
* *
* @param year 年份 * @param year 年份
* @param quarter 季度 * @param quarter 季度
* @return {@link YearQuarter} 实例 * @return {@code YearQuarter} 实例
*/ */
public static YearQuarter of(int year, Quarter quarter) { public static YearQuarter of(int year, Quarter quarter) {
return new YearQuarter(YEAR.checkValidIntValue(year), Objects.requireNonNull(quarter)); return new YearQuarter(YEAR.checkValidIntValue(year), Objects.requireNonNull(quarter));
} }
/** /**
* 根据指定日期判断日期所在的年份与季度创建 {@link YearQuarter} 实例 * 根据指定日期判断日期所在的年份与季度创建 {@code YearQuarter} 实例
* *
* @param date 日期 * @param date 日期
* @return {@link YearQuarter} 实例 * @return {@code YearQuarter} 实例
*/ */
public static YearQuarter of(LocalDate date) { public static YearQuarter of(LocalDate date) {
Objects.requireNonNull(date); Objects.requireNonNull(date);
@ -72,25 +81,23 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
} }
/** /**
* 根据指定日期判断日期所在的年份与季度创建 {@link YearQuarter} 实例 * 根据指定日期判断日期所在的年份与季度创建 {@code YearQuarter} 实例
* *
* @param date 日期 * @param date 日期
* @return {@link YearQuarter} 实例 * @return {@code YearQuarter} 实例
*/ */
public static YearQuarter of(Date date) { public static YearQuarter of(Date date) {
Objects.requireNonNull(date); Objects.requireNonNull(date);
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation") final int yearValue = YEAR.checkValidIntValue(date.getYear() + 1900L);
final int yearValue = YEAR.checkValidIntValue(date.getYear() + 1900L); @SuppressWarnings("deprecation") final int monthValue = date.getMonth() + 1;
@SuppressWarnings("deprecation")
final int monthValue = date.getMonth() + 1;
return new YearQuarter(yearValue, Quarter.fromMonth(monthValue)); return new YearQuarter(yearValue, Quarter.fromMonth(monthValue));
} }
/** /**
* 根据指定日期判断日期所在的年份与季度创建 {@link YearQuarter} 实例 * 根据指定日期判断日期所在的年份与季度创建 {@code YearQuarter} 实例
* *
* @param date 日期 * @param date 日期
* @return {@link YearQuarter} 实例 * @return {@code YearQuarter} 实例
*/ */
public static YearQuarter of(Calendar date) { public static YearQuarter of(Calendar date) {
Objects.requireNonNull(date); Objects.requireNonNull(date);
@ -100,10 +107,10 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
} }
/** /**
* 根据指定年月判断其所在的年份与季度创建 {@link YearQuarter} 实例 * 根据指定年月判断其所在的年份与季度创建 {@code YearQuarter} 实例
* *
* @param yearMonth 年月 * @param yearMonth 年月
* @return {@link YearQuarter} 实例 * @return {@code YearQuarter} 实例
*/ */
public static YearQuarter of(YearMonth yearMonth) { public static YearQuarter of(YearMonth yearMonth) {
Objects.requireNonNull(yearMonth); Objects.requireNonNull(yearMonth);
@ -126,6 +133,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 年份 * 年份
*
* @return 年份 * @return 年份
*/ */
public int getYear() { public int getYear() {
@ -134,6 +142,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 季度 * 季度
*
* @return 季度 * @return 季度
*/ */
public Quarter getQuarter() { public Quarter getQuarter() {
@ -142,6 +151,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 季度值 1 开始 * 季度值 1 开始
*
* @return 季度值 * @return 季度值
*/ */
public int getQuarterValue() { public int getQuarterValue() {
@ -150,6 +160,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 该季度第一个月 * 该季度第一个月
*
* @return {@link YearMonth} 对象 * @return {@link YearMonth} 对象
*/ */
public YearMonth firstYearMonth() { public YearMonth firstYearMonth() {
@ -158,6 +169,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 该季度第一个月 * 该季度第一个月
*
* @return {@link Month} 对象 * @return {@link Month} 对象
*/ */
public Month firstMonth() { public Month firstMonth() {
@ -166,6 +178,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 该季度的第一个月 * 该季度的第一个月
*
* @return 结果月份值从 1 开始1 表示 1月以此类推 * @return 结果月份值从 1 开始1 表示 1月以此类推
*/ */
public int firstMonthValue() { public int firstMonthValue() {
@ -174,6 +187,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 该季度的最后一个月 * 该季度的最后一个月
*
* @return {@link YearMonth} 对象 * @return {@link YearMonth} 对象
*/ */
public YearMonth lastYearMonth() { public YearMonth lastYearMonth() {
@ -182,6 +196,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 该季度的最后一个月 * 该季度的最后一个月
*
* @return {@link Month} 对象 * @return {@link Month} 对象
*/ */
public Month lastMonth() { public Month lastMonth() {
@ -190,6 +205,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 该季度的最后一个月 * 该季度的最后一个月
*
* @return 结果月份值从 1 开始1 表示 1月以此类推 * @return 结果月份值从 1 开始1 表示 1月以此类推
*/ */
public int lastMonthValue() { public int lastMonthValue() {
@ -198,6 +214,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 该季度的第一天 * 该季度的第一天
*
* @return {@link LocalDate} 对象 * @return {@link LocalDate} 对象
*/ */
public LocalDate firstDate() { public LocalDate firstDate() {
@ -206,6 +223,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 该季度的最后一天 * 该季度的最后一天
*
* @return {@link LocalDate} 对象 * @return {@link LocalDate} 对象
*/ */
public LocalDate lastDate() { public LocalDate lastDate() {
@ -218,6 +236,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 添加季度 * 添加季度
*
* @param quartersToAdd 要添加的季度数 * @param quartersToAdd 要添加的季度数
* @return 计算结果 * @return 计算结果
*/ */
@ -229,11 +248,12 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
long calcQuarters = quarterCount + quartersToAdd; // safe overflow long calcQuarters = quarterCount + quartersToAdd; // safe overflow
int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcQuarters, 4)); int newYear = YEAR.checkValidIntValue(Math.floorDiv(calcQuarters, 4));
int newQuarter = (int) Math.floorMod(calcQuarters, 4) + 1; int newQuarter = (int) Math.floorMod(calcQuarters, 4) + 1;
return new YearQuarter(newYear, Quarter.of(newQuarter)); return new YearQuarter(newYear, Objects.requireNonNull(Quarter.of(newQuarter)));
} }
/** /**
* 减去季度 * 减去季度
*
* @param quartersToMinus 要减去的季度数 * @param quartersToMinus 要减去的季度数
* @return 计算结果 * @return 计算结果
*/ */
@ -243,6 +263,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 下一个季度 * 下一个季度
*
* @return 结果 * @return 结果
*/ */
public YearQuarter nextQuarter() { public YearQuarter nextQuarter() {
@ -251,6 +272,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 上一个季度 * 上一个季度
*
* @return 结果 * @return 结果
*/ */
public YearQuarter lastQuarter() { public YearQuarter lastQuarter() {
@ -259,6 +281,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 添加年份 * 添加年份
*
* @param yearsToAdd 要添加的年份数 * @param yearsToAdd 要添加的年份数
* @return 计算结果 * @return 计算结果
*/ */
@ -272,6 +295,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 减去年份 * 减去年份
*
* @param yearsToMinus 要减去的年份数 * @param yearsToMinus 要减去的年份数
* @return 计算结果 * @return 计算结果
*/ */
@ -281,6 +305,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 下一年同季度 * 下一年同季度
*
* @return 计算结果 * @return 计算结果
*/ */
public YearQuarter nextYear() { public YearQuarter nextYear() {
@ -289,6 +314,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 上一年同季度 * 上一年同季度
*
* @return 计算结果 * @return 计算结果
*/ */
public YearQuarter lastYear() { public YearQuarter lastYear() {
@ -331,6 +357,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 判断是否在指定年份季度之前 * 判断是否在指定年份季度之前
*
* @param other 比较对象 * @param other 比较对象
* @return 结果 * @return 结果
*/ */
@ -340,6 +367,7 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
/** /**
* 判断是否在指定年份季度之后 * 判断是否在指定年份季度之后
*
* @param other 比较对象 * @param other 比较对象
* @return 结果 * @return 结果
*/ */
@ -352,9 +380,9 @@ public final class YearQuarter implements Comparable<YearQuarter>, Serializable
// #region - toString // #region - toString
/** /**
* 返回 {@link YearQuarter} 的字符串表示形式 "2024 Q3" * 返回 {@code YearQuarter} 的字符串表示形式 "2024 Q3"
* *
* @return {@link YearQuarter} 的字符串表示形式 * @return {@code YearQuarter} 的字符串表示形式
*/ */
@Override @Override
public String toString() { public String toString() {

View File

@ -1,13 +1,10 @@
package cn.hutool.core.date; package cn.hutool.core.date;
import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.time.MonthDay; import java.time.MonthDay;
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*;
public class QuarterTest { public class QuarterTest {
@ -209,60 +206,4 @@ public class QuarterTest {
assertEquals(Quarter.Q1, Quarter.Q4.plus(i)); assertEquals(Quarter.Q1, Quarter.Q4.plus(i));
} }
} }
@Test
void testMinusZeroAndNegativeNumber() {
for (int i = 0; i < 100; i += 4) {
assertEquals(Quarter.Q1, Quarter.Q1.minus(i));
assertEquals(Quarter.Q2, Quarter.Q2.minus(i));
assertEquals(Quarter.Q3, Quarter.Q3.minus(i));
assertEquals(Quarter.Q4, Quarter.Q4.minus(i));
}
for (int i = 1; i < 100 + 1; i += 4) {
assertEquals(Quarter.Q4, Quarter.Q1.minus(i));
assertEquals(Quarter.Q1, Quarter.Q2.minus(i));
assertEquals(Quarter.Q2, Quarter.Q3.minus(i));
assertEquals(Quarter.Q3, Quarter.Q4.minus(i));
}
for (int i = 2; i < 100 + 2; i += 4) {
assertEquals(Quarter.Q3, Quarter.Q1.minus(i));
assertEquals(Quarter.Q4, Quarter.Q2.minus(i));
assertEquals(Quarter.Q1, Quarter.Q3.minus(i));
assertEquals(Quarter.Q2, Quarter.Q4.minus(i));
}
for (int i = 3; i < 100 + 3; i += 4) {
assertEquals(Quarter.Q2, Quarter.Q1.minus(i));
assertEquals(Quarter.Q3, Quarter.Q2.minus(i));
assertEquals(Quarter.Q4, Quarter.Q3.minus(i));
assertEquals(Quarter.Q1, Quarter.Q4.minus(i));
}
}
@Test
void testMinusZeroAndPositiveRealNumbers() {
for (int i = 0; i > -100; i -= 4) {
assertEquals(Quarter.Q1, Quarter.Q1.minus(i));
assertEquals(Quarter.Q2, Quarter.Q2.minus(i));
assertEquals(Quarter.Q3, Quarter.Q3.minus(i));
assertEquals(Quarter.Q4, Quarter.Q4.minus(i));
}
for (int i = -1; i > -(100 + 1); i -= 4) {
assertEquals(Quarter.Q2, Quarter.Q1.minus(i));
assertEquals(Quarter.Q3, Quarter.Q2.minus(i));
assertEquals(Quarter.Q4, Quarter.Q3.minus(i));
assertEquals(Quarter.Q1, Quarter.Q4.minus(i));
}
for (int i = -2; i > -(100 + 2); i -= 4) {
assertEquals(Quarter.Q3, Quarter.Q1.minus(i));
assertEquals(Quarter.Q4, Quarter.Q2.minus(i));
assertEquals(Quarter.Q1, Quarter.Q3.minus(i));
assertEquals(Quarter.Q2, Quarter.Q4.minus(i));
}
for (int i = -3; i > -(100 + 3); i -= 4) {
assertEquals(Quarter.Q4, Quarter.Q1.minus(i));
assertEquals(Quarter.Q1, Quarter.Q2.minus(i));
assertEquals(Quarter.Q2, Quarter.Q3.minus(i));
assertEquals(Quarter.Q3, Quarter.Q4.minus(i));
}
}
} }