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

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


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

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

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

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


相关文章
|
8月前
|
存储 弹性计算 大数据
阿里云服务器38元、99元、199元特惠详细配置、适用场景及购买条件介绍
阿里云特惠云服务器全解析:入门款:轻量应用服务器(2核2G200M带宽+40G ESSD盘)38元/年,日均0.1元。进阶款:经济型e实例(2核2G3M带宽+40G ESSD Entry盘)99元/年,续费同价。性能款:通用算力型u1实例(2核4G5M带宽+80G ESSD Entry盘)199元/年,企业独享,续费同价。三款配置覆盖个人建站、中小企业应用及轻量级企业服务,通过大数据精选用户常用配置,实现价格与性能的精准匹配。本文将详细解析这些阿里云服务器的配置、价格、限购条件以及购买指南,帮助大家更好地了解和选择适合自己的云服务器。
|
8月前
|
XML 机器人 数据安全/隐私保护
QQ机器人xml卡片代码,xml卡片消息生成器, qq卡片代码大全autojs版【仅供学习参考】
代码说明:这个实现包含三个主要模块,XML生成器核心类、常用卡片模板和示例使用代码
|
9月前
|
XML 数据格式
QQ群聊天网警已经介入,最新QQ xml卡片生成器,装逼娱乐神器代码
本项目为QQ卡片XML生成器,包含核心生成器、卡片增强器和主程序界面。支持多种样式、动态效果与主题,代码超过300行,适合学习参考。
|
机器学习/深度学习 自然语言处理 PyTorch
LLM-Mixer: 融合多尺度时间序列分解与预训练模型,可以精准捕捉短期波动与长期趋势
近年来,大型语言模型(LLMs)在自然语言处理领域取得显著进展,研究人员开始探索将其应用于时间序列预测。Jin等人提出了LLM-Mixer框架,通过多尺度时间序列分解和预训练的LLMs,有效捕捉时间序列数据中的短期波动和长期趋势,提高了预测精度。实验结果显示,LLM-Mixer在多个基准数据集上优于现有方法,展示了其在时间序列预测任务中的巨大潜力。
502 3
LLM-Mixer: 融合多尺度时间序列分解与预训练模型,可以精准捕捉短期波动与长期趋势
|
设计模式 前端开发 C#
使用 Prism 框架实现导航.NET 6.0 + WPF
使用 Prism 框架实现导航.NET 6.0 + WPF
711 10
|
小程序 搜索推荐 数据挖掘
【开题报告】基于微信小程序的电子产品商城的设计与实现
【开题报告】基于微信小程序的电子产品商城的设计与实现
1704 0
|
Java API
如何在 Java 中将 Arraylist 变成数组?
【8月更文挑战第23天】
783 0
|
Java jenkins 持续交付
基于Jenkins,docker实现自动化部署(持续交互)【转】
  前言 随着业务的增长,需求也开始增多,每个需求的大小,开发周期,发布时间都不一致。基于微服务的系统架构,功能的叠加,对应的服务的数量也在增加,大小功能的快速迭代,更加要求部署的快速化,智能化。
12343 1
|
Java 测试技术 开发者
Spring构造器注入有多好?
Spring构造器注入有多好?
1528 0
Spring构造器注入有多好?