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; + +/** + * 时辰转换器,支持宋以后的二十四时辰制度。 + *

本转换器提供以下功能: + *

+ *

+ *

+ * 异常情况: + *

+ *

+ *

+ * 示例: + *

+ *

+ * + * @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)); + } + +}