mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
!1184 [v6] [feature] 添加十二时辰与现代时间的互转
Merge pull request !1184 from 阿超/v6-dev
This commit is contained in:
commit
648ffb20a6
@ -168,6 +168,14 @@ public class DateBetween implements Serializable {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Date getBegin() {
|
||||
return begin;
|
||||
}
|
||||
|
||||
public Date getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化输出时间差
|
||||
*
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
* 时辰转换器,支持宋以后的二十四时辰制度。
|
||||
* <p>本转换器提供以下功能:
|
||||
* <ul>
|
||||
* <li>处理包含“时”、“初”或“正”后缀的长安时辰描述,并自动返回相应的现代时间段。
|
||||
* “初”和“正”分别对应每个时辰的前半段和后半段,而不带后缀的“时”描述则涵盖该时辰的完整时间段。</li>
|
||||
* <li>根据小时数转换为相应的长安时辰描述,通过{@code isAbs}参数控制是否包含“初”或“正”。</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* 异常情况:
|
||||
* <ul>
|
||||
* <li>如果输入的长安时辰描述无效或不被识别,{@code toModernTime} 方法将抛出 {@code IllegalArgumentException}。</li>
|
||||
* <li>同样,如果{@code toShiChen}方法接收到无效的小时数,将返回“未知”。</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* 示例:
|
||||
* <ul>
|
||||
* <li>{@code toModernTime("子时")} 返回的时间段从23点开始到1点结束。</li>
|
||||
* <li>{@code toModernTime("子初")} 返回的时间段从23点开始到0点结束。</li>
|
||||
* <li>{@code toModernTime("子正")} 返回的时间段从0点开始到1点结束。</li>
|
||||
* <li>{@code toShiChen(0, false)} 返回“子正”。</li>
|
||||
* <li>{@code toShiChen(0, true)} 返回“子时”。</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @author achao@hutool.cn
|
||||
*/
|
||||
public class ShiChen {
|
||||
|
||||
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 {
|
||||
// 初始化时辰对应的小时范围
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将长安时辰描述转换为现代时间段。
|
||||
* <p>
|
||||
* 示例:
|
||||
* <ul>
|
||||
* <li>{@code toModernTime("子时")} 返回的时间段从23点开始到1点结束。</li>
|
||||
* <li>{@code toModernTime("子初")} 返回的时间段从23点开始到0点结束。</li>
|
||||
* <li>{@code toModernTime("子正")} 返回的时间段从0点开始到1点结束。</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据给定的小时数转换为对应的长安时辰描述。
|
||||
* <p>
|
||||
* 示例:
|
||||
* <ul>
|
||||
* <li>{@code toShiChen(0, false)} 返回“子正”。</li>
|
||||
* <li>{@code toShiChen(0, true)} 返回“子时”。</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user