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

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


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

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

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

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

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

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));
  }
}


相关文章
|
存储 搜索推荐 人机交互
Qt鼠标事件全面解析:从基础到实战
Qt鼠标事件全面解析:从基础到实战
2351 0
|
3月前
|
存储 弹性计算 大数据
阿里云服务器38元、99元、199元特惠详细配置、适用场景及购买条件介绍
阿里云特惠云服务器全解析:入门款:轻量应用服务器(2核2G200M带宽+40G ESSD盘)38元/年,日均0.1元。进阶款:经济型e实例(2核2G3M带宽+40G ESSD Entry盘)99元/年,续费同价。性能款:通用算力型u1实例(2核4G5M带宽+80G ESSD Entry盘)199元/年,企业独享,续费同价。三款配置覆盖个人建站、中小企业应用及轻量级企业服务,通过大数据精选用户常用配置,实现价格与性能的精准匹配。本文将详细解析这些阿里云服务器的配置、价格、限购条件以及购买指南,帮助大家更好地了解和选择适合自己的云服务器。
|
11月前
|
人工智能 小程序
【一步步开发AI运动小程序】五、帧图像人体识别
随着AI技术的发展,阿里体育等公司推出的AI运动APP,如“乐动力”和“天天跳绳”,使云上运动会、线上健身等概念广受欢迎。本文将引导您从零开始开发一个AI运动小程序,使用“云智AI运动识别小程序插件”。文章分为四部分:初始化人体识别功能、调用人体识别功能、人体识别结果处理以及识别结果旋转矫正。下篇将继续介绍人体骨骼图绘制。
|
数据可视化 小程序 API
什么是低代码(Low-Code)?我们需要低代码吗?
低代码是一种通过可视化界面和配置化方式减少手写代码工作量的软件开发技术和工具模式,适合专业开发者及非技术人员快速创建应用。本文基于作者六年实践经验,深入浅出地讲解低代码的核心价值、应用场景及其对企业、开发团队和个人开发者的意义,并推荐了织信Informat、宜搭、爱速搭等十款主流低代码平台,帮助读者快速了解和选择合适的工具。全文干货满满,建议收藏。
Threejs制作骨骼模型
这篇文章详细介绍了在Three.js中创建骨骼动画的过程,包括骨骼节点的创建、权重设置以及控制骨骼关节实现动态效果的步骤,并通过一个具体的圆柱体模型演示了如何添加和控制骨骼动画。
239 2
|
11月前
|
前端开发 开发者 Docker
深入探索Docker Compose:简化多容器应用的部署
深入探索Docker Compose:简化多容器应用的部署
269 0
|
JSON Java API
哇塞!Spring Boot 中的 @DateTimeFormat 和 @JsonFormat,竟能引发数据时间大变革!
【8月更文挑战第29天】在Spring Boot开发中,正确处理日期时间至关重要。
480 1
|
负载均衡 Java 开发者
细解微服务架构实践:如何使用Spring Cloud进行Java微服务治理
【4月更文挑战第17天】Spring Cloud是Java微服务治理的首选框架,整合了Eureka(服务发现)、Ribbon(客户端负载均衡)、Hystrix(熔断器)、Zuul(API网关)和Config Server(配置中心)。通过Eureka实现服务注册与发现,Ribbon提供负载均衡,Hystrix实现熔断保护,Zuul作为API网关,Config Server集中管理配置。理解并运用Spring Cloud进行微服务治理是现代Java开发者的关键技能。
598 3
单机elasticsearch设置远程访问
我这里是在虚拟机安装的es,虚拟机系统用的是优麒麟20.04
|
XML JSON 前端开发
获取后端接口请求中的参数(@PathVariable,@RequestParam,@RequestBody区别,使用postman请求
获取后端接口请求中的参数(@PathVariable,@RequestParam,@RequestBody区别,使用postman请求
616 1