diff --git a/src/main/java/xyz/zhouxy/plusone/commons/base/Quarter.java b/src/main/java/xyz/zhouxy/plusone/commons/time/Quarter.java similarity index 79% rename from src/main/java/xyz/zhouxy/plusone/commons/base/Quarter.java rename to src/main/java/xyz/zhouxy/plusone/commons/time/Quarter.java index 4f7c2ed..7e9fb14 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/base/Quarter.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/time/Quarter.java @@ -1,4 +1,4 @@ -package xyz.zhouxy.plusone.commons.base; +package xyz.zhouxy.plusone.commons.time; import java.time.Month; import java.time.MonthDay; @@ -27,14 +27,10 @@ public enum Quarter { private final int value; /** 季度开始月份 */ - private final Month firstMonth; - /** 季度开始日期 */ - private final MonthDay firstMonthDay; + private final int firstMonth; /** 季度结束月份 */ - private final Month lastMonth; - /** 季度结束日期 */ - private final MonthDay lastMonthDay; + private final int lastMonth; /** 常量值 */ private static final Quarter[] ENUMS = Quarter.values(); @@ -45,14 +41,8 @@ public enum Quarter { Quarter(int value) { this.value = value; - final int lastMonthValue = value * 3; - final int firstMonthValue = lastMonthValue - 2; - - this.firstMonth = Month.of(firstMonthValue); - this.firstMonthDay = MonthDay.of(this.firstMonth, 1); - this.lastMonth = Month.of(lastMonthValue); - // 季度的最后一个月不可能是 2 月 - this.lastMonthDay = MonthDay.of(this.lastMonth, this.lastMonth.maxLength()); + this.lastMonth = value * 3; + this.firstMonth = this.lastMonth - 2; } /** @@ -110,31 +100,33 @@ public enum Quarter { } public Month firstMonth() { - return firstMonth; + return Month.of(firstMonth); } public int firstMonthValue() { - return firstMonth.getValue(); + return firstMonth; } public Month lastMonth() { - return lastMonth; + return Month.of(lastMonth); } public int lastMonthValue() { - return lastMonth.getValue(); + return lastMonth; } public MonthDay firstMonthDay() { - return firstMonthDay; + return MonthDay.of(this.firstMonth, 1); } public MonthDay lastMonthDay() { - return lastMonthDay; + // 季度的最后一个月不可能是 2 月 + final Month month = lastMonth(); + return MonthDay.of(month, month.maxLength()); } public int firstDayOfYear(boolean leapYear) { - return this.firstMonth.firstDayOfYear(leapYear); + return Month.of(this.firstMonth).firstDayOfYear(leapYear); } // Getters end diff --git a/src/main/java/xyz/zhouxy/plusone/commons/base/YearQuarter.java b/src/main/java/xyz/zhouxy/plusone/commons/time/YearQuarter.java similarity index 99% rename from src/main/java/xyz/zhouxy/plusone/commons/base/YearQuarter.java rename to src/main/java/xyz/zhouxy/plusone/commons/time/YearQuarter.java index e0b0bf5..ac3946d 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/base/YearQuarter.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/time/YearQuarter.java @@ -1,4 +1,4 @@ -package xyz.zhouxy.plusone.commons.base; +package xyz.zhouxy.plusone.commons.time; import java.io.Serializable; import java.time.LocalDate; diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/DateTimeTools.java b/src/main/java/xyz/zhouxy/plusone/commons/util/DateTimeTools.java index d72dc83..e11c97f 100644 --- a/src/main/java/xyz/zhouxy/plusone/commons/util/DateTimeTools.java +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/DateTimeTools.java @@ -18,8 +18,8 @@ import org.apache.commons.lang3.StringUtils; import com.google.common.base.Preconditions; import xyz.zhouxy.plusone.commons.collection.SafeConcurrentHashMap; -import xyz.zhouxy.plusone.commons.base.Quarter; -import xyz.zhouxy.plusone.commons.base.YearQuarter; +import xyz.zhouxy.plusone.commons.time.Quarter; +import xyz.zhouxy.plusone.commons.time.YearQuarter; import xyz.zhouxy.plusone.commons.collection.MapWrapper; /** diff --git a/src/test/java/xyz/zhouxy/plusone/commons/base/YearQuarterTests.java b/src/test/java/xyz/zhouxy/plusone/commons/base/YearQuarterTests.java deleted file mode 100644 index c6d66c3..0000000 --- a/src/test/java/xyz/zhouxy/plusone/commons/base/YearQuarterTests.java +++ /dev/null @@ -1,55 +0,0 @@ -package xyz.zhouxy.plusone.commons.base; - -import org.junit.jupiter.api.Test; - -import lombok.extern.slf4j.Slf4j; - -import java.time.LocalDate; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -@Slf4j -public class YearQuarterTests { - - @Test - void of_ValidYearAndQuarter_CreatesYearQuarter() { - int year = 2023; - Quarter quarter = Quarter.Q1; - - YearQuarter expected = YearQuarter.of(year, quarter); - YearQuarter actual = YearQuarter.of(LocalDate.of(year, 2, 28)); - - assertEquals(expected, actual); - - assertEquals("Q1 2023", actual.toString()); - } - - @Test - @SuppressWarnings("null") - void of_InvalidQuarter_ThrowsNullPointerException() { - int year = 2023; - Quarter quarter = null; - - assertThrows(NullPointerException.class, () -> YearQuarter.of(year, quarter)); - } - - @Test - void of_ValidYearQuarter_GetsCorrectStartAndEndDate() { - - for (int year = 1990; year <= 2024; year++) { - for (int qrtr = 1; qrtr <= 4; qrtr++) { - Quarter quarter = Quarter.of(qrtr); - YearQuarter yearQuarter = YearQuarter.of(year, quarter); - - LocalDate expectedStartDate = quarter.firstMonthDay().atYear(year); - log.info("{} - expectedStartDate: {}", yearQuarter, expectedStartDate); - LocalDate expectedEndDate = quarter.lastMonthDay().atYear(year); - log.info("{} - expectedEndDate: {}", yearQuarter, expectedEndDate); - - assertEquals(expectedStartDate, yearQuarter.firstDate()); - assertEquals(expectedEndDate, yearQuarter.lastDate()); - } - } - } -} diff --git a/src/test/java/xyz/zhouxy/plusone/commons/base/QuarterTests.java b/src/test/java/xyz/zhouxy/plusone/commons/time/QuarterTests.java similarity index 55% rename from src/test/java/xyz/zhouxy/plusone/commons/base/QuarterTests.java rename to src/test/java/xyz/zhouxy/plusone/commons/time/QuarterTests.java index 35b2d67..8620776 100644 --- a/src/test/java/xyz/zhouxy/plusone/commons/base/QuarterTests.java +++ b/src/test/java/xyz/zhouxy/plusone/commons/time/QuarterTests.java @@ -1,4 +1,4 @@ -package xyz.zhouxy.plusone.commons.base; +package xyz.zhouxy.plusone.commons.time; import static org.junit.jupiter.api.Assertions.*; @@ -27,15 +27,15 @@ class QuarterTests { // ========== - int startMonthValue = quarter.firstMonthValue(); - log.info("startMonthValue: {}", startMonthValue); - assertEquals(1, startMonthValue); + int firstMonthValue = quarter.firstMonthValue(); + log.info("firstMonthValue: {}", firstMonthValue); + assertEquals(1, firstMonthValue); - Month startMonth = quarter.firstMonth(); - log.info("startMonth: {}", startMonth); - assertEquals(Month.JANUARY, startMonth); + Month firstMonth = quarter.firstMonth(); + log.info("firstMonth: {}", firstMonth); + assertEquals(Month.JANUARY, firstMonth); - assertEquals(startMonthValue, startMonth.getValue()); + assertEquals(firstMonthValue, firstMonth.getValue()); // ========== @@ -51,9 +51,9 @@ class QuarterTests { // ========== - MonthDay startMonthDay = quarter.firstMonthDay(); - log.info("startMonthDay: {}", startMonthDay); - assertEquals(startMonthDay, MonthDay.of(1, 1)); + MonthDay firstMonthDay = quarter.firstMonthDay(); + log.info("firstMonthDay: {}", firstMonthDay); + assertEquals(firstMonthDay, MonthDay.of(1, 1)); MonthDay lastMonthDay = quarter.lastMonthDay(); log.info("lastMonthDay: {}", lastMonthDay); @@ -74,15 +74,15 @@ class QuarterTests { // ========== - int startMonthValue = quarter.firstMonthValue(); - log.info("startMonthValue: {}", startMonthValue); - assertEquals(4, startMonthValue); + int firstMonthValue = quarter.firstMonthValue(); + log.info("firstMonthValue: {}", firstMonthValue); + assertEquals(4, firstMonthValue); - Month startMonth = quarter.firstMonth(); - log.info("startMonth: {}", startMonth); - assertEquals(Month.APRIL, startMonth); + Month firstMonth = quarter.firstMonth(); + log.info("firstMonth: {}", firstMonth); + assertEquals(Month.APRIL, firstMonth); - assertEquals(startMonthValue, startMonth.getValue()); + assertEquals(firstMonthValue, firstMonth.getValue()); // ========== @@ -98,9 +98,9 @@ class QuarterTests { // ========== - MonthDay startMonthDay = quarter.firstMonthDay(); - log.info("startMonthDay: {}", startMonthDay); - assertEquals(startMonthDay, MonthDay.of(4, 1)); + MonthDay firstMonthDay = quarter.firstMonthDay(); + log.info("firstMonthDay: {}", firstMonthDay); + assertEquals(firstMonthDay, MonthDay.of(4, 1)); MonthDay lastMonthDay = quarter.lastMonthDay(); log.info("lastMonthDay: {}", lastMonthDay); @@ -121,15 +121,15 @@ class QuarterTests { // ========== - int startMonthValue = quarter.firstMonthValue(); - log.info("startMonthValue: {}", startMonthValue); - assertEquals(7, startMonthValue); + int firstMonthValue = quarter.firstMonthValue(); + log.info("firstMonthValue: {}", firstMonthValue); + assertEquals(7, firstMonthValue); - Month startMonth = quarter.firstMonth(); - log.info("startMonth: {}", startMonth); - assertEquals(Month.JULY, startMonth); + Month firstMonth = quarter.firstMonth(); + log.info("firstMonth: {}", firstMonth); + assertEquals(Month.JULY, firstMonth); - assertEquals(startMonthValue, startMonth.getValue()); + assertEquals(firstMonthValue, firstMonth.getValue()); // ========== @@ -145,9 +145,9 @@ class QuarterTests { // ========== - MonthDay startMonthDay = quarter.firstMonthDay(); - log.info("startMonthDay: {}", startMonthDay); - assertEquals(startMonthDay, MonthDay.of(7, 1)); + MonthDay firstMonthDay = quarter.firstMonthDay(); + log.info("firstMonthDay: {}", firstMonthDay); + assertEquals(firstMonthDay, MonthDay.of(7, 1)); MonthDay lastMonthDay = quarter.lastMonthDay(); log.info("lastMonthDay: {}", lastMonthDay); @@ -168,15 +168,15 @@ class QuarterTests { // ========== - int startMonthValue = quarter.firstMonthValue(); - log.info("startMonthValue: {}", startMonthValue); - assertEquals(10, startMonthValue); + int firstMonthValue = quarter.firstMonthValue(); + log.info("firstMonthValue: {}", firstMonthValue); + assertEquals(10, firstMonthValue); - Month startMonth = quarter.firstMonth(); - log.info("startMonth: {}", startMonth); - assertEquals(Month.OCTOBER, startMonth); + Month firstMonth = quarter.firstMonth(); + log.info("firstMonth: {}", firstMonth); + assertEquals(Month.OCTOBER, firstMonth); - assertEquals(startMonthValue, startMonth.getValue()); + assertEquals(firstMonthValue, firstMonth.getValue()); // ========== @@ -191,12 +191,37 @@ class QuarterTests { // ========== - MonthDay startMonthDay = quarter.firstMonthDay(); - log.info("startMonthDay: {}", startMonthDay); - assertEquals(startMonthDay, MonthDay.of(10, 1)); + MonthDay firstMonthDay = quarter.firstMonthDay(); + log.info("firstMonthDay: {}", firstMonthDay); + assertEquals(firstMonthDay, MonthDay.of(10, 1)); MonthDay lastMonthDay = quarter.lastMonthDay(); log.info("lastMonthDay: {}", lastMonthDay); assertEquals(lastMonthDay, MonthDay.of(12, 31)); } + + @Test + void testFirstDayOfYear() { + int firstDayOfYear; + + firstDayOfYear = Quarter.Q1.firstDayOfYear(true); + assertEquals(1, firstDayOfYear); + firstDayOfYear = Quarter.Q1.firstDayOfYear(false); + assertEquals(1, firstDayOfYear); + + firstDayOfYear = Quarter.Q2.firstDayOfYear(true); + assertEquals(1 + (31 + 29 + 31), firstDayOfYear); + firstDayOfYear = Quarter.Q2.firstDayOfYear(false); + assertEquals(1 + (31 + 28 + 31), firstDayOfYear); + + firstDayOfYear = Quarter.Q3.firstDayOfYear(true); + assertEquals(1 + (31 + 29 + 31) + (30 + 31 + 30), firstDayOfYear); + firstDayOfYear = Quarter.Q3.firstDayOfYear(false); + assertEquals(1 + (31 + 28 + 31) + (30 + 31 + 30), firstDayOfYear); + + firstDayOfYear = Quarter.Q4.firstDayOfYear(true); + assertEquals(1 + (31 + 29 + 31) + (30 + 31 + 30) + (31 + 30 + 31), firstDayOfYear); + firstDayOfYear = Quarter.Q4.firstDayOfYear(false); + assertEquals(1 + (31 + 28 + 31) + (30 + 31 + 30) + (31 + 30 + 31), firstDayOfYear); + } } diff --git a/src/test/java/xyz/zhouxy/plusone/commons/time/YearQuarterTests.java b/src/test/java/xyz/zhouxy/plusone/commons/time/YearQuarterTests.java new file mode 100644 index 0000000..32b2ecd --- /dev/null +++ b/src/test/java/xyz/zhouxy/plusone/commons/time/YearQuarterTests.java @@ -0,0 +1,150 @@ +package xyz.zhouxy.plusone.commons.time; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import lombok.extern.slf4j.Slf4j; + +import java.time.LocalDate; +import java.time.YearMonth; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Slf4j +public class YearQuarterTests { + + @Test + void of_ValidYearAndQuarter_CreatesYearQuarter() { + int year = 2023; + Quarter quarter = Quarter.Q1; + + YearQuarter expected = YearQuarter.of(year, quarter); + YearQuarter actual = YearQuarter.of(LocalDate.of(year, 2, 28)); + + assertEquals(expected, actual); + + assertEquals("Q1 2023", actual.toString()); + } + + @Test + @SuppressWarnings("null") + void of_InvalidQuarter_ThrowsNullPointerException() { + int year = 2023; + Quarter quarter = null; + + assertThrows(NullPointerException.class, () -> YearQuarter.of(year, quarter)); + } + + @Test + void of_ValidYearQuarter_GetsCorrectStartAndEndDate() { + + for (int year = 1990; year <= 2024; year++) { + for (int qrtr = 1; qrtr <= 4; qrtr++) { + Quarter quarter = Quarter.of(qrtr); + YearQuarter yearQuarter = YearQuarter.of(year, quarter); + + LocalDate expectedStartDate = quarter.firstMonthDay().atYear(year); + log.info("{} - expectedStartDate: {}", yearQuarter, expectedStartDate); + LocalDate expectedEndDate = quarter.lastMonthDay().atYear(year); + log.info("{} - expectedEndDate: {}", yearQuarter, expectedEndDate); + + assertEquals(expectedStartDate, yearQuarter.firstDate()); + assertEquals(expectedEndDate, yearQuarter.lastDate()); + } + } + } + + @ParameterizedTest + @ValueSource(ints = { + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, + 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022, 2023, 2024 + }) + void testFirstYearMonth(int year) { + YearQuarter yq; + + yq = YearQuarter.of(year, Quarter.Q1); + assertEquals(YearMonth.of(year, 1), yq.firstYearMonth()); + yq = YearQuarter.of(year, Quarter.Q2); + assertEquals(YearMonth.of(year, 4), yq.firstYearMonth()); + yq = YearQuarter.of(year, Quarter.Q3); + assertEquals(YearMonth.of(year, 7), yq.firstYearMonth()); + yq = YearQuarter.of(year, Quarter.Q4); + assertEquals(YearMonth.of(year, 10), yq.firstYearMonth()); + + yq = YearQuarter.of(year, Quarter.Q1); + assertEquals(YearMonth.of(year, 3), yq.lastYearMonth()); + yq = YearQuarter.of(year, Quarter.Q2); + assertEquals(YearMonth.of(year, 6), yq.lastYearMonth()); + yq = YearQuarter.of(year, Quarter.Q3); + assertEquals(YearMonth.of(year, 9), yq.lastYearMonth()); + yq = YearQuarter.of(year, Quarter.Q4); + assertEquals(YearMonth.of(year, 12), yq.lastYearMonth()); + } + + @Test + void testCompareTo() { + int year1; + int quarter1; + YearQuarter yearQuarter1; + + year1 = 2024; + quarter1 = 1; + yearQuarter1 = YearQuarter.of(year1, Quarter.of(quarter1)); + + for (int year2 = 2000; year2 <= 2050; year2++) { + for (int quarter2 = 1; quarter2 <= 4; quarter2++) { + YearQuarter yearQuarter2 = YearQuarter.of(year2, Quarter.of(quarter2)); + + if (year1 == year2) { + // 同年 + assertEquals(quarter1 - quarter2, yearQuarter1.compareTo(yearQuarter2)); + + if (quarter1 == quarter2) { + // 同年同季度 + assertEquals(yearQuarter1, yearQuarter2); + assertEquals(0, yearQuarter1.compareTo(yearQuarter2)); + } + else if (quarter1 < quarter2) { + assertNotEquals(yearQuarter1, yearQuarter2); + assertTrue(yearQuarter1.isBefore(yearQuarter2)); + assertFalse(yearQuarter1.isAfter(yearQuarter2)); + assertFalse(yearQuarter2.isBefore(yearQuarter1)); + assertTrue(yearQuarter2.isAfter(yearQuarter1)); + } + else if (quarter1 > quarter2) { + assertNotEquals(yearQuarter1, yearQuarter2); + assertFalse(yearQuarter1.isBefore(yearQuarter2)); + assertTrue(yearQuarter1.isAfter(yearQuarter2)); + assertTrue(yearQuarter2.isBefore(yearQuarter1)); + assertFalse(yearQuarter2.isAfter(yearQuarter1)); + } + } + else { + // 不同年 + assertEquals(year1 - year2, yearQuarter1.compareTo(yearQuarter2)); + assertNotEquals(0, yearQuarter1.compareTo(yearQuarter2)); + if (year1 < year2) { + assertNotEquals(yearQuarter1, yearQuarter2); + assertTrue(yearQuarter1.isBefore(yearQuarter2)); + assertFalse(yearQuarter1.isAfter(yearQuarter2)); + assertFalse(yearQuarter2.isBefore(yearQuarter1)); + assertTrue(yearQuarter2.isAfter(yearQuarter1)); + } + else if (year1 > year2) { + assertNotEquals(yearQuarter1, yearQuarter2); + assertFalse(yearQuarter1.isBefore(yearQuarter2)); + assertTrue(yearQuarter1.isAfter(yearQuarter2)); + assertTrue(yearQuarter2.isBefore(yearQuarter1)); + assertFalse(yearQuarter2.isAfter(yearQuarter1)); + } + } + } + } + } +}