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

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


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

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

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

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


相关文章
|
4月前
|
存储 人工智能 机器人
工作3年,还分不清文件大小单位关系的?就看这篇吧!
工作3年,还分不清文件大小单位关系的?就看这篇吧!
|
7月前
长安十二时辰与现代时间的互转
长安十二时辰与现代时间的互转
63 0
|
7月前
|
JavaScript 小程序 前端开发
JS将时间戳转换为刚刚、N分钟前、今天几点几分、昨天几点几分等表示法
JS将时间戳转换为刚刚、N分钟前、今天几点几分、昨天几点几分等表示法
114 0
|
7月前
|
算法 Java API
算法编程(二十四):日期之间隔几天
算法编程(二十四):日期之间隔几天
79 0
《C++避坑神器·十三》保留多少位小数和去掉小数位后面的零
《C++避坑神器·十三》保留多少位小数和去掉小数位后面的零
264 0
|
传感器 存储 编解码
即时通讯音视频开发(二十):一文读懂视频的颜色模型转换和色域转换
本文将以通俗易懂的文字,引导你理解视频是如何从采集开始,历经各种步骤,最终通过颜色模型转换和不同的色域转换,让你看到赏心悦目的视频结果的。
86 0
|
安全 Java Linux
正确认识及掌握时间的用法
时间是一个相对地区而言的概念,因此有一个基准地区,就是本初子午线穿过的地区。了解世界时间相关的概念可以更好地协调全球人们的活动,便于跨越不同地区的时差。比如按照UTC时区划分算,洛杉矶和北京 之间的时间差异是16个小时, 但是一旦洛杉矶启用了夏令时两者之间的时间差异只有15个小时,神奇吗?
350 0
正确认识及掌握时间的用法
基本时间单位 | 带你读《5G 空口设计与实践进阶 》之十五
为提供精确、一致的时间度量,NR 定义了最小时间单位 Tc。
基本时间单位 | 带你读《5G 空口设计与实践进阶 》之十五
|
安全 C++
CSDN三道简单题:合并检测、星期一、特别数的和
CSDN三道简单题:合并检测、星期一、特别数的和
136 0
CSDN三道简单题:合并检测、星期一、特别数的和
|
API
一日一技:推特时间的格式化方案
一日一技:推特时间的格式化方案
254 0

热门文章

最新文章