前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >十二时辰与现代时间的互转(精确版)

十二时辰与现代时间的互转(精确版)

作者头像
阿超
发布2024-02-28 08:52:43
1030
发布2024-02-28 08:52:43
举报
文章被收录于专栏:快乐阿超快乐阿超

内抑怒气,外制愠色,处世待人,心平气和。——圣德太子

最新版优化了一版,支持了

宋以后把十二时辰中每个时辰平分为初、正两部分,这样,子初、子正、丑初、丑正…依次下去,恰为二十四时辰,同现在一天二十四小时时间一致

hutool-core/src/main/java/org/dromara/hutool/core/date/chinese/ShiChen.java · dromara/hutool - Gitee.com

代码语言:javascript
复制
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>
 * 异常情况:
 * <ul>
 * <li>如果输入的时辰描述无效或不被识别,{@code toModernTime} 方法将抛出 {@code IllegalArgumentException}。</li>
 * <li>同样,如果{@code toShiChen}方法接收到无效的小时数,将返回“未知”。</li>
 * </ul>
 * 示例:
 * <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>
 *
 * @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 {
		// 初始化时辰对应的小时范围
		final String[] times = {"子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申", "酉", "戌", "亥"};
		int hour = 23;
		for (final 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 (final 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;
		}
	}

	/**
	 * 将时辰描述转换为现代时间段。示例:
	 * <ul>
	 * <li>{@code toModernTime("子时")} 返回的时间段从23点开始到1点结束。</li>
	 * <li>{@code toModernTime("子初")} 返回的时间段从23点开始到0点结束。</li>
	 * <li>{@code toModernTime("子正")} 返回的时间段从0点开始到1点结束。</li>
	 * </ul>
	 *
	 * @param shiChen 时辰描述,可以是“时”、“初”或“正”结尾。
	 * @return {@link DateBetween} 对象,表示起始和结束时间。
	 * @throws IllegalArgumentException 如果输入的时辰描述无效。
	 */
	public static DateBetween toModernTime(final String shiChen) {
		if (StrUtil.isEmpty(shiChen)) {
			throw new IllegalArgumentException("Invalid shiChen");
		}
		final Integer startHour;
		final Integer endHour;
		final LocalDateTime start;
		final LocalDateTime end;

		if (shiChen.endsWith("初") || shiChen.endsWith("正")) {
			startHour = timeMap.get(shiChen);
			if (startHour == null) {
				throw new IllegalArgumentException("Invalid ShiChen time");
			}
			endHour = (startHour + 1) % 24;
		} else {
			final String baseTime = shiChen.replace("时", "");
			final Integer[] hours = fullTimeMap.get(baseTime);
			if (hours == null) {
				throw new IllegalArgumentException("Invalid ShiChen 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);

		final Date startDate = Date.from(start.atZone(ZoneId.systemDefault()).toInstant());
		final Date endDate = Date.from(end.atZone(ZoneId.systemDefault()).toInstant());

		return DateBetween.of(startDate, endDate);
	}

	/**
	 * 根据给定的小时数转换为对应的时辰描述。示例:
	 * <ul>
	 *   <li>{@code toShiChen(0, false)} 返回“子正”。</li>
	 *   <li>{@code toShiChen(0, true)} 返回“子时”。</li>
	 * </ul>
	 *
	 * @param hour  小时数,应在0到23之间。
	 * @param isAbs 是否返回绝对时辰描述(即包含“时”后缀),而不是“初”或“正”。
	 * @return 时辰描述,如果小时数无效,则返回“未知”。
	 */
	public static String toShiChen(final int hour, final boolean isAbs) {
		String result = hourToShiChenAbsMap.getOrDefault(hour, "未知");
		if (!isAbs && !result.equals("未知")) {
			result = hourToShiChenMap.get(hour);
		}
		return result;
	}

}

hutool-core/src/test/java/org/dromara/hutool/core/date/chinese/ShiChenTest.java · dromara/hutool - Gitee.com

代码语言:javascript
复制
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));
	}

}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2024-02-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
腾讯云服务器利旧
云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档