diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/date/DateBetween.java b/hutool-core/src/main/java/org/dromara/hutool/core/date/DateBetween.java
index b5114482d..e78e42253 100644
--- a/hutool-core/src/main/java/org/dromara/hutool/core/date/DateBetween.java
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/date/DateBetween.java
@@ -168,6 +168,14 @@ public class DateBetween implements Serializable {
return result;
}
+ public Date getBegin() {
+ return begin;
+ }
+
+ public Date getEnd() {
+ return end;
+ }
+
/**
* 格式化输出时间差
*
diff --git a/hutool-core/src/main/java/org/dromara/hutool/core/date/chinese/ShiChen.java b/hutool-core/src/main/java/org/dromara/hutool/core/date/chinese/ShiChen.java
new file mode 100644
index 000000000..799ac571f
--- /dev/null
+++ b/hutool-core/src/main/java/org/dromara/hutool/core/date/chinese/ShiChen.java
@@ -0,0 +1,139 @@
+package org.dromara.hutool.core.date.chinese;
+
+import org.dromara.hutool.core.date.DateBetween;
+import org.dromara.hutool.core.text.StrUtil;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 时辰转换器,支持宋以后的二十四时辰制度。
+ *
本转换器提供以下功能:
+ *
+ * - 处理包含“时”、“初”或“正”后缀的长安时辰描述,并自动返回相应的现代时间段。
+ * “初”和“正”分别对应每个时辰的前半段和后半段,而不带后缀的“时”描述则涵盖该时辰的完整时间段。
+ * - 根据小时数转换为相应的长安时辰描述,通过{@code isAbs}参数控制是否包含“初”或“正”。
+ *
+ *
+ *
+ * 异常情况:
+ *
+ * - 如果输入的长安时辰描述无效或不被识别,{@code toModernTime} 方法将抛出 {@code IllegalArgumentException}。
+ * - 同样,如果{@code toShiChen}方法接收到无效的小时数,将返回“未知”。
+ *
+ *
+ *
+ * 示例:
+ *
+ * - {@code toModernTime("子时")} 返回的时间段从23点开始到1点结束。
+ * - {@code toModernTime("子初")} 返回的时间段从23点开始到0点结束。
+ * - {@code toModernTime("子正")} 返回的时间段从0点开始到1点结束。
+ * - {@code toShiChen(0, false)} 返回“子正”。
+ * - {@code toShiChen(0, true)} 返回“子时”。
+ *
+ *
+ *
+ * @author achao@hutool.cn
+ */
+public class ShiChen {
+
+ private static final Map timeMap = new HashMap<>();
+ private static final Map fullTimeMap = new HashMap<>();
+ private static final Map hourToShiChenMap = new HashMap<>();
+ private static final Map hourToShiChenAbsMap = new HashMap<>();
+
+ static {
+ // 初始化时辰对应的小时范围
+ String[] times = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};
+ int hour = 23;
+ for (String time : times) {
+ timeMap.put(time + "初", hour % 24);
+ timeMap.put(time + "正", (hour + 1) % 24);
+ fullTimeMap.put(time, new Integer[]{hour % 24, (hour + 2) % 24});
+ hour += 2;
+ }
+
+ // 初始化小时到时辰的映射
+ hour = 23;
+ for (String time : times) {
+ hourToShiChenMap.put(hour % 24, time + "初");
+ hourToShiChenMap.put((hour + 1) % 24, time + "正");
+ hourToShiChenAbsMap.put(hour % 24, time + "时");
+ hourToShiChenAbsMap.put((hour + 1) % 24, time + "时");
+ hour += 2;
+ }
+ }
+
+ /**
+ * 将长安时辰描述转换为现代时间段。
+ *
+ * 示例:
+ *
+ * - {@code toModernTime("子时")} 返回的时间段从23点开始到1点结束。
+ * - {@code toModernTime("子初")} 返回的时间段从23点开始到0点结束。
+ * - {@code toModernTime("子正")} 返回的时间段从0点开始到1点结束。
+ *
+ *
+ *
+ * @param shiChen 长安时辰描述,可以是“时”、“初”或“正”结尾。
+ * @return {@link DateBetween} 对象,表示起始和结束时间。
+ * @throws IllegalArgumentException 如果输入的长安时辰描述无效。
+ */
+ public static DateBetween toModernTime(String shiChen) {
+ if (StrUtil.isEmpty(shiChen)) {
+ throw new IllegalArgumentException("Invalid shiChen");
+ }
+ Integer startHour, endHour;
+ LocalDateTime start, end;
+
+ if (shiChen.endsWith("初") || shiChen.endsWith("正")) {
+ startHour = timeMap.get(shiChen);
+ if (startHour == null) {
+ throw new IllegalArgumentException("Invalid ChangAn time");
+ }
+ endHour = (startHour + 1) % 24;
+ } else {
+ String baseTime = shiChen.replace("时", "");
+ Integer[] hours = fullTimeMap.get(baseTime);
+ if (hours == null) {
+ throw new IllegalArgumentException("Invalid ChangAn time");
+ }
+ startHour = hours[0];
+ endHour = hours[1];
+ }
+
+ start = LocalDateTime.now().withHour(startHour).withMinute(0).withSecond(0).withNano(0);
+ end = (startHour > endHour) ? start.plusDays(1).withHour(endHour) : start.withHour(endHour);
+
+ Date startDate = Date.from(start.atZone(ZoneId.systemDefault()).toInstant());
+ Date endDate = Date.from(end.atZone(ZoneId.systemDefault()).toInstant());
+
+ return DateBetween.of(startDate, endDate);
+ }
+
+ /**
+ * 根据给定的小时数转换为对应的长安时辰描述。
+ *
+ * 示例:
+ *
+ * - {@code toShiChen(0, false)} 返回“子正”。
+ * - {@code toShiChen(0, true)} 返回“子时”。
+ *
+ *
+ *
+ * @param hour 小时数,应在0到23之间。
+ * @param isAbs 是否返回绝对时辰描述(即包含“时”后缀),而不是“初”或“正”。
+ * @return 长安时辰描述,如果小时数无效,则返回“未知”。
+ */
+ public static String toShiChen(int hour, boolean isAbs) {
+ String result = hourToShiChenAbsMap.getOrDefault(hour, "未知");
+ if (!isAbs && !result.equals("未知")) {
+ result = hourToShiChenMap.get(hour);
+ }
+ return result;
+ }
+
+}
diff --git a/hutool-core/src/test/java/org/dromara/hutool/core/date/chinese/ShiChenTest.java b/hutool-core/src/test/java/org/dromara/hutool/core/date/chinese/ShiChenTest.java
new file mode 100644
index 000000000..7e950b417
--- /dev/null
+++ b/hutool-core/src/test/java/org/dromara/hutool/core/date/chinese/ShiChenTest.java
@@ -0,0 +1,53 @@
+package org.dromara.hutool.core.date.chinese;
+
+import org.dromara.hutool.core.date.DateUnit;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * ShiChenTest
+ *
+ * @author achao@apache.org
+ */
+public class ShiChenTest {
+
+ @Test
+ void testToModernTime() {
+ // 测试“时”后缀的转换,表示整个时辰
+ assertEquals(2, ShiChen.toModernTime("子时").between(DateUnit.HOUR));
+
+ // 测试“初”和“正”后缀的转换,表示时辰的前半段和后半段
+ assertEquals(1, ShiChen.toModernTime("子初").between(DateUnit.HOUR));
+ assertEquals(1, ShiChen.toModernTime("子正").between(DateUnit.HOUR));
+
+ // 测试所有时辰
+ String[] times = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};
+ for (String time : times) {
+ assertEquals(2, ShiChen.toModernTime(time + "时").between(DateUnit.HOUR));
+ assertEquals(1, ShiChen.toModernTime(time + "初").between(DateUnit.HOUR));
+ assertEquals(1, ShiChen.toModernTime(time + "正").between(DateUnit.HOUR));
+ }
+ assertThrows(IllegalArgumentException.class, () -> ShiChen.toModernTime("无效时"));
+ assertThrows(IllegalArgumentException.class, () -> ShiChen.toModernTime("无效正"));
+ assertThrows(IllegalArgumentException.class, () -> ShiChen.toModernTime(""));
+ assertThrows(IllegalArgumentException.class, () -> ShiChen.toModernTime(null));
+ }
+
+ @Test
+ void testToShiChen() {
+ // 测试小时转换为长安时辰,不包含“初”或“正”
+ assertEquals("子时", ShiChen.toShiChen(23, true));
+ assertEquals("子时", ShiChen.toShiChen(0, true));
+
+ // 测试小时转换为长安时辰,包含“初”或“正”
+ assertEquals("子正", ShiChen.toShiChen(0, false));
+ assertEquals("丑初", ShiChen.toShiChen(1, false));
+
+ // 测试边界条件
+ assertEquals("未知", ShiChen.toShiChen(24, true));
+ assertEquals("未知", ShiChen.toShiChen(-1, false));
+ }
+
+}