[improve] 支持 宋以后把十二时辰中每个时辰平分为初、正两部分

This commit is contained in:
VampireAchao 2024-02-27 01:19:47 +08:00 committed by VampireAchao
parent 182ada0c11
commit 0e4fa57574
2 changed files with 105 additions and 82 deletions

View File

@ -1,6 +1,7 @@
package org.dromara.hutool.core.date.chinese; package org.dromara.hutool.core.date.chinese;
import org.dromara.hutool.core.date.DateBetween; import org.dromara.hutool.core.date.DateBetween;
import org.dromara.hutool.core.text.StrUtil;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
@ -9,67 +10,80 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* 时辰转换器 * 时辰转换器支持宋以后的二十四时辰制度
* <p> * <p>
* 23-1 -> 子时 * 该转换器能够处理包含后缀的长安时辰描述并根据这些描述自动返回相应的现代时间段
* 1-3 -> 丑时 * 对于的描述分别对应每个时辰的前半段和后半段而不带后缀的时辰描述则表示该时辰的整个时间段
* 3-5 -> 寅时 * </p>
* 5-7 -> 卯时 * <p>
* 7-9 -> 辰时 * 此外该转换器还提供了根据小时数转换为对应的长安时辰描述的功能通过isAbs参数可以控制返回的描述是否包含
* 9-11 -> 巳时 * </p>
* 11-13 -> 午时 * <p>
* 13-15 -> 未时 * 示例
* 15-17 -> 申时 * <ul>
* 17-19 -> 酉时 * <li>toModernTime("子时") 返回的时间段从23点开始到1点结束</li>
* 19-21 -> 戌时 * <li>toModernTime("子初") 返回的时间段从23点开始到0点结束</li>
* 21-23 -> 亥时 * <li>toModernTime("子正") 返回的时间段从0点开始到1点结束</li>
* 24/-1/其他值 -> 未知 * <li>toShiChen(0, false) 返回子正</li>
* </p> * <li>toShiChen(0, true) 返回子时</li>
* </ul>
* </p>
* @author achao@hutool.cn * @author achao@hutool.cn
*/ */
public class ShiChen { public class ShiChen {
private static final Map<String, int[]> timeMap = new HashMap<>(); private static final Map<String, Integer> timeMap = new HashMap<>();
private static final Map<String, Integer[]> fullTimeMap = new HashMap<>();
private static final Map<Integer, String> hourToShiChenMap = new HashMap<>();
private static final Map<Integer, String> hourToShiChenAbsMap = new HashMap<>();
static { static {
// 初始化时辰对应的小时范围 // 初始化时辰对应的小时范围
timeMap.put("", new int[]{23, 1}); String[] times = {"", "", "", "", "", "", "", "", "", "", "", ""};
timeMap.put("", new int[]{1, 3}); int hour = 23;
timeMap.put("", new int[]{3, 5}); for (String time : times) {
timeMap.put("", new int[]{5, 7}); timeMap.put(time + "", hour % 24);
timeMap.put("", new int[]{7, 9}); timeMap.put(time + "", (hour + 1) % 24);
timeMap.put("", new int[]{9, 11}); fullTimeMap.put(time, new Integer[]{hour % 24, (hour + 2) % 24});
timeMap.put("", new int[]{11, 13}); hour += 2;
timeMap.put("", new int[]{13, 15}); }
timeMap.put("", new int[]{15, 17});
timeMap.put("", new int[]{17, 19}); // 初始化小时到时辰的映射
timeMap.put("", new int[]{19, 21}); hour = 23;
timeMap.put("", new int[]{21, 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;
}
} }
/** public static DateBetween toModernTime(String shiChen) {
* 将长安时辰转换为现代时间 if (StrUtil.isEmpty(shiChen)) {
* <p> throw new IllegalArgumentException("Invalid shiChen");
* toModernTime("子时").getBegin().getHours() -> 23 }
* toModernTime("子时").getEnd().getHours() -> 1 Integer startHour, endHour;
* </p> LocalDateTime start, end;
*
* @param changAnTime 长安时辰 if (shiChen.endsWith("") || shiChen.endsWith("")) {
* @return 现代时间段 startHour = timeMap.get(shiChen);
*/ if (startHour == null) {
public static DateBetween toModernTime(String changAnTime) { throw new IllegalArgumentException("Invalid ChangAn time");
String time = changAnTime.replace("", ""); }
int[] hours = timeMap.get(time); endHour = (startHour + 1) % 24;
if (hours == null) { } else {
throw new IllegalArgumentException("Invalid ChangAn time"); String baseTime = shiChen.replace("", "");
Integer[] hours = fullTimeMap.get(baseTime);
if (hours == null) {
throw new IllegalArgumentException("Invalid ChangAn time");
}
startHour = hours[0];
endHour = hours[1];
} }
LocalDateTime now = LocalDateTime.now(); start = LocalDateTime.now().withHour(startHour).withMinute(0).withSecond(0).withNano(0);
LocalDateTime start = now.withHour(hours[0]).withMinute(0).withSecond(0).withNano(0); end = (startHour > endHour) ? start.plusDays(1).withHour(endHour) : start.withHour(endHour);
LocalDateTime end = now.withHour(hours[1]).withMinute(0).withSecond(0).withNano(0);
if (hours[0] >= hours[1]) {
end = end.plusDays(1); // 处理跨日情况
}
Date startDate = Date.from(start.atZone(ZoneId.systemDefault()).toInstant()); Date startDate = Date.from(start.atZone(ZoneId.systemDefault()).toInstant());
Date endDate = Date.from(end.atZone(ZoneId.systemDefault()).toInstant()); Date endDate = Date.from(end.atZone(ZoneId.systemDefault()).toInstant());
@ -77,23 +91,12 @@ public class ShiChen {
return DateBetween.of(startDate, endDate); return DateBetween.of(startDate, endDate);
} }
/** public static String toShiChen(int hour, boolean isAbs) {
* 将小时转换为长安时辰 String result = hourToShiChenAbsMap.getOrDefault(hour, "未知");
* <p> if (!isAbs && !result.equals("未知")) {
* toChangAnTime(1) -> "子时" result = hourToShiChenMap.get(hour);
*</p>
* @param hour 小时
* @return 长安时辰
*/
public static String toChangAnTime(int hour) {
for (Map.Entry<String, int[]> entry : timeMap.entrySet()) {
int startHour = entry.getValue()[0];
int endHour = entry.getValue()[1];
if (hour == 23 || hour == 0 || (hour >= startHour && hour < endHour) || (startHour > endHour && hour < endHour)) {
return entry.getKey() + "";
}
} }
return "未知"; return result;
} }
} }

View File

@ -1,6 +1,5 @@
package org.dromara.hutool.core.date.chinese; package org.dromara.hutool.core.date.chinese;
import org.dromara.hutool.core.date.DateBetween;
import org.dromara.hutool.core.date.DateUnit; import org.dromara.hutool.core.date.DateUnit;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@ -13,27 +12,48 @@ import org.junit.jupiter.api.Test;
public class ShiChenTest { public class ShiChenTest {
@Test @Test
void testToModernTimeForAllTimes() { void testToModernTime() {
// 测试每个时辰的转换 // 测试后缀的转换表示整个时辰
Assertions.assertEquals(2, ShiChen.toModernTime("子时").between(DateUnit.HOUR));
// 测试后缀的转换表示时辰的前半段和后半段
Assertions.assertEquals(1, ShiChen.toModernTime("子初").between(DateUnit.HOUR));
Assertions.assertEquals(1, ShiChen.toModernTime("子正").between(DateUnit.HOUR));
// 测试所有时辰
String[] times = {"", "", "", "", "", "", "", "", "", "", "", ""}; String[] times = {"", "", "", "", "", "", "", "", "", "", "", ""};
int[][] expectedHours = {{23, 1}, {1, 3}, {3, 5}, {5, 7}, {7, 9}, {9, 11}, {11, 13}, {13, 15}, {15, 17}, {17, 19}, {19, 21}, {21, 23}}; for (String time : times) {
for (int i = 0; i < times.length; i++) { Assertions.assertEquals(2, ShiChen.toModernTime(time + "").between(DateUnit.HOUR));
DateBetween dateBetween = ShiChen.toModernTime(times[i] + ""); Assertions.assertEquals(1, ShiChen.toModernTime(time + "").between(DateUnit.HOUR));
Assertions.assertEquals(2, dateBetween.between(DateUnit.HOUR)); Assertions.assertEquals(1, ShiChen.toModernTime(time + "").between(DateUnit.HOUR));
Assertions.assertEquals(expectedHours[i][0], dateBetween.getBegin().getHours());
Assertions.assertEquals(expectedHours[i][1], dateBetween.getEnd().getHours());
} }
Assertions.assertThrows(IllegalArgumentException.class, () -> {
ShiChen.toModernTime("无效时");
});
Assertions.assertThrows(IllegalArgumentException.class, () -> {
ShiChen.toModernTime("无效正");
});
Assertions.assertThrows(IllegalArgumentException.class, () -> {
ShiChen.toModernTime("");
});
Assertions.assertThrows(IllegalArgumentException.class, () -> {
ShiChen.toModernTime(null);
});
} }
@Test @Test
void testToChangAnTimeForAllHours() { void testToShiChen() {
// 从23时开始测试因为子时开始于23时 // 测试小时转换为长安时辰不包含
String[] expectedTimes = {"子时", "丑时", "丑时", "寅时", "寅时", "卯时", "卯时", "辰时", "辰时", "巳时", "巳时", "午时", "午时", "未时", "未时", "申时", "申时", "酉时", "酉时", "戌时", "戌时", "亥时", "亥时", "子时", "未知"}; Assertions.assertEquals("子时", ShiChen.toShiChen(23, true));
for (int hour = 0; hour <= 24; hour++) { Assertions.assertEquals("子时", ShiChen.toShiChen(0, true));
String expectedTime = expectedTimes[hour];
String actualTime = ShiChen.toChangAnTime(hour); // 测试小时转换为长安时辰包含
Assertions.assertEquals(expectedTime, actualTime); Assertions.assertEquals("子正", ShiChen.toShiChen(0, false));
} Assertions.assertEquals("丑初", ShiChen.toShiChen(1, false));
// 测试边界条件
Assertions.assertEquals("未知", ShiChen.toShiChen(24, true));
Assertions.assertEquals("未知", ShiChen.toShiChen(-1, false));
} }
} }