中文日期(2021年09月11日 和 二〇二一年九月十一日 )在生活中经常用到,2021年09月11日很好处理直接使用模板:yyyy年MM月dd日;二〇二一年九月十一日比较不好处理,需要每个数字进行转换判断,下面使用数组和HashMap来提高效率和简化代码。

1.数字转换枚举类

比较关键,将0到31和中文关联起来,同时生成数组和HashMap。

package com.xkzhangsan.time.enums;

import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier; import com.xkzhangsan.time.utils.CollectionUtil;
import com.xkzhangsan.time.utils.CommonCache; /**
* 中文日期数字枚举
*
* @author xkzhangsan
*/
public enum ChineseDateDigitEnum { ZERO("〇"),
ONE("一"),
TWO("二"),
THREE("三"),
FOUR("四"),
FIVE("五"),
SIX("六"),
SEVEN("七"),
EIGHT("八"),
NINE("九"),
TEN("十"),
ELEVEN("十一"),
TWELVE("十二"),
THIRTEEN("十三"),
FOURTEEN("十四"),
FIFTEEN("十五"),
SIXTEEN("十六"),
SEVENTEEN("十七"),
EIGHTEEN("十八"),
NINETEEN("十九"),
TWENTY("二十"),
TWENTYONE("二十一"),
TWENTYTWO("二十二"),
TWENTYTHREE("二十三"),
TWENTYFOUR("二十四"),
TWENTYFIVE("二十五"),
TWENTYSIX("二十六"),
TWENTYSEVEN("二十七"),
TWENTYEIGHT("二十八"),
TWENTYNINE("二十九"),
THIRTY("三十"),
THIRTYONE("三十一"); public static final ChineseDateDigitEnum[] ENUMS = ChineseDateDigitEnum.values(); public static final String CHINESE_DATE_DIGIT_MAP = "CHINESE_DATE_DIGIT_MAP"; private String chineseDigit; private ChineseDateDigitEnum(String chineseDigit) {
this.chineseDigit = chineseDigit;
} public String getChineseDigit() {
return chineseDigit;
} @SuppressWarnings("unchecked")
public static Integer getIndexUseCache(String chineseDigit){
Map<String, Integer> chineseDateDigitMap = new HashMap<>(32); //查询缓存
chineseDateDigitMap = (Map<String, Integer>)CommonCache.get(CHINESE_DATE_DIGIT_MAP); //缓存存在,返回缓存
if(CollectionUtil.isNotEmpty(chineseDateDigitMap)){
return chineseDateDigitMap.get(chineseDigit);
} //缓存不存在,先设置缓存然后返回
Supplier<Object> supplier = new Supplier<Object>() {
@Override
public Object get() {
Map<String, Integer> dateDigitMap = new HashMap<>(); for(ChineseDateDigitEnum chineseDateDigitEnum : ENUMS){
dateDigitMap.put(chineseDateDigitEnum.getChineseDigit(), chineseDateDigitEnum.ordinal());
}
return dateDigitMap;
}
};
return ((Map<String, Integer>)CommonCache.get(CHINESE_DATE_DIGIT_MAP, supplier)).get(chineseDigit);
} }

2.格式化

ChineseDateDigitEnum.ENUMS[localDateTime.getDayOfMonth()] ,通过枚举数组下标取值,效率非常高。
    /**
* 中文日期格式化,isUpperCase false:2021年09月11日 true: 二〇二一年九月十一日
* @param date Date
* @param isUpperCase 是否大写,false:2021年09月11日 true: 二〇二一年九月十一日
* @return String
*/
public static String formatToChineseDateStr(Date date, boolean isUpperCase){
return formatToChineseDateStr(DateTimeConverterUtil.toLocalDateTime(date), isUpperCase);
} /**
* 中文日期格式化,isUpperCase false:2021年09月11日 true: 二〇二一年九月十一日
* @param localDateTime LocalDateTime
* @param isUpperCase 是否大写,false:2021年09月11日 true: 二〇二一年九月十一日
* @return String
*/
public static String formatToChineseDateStr(LocalDateTime localDateTime, boolean isUpperCase){
Objects.requireNonNull(localDateTime, "localDateTime");
if(isUpperCase){
StringBuilder buf = new StringBuilder();
//年
String year = String.valueOf(localDateTime.getYear());
int yearLength = year.length();
for(int i=0; i<yearLength; i++){
buf.append(ChineseDateDigitEnum.ENUMS[year.charAt(i)-48].getChineseDigit());
}
buf.append("年");
//月
buf.append(ChineseDateDigitEnum.ENUMS[localDateTime.getMonthValue()].getChineseDigit());
buf.append("月");
//日
buf.append(ChineseDateDigitEnum.ENUMS[localDateTime.getDayOfMonth()].getChineseDigit());
buf.append("日");
return buf.toString();
}else{
return format(localDateTime, YYYY_MM_DD_CN_FMT);
}
}

3.解析

ChineseDateDigitEnum.getIndexUseCache(dayStrArr[0]) ,通过将数字转换枚举类转换为HashMap,并且使用缓存将map缓存起来,效率非常高。
    /**
* 中文日期解析 2021年09月11日 或 二〇二一年九月十一日,返回Date
* @param text 2021年09月11日 或 二〇二一年九月十一日
* @return Date
*/
public static Date parseChineseDateStrToDate(String text){
return DateTimeConverterUtil.toDate(parseChineseDateStrToLocalDateTime(text));
} /**
* 中文日期解析 2021年09月11日 或 二〇二一年九月十一日,返回LocalDateTime
* @param text 2021年09月11日 或 二〇二一年九月十一日
* @return LocalDateTime
*/
public static LocalDateTime parseChineseDateStrToLocalDateTime(String text){
if(StringUtil.isEmpty(text)){
throw new NullPointerException("text");
}
text = text.trim();
Pattern pattern = RegexEnum.NormYearFour.getPattern();
Matcher match = pattern.matcher(text);
if (match.find()){
return parseToLocalDateTime(text, YYYY_MM_DD_CN_FMT);
} else {
StringBuilder buf = new StringBuilder();
//年
String[] yearStrArr = text.split("年");
String yearStr = yearStrArr[0];
int yearStrLength = yearStr.length();
for(int i=0; i<yearStrLength; i++){
buf.append(ChineseDateDigitEnum.getIndexUseCache(String.valueOf(yearStr.charAt(i))));
}
int year = Integer.parseInt(buf.toString());
//月
String[] monthStrArr = yearStrArr[1].split("月");
int month = ChineseDateDigitEnum.getIndexUseCache(monthStrArr[0]);
//日
String[] dayStrArr = monthStrArr[1].split("日");
int day = ChineseDateDigitEnum.getIndexUseCache(dayStrArr[0]);
return LocalDateTime.of(year, month, day, 0, 0);
}
}

4.测试

    /**
* 中文日期格式化测试
*/
@Test
public void formatToChineseDateStrTest(){
Date date = DateTimeCalculatorUtil.getDate(2021, 9, 11);
Assert.assertEquals("2021年09月11日",DateTimeFormatterUtil.formatToChineseDateStr(date, false));
Assert.assertEquals("二〇二一年九月十一日",DateTimeFormatterUtil.formatToChineseDateStr(date, true)); LocalDateTime localDateTime = LocalDateTime.of(2021, 9, 11, 0, 0);
Assert.assertEquals("2021年09月11日",DateTimeFormatterUtil.formatToChineseDateStr(localDateTime, false));
Assert.assertEquals("二〇二一年九月十一日",DateTimeFormatterUtil.formatToChineseDateStr(localDateTime, true));
} /**
* 中文日期解析测试
*/
@Test
public void parseChineseDateStrToDateTest(){
Date date = DateTimeCalculatorUtil.getDate(2021, 8, 31);
Assert.assertEquals(date, DateTimeFormatterUtil.parseChineseDateStrToDate("2021年08月31日"));
Assert.assertEquals(date, DateTimeFormatterUtil.parseChineseDateStrToDate("二〇二一年八月三十一日")); LocalDateTime localDateTime = LocalDateTime.of(2021, 8, 31, 0, 0);
Assert.assertEquals(localDateTime, DateTimeFormatterUtil.parseChineseDateStrToLocalDateTime("2021年08月31日"));
Assert.assertEquals(localDateTime, DateTimeFormatterUtil.parseChineseDateStrToLocalDateTime("二〇二一年八月三十一日"));
}
源代码地址:https://github.com/xkzhangsan/xk-time

Java日期时间API系列42-----一种高效的中文日期格式化和解析方法的更多相关文章

  1. Java日期时间API系列19-----Jdk8中java.time包中的新的日期时间API类,ZonedDateTime与ZoneId和LocalDateTime的关系,ZonedDateTime格式化和时区转换等。

    通过Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类中时间范围示意图:可以很清晰的看出ZonedDateTime相当于LocalDateTime+ZoneI ...

  2. Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析

    目录 0.前言 1.TemporalAccessor源码 2.Temporal源码 3.TemporalAdjuster源码 4.ChronoLocalDate源码 5.LocalDate源码 6.总 ...

  3. Java日期时间API系列11-----Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate

    通过Java日期时间API系列7-----Jdk8中java.time包中的新的日期时间API类的优点,java8具有很多优点,现在网上查到的农历转换工具类都是基于jdk7及以前的类写的,下面使用ja ...

  4. Java日期时间API系列12-----Jdk8中java.time包中的新的日期时间API类,日期格式化,常用日期格式大全

    通过Java日期时间API系列10-----Jdk8中java.time包中的新的日期时间API类的DateTimeFormatter, 可以看出java8的DateTimeFormatter完美解决 ...

  5. Java日期时间API系列13-----Jdk8中java.time包中的新的日期时间API类,时间类转换,Date转LocalDateTime,LocalDateTime转Date等

    从前面的系列博客中可以看出Jdk8中java.time包中的新的日期时间API类设计的很好,但Date由于使用仍非常广泛,这就涉及到Date转LocalDateTime,LocalDateTime转D ...

  6. Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类

    因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...

  7. Java日期时间API系列7-----Jdk8中java.time包中的新的日期时间API类的特点

    1.不变性 新的日期/时间API中,所有的类都是不可变的,这对多线程环境有好处. 比如:LocalDateTime 2.关注点分离 新的API将人可读的日期时间和机器时间(unix timestamp ...

  8. Java日期时间API系列21-----Jdk8中java.time包中的新的日期时间API类,xk-time时间转换,计算,格式化,解析的工具

    通过工作之余,对Java8中java.time包源码的不断学习,使用和总结,开发了xk-time,初步完成,欢迎试用和提出建议! xk-time xk-time is a datetime conve ...

  9. Java日期时间API系列2-----Jdk7及以前的日期时间类在mysql数据库中的应用

    1.java中与数据库相关的时间类 java提供与mysql方便交互的三种数据类型: java.sql.Date java.sql.Time java.sql.Timestamp 它们都是继承java ...

  10. Java日期时间API系列10-----Jdk8中java.time包中的新的日期时间API类的DateTimeFormatter

    1.DateTimeFormatter final修饰,线程安全,用于打印和解析日期-时间对象的格式化程序. 创建DateTimeFormatter: DateTimeFormatter dateTi ...

随机推荐

  1. XML学习笔记3——XSD简述

    现在的语言,如果不有那么一点OO的影子,都不好意思称之为语言了.在XML的语义约束方面,DTD虽然简单,但是功能不够强大,完全是直白的描述,于是又有了替代DTD的XSD(XML Schema Defi ...

  2. ibatis中使用like模糊查询

    select * from table1 where name like '%#name#%' 两种有效的方法: 1) 使用$代替#.此种方法就是去掉了类型检查,使用字符串连接,不过可能会有sql注入 ...

  3. MSSQL手札二 MSSQL的触发器

    触发器,就是在对表做DML操作的时候,触发一些其他的事件,触发器一般用在check约束更加复杂的约束上面,是一种特殊的存储过程,不可以被主动调用. 语法如下: CREATE TRIGGER trigg ...

  4. Storm系列(十六)架构分析之Executor-Bolt

    准备消息循环的数据 函数原型: 1  let[executor-sampler (mk-stats-sampler (:storm-conf executor-data))] 主要功能: 定义tupl ...

  5. socket.io实现

    后台代码 index_server.js var app = require('http').createServer(handler)//创建服务器app , io = require('socke ...

  6. 关于 MyBatis MyBatis-Spring Jdbc 批量插入的各种比较分析

    因为目前SME项目中编写了一套蜘蛛爬虫程序,所以导致插入数据库的数据量剧增.就项目中使用到的3种DB插入方式进行了一个Demo分析: 具体代码如下: 1: MyBatis 开启Batch方式,最普通的 ...

  7. JAVA学习笔记(2)—— java初始化三个原则

    1. 初始化原则 (1)   静态对象(变量)优先于非静态对象(变量)初始化,其中静态对象(变量)初始化一次,非静态对象(变量)可能会初始化多次. (2)   父类优先于子类初始化 (3)   按照成 ...

  8. python网络编程(十三)

    协程-greenlet版 为了更好使用协程来完成多任务,python中的greenlet模块对其封装,从而使得切换任务变的更加简单 安装方式 使用如下命令安装greenlet模块: sudo pip ...

  9. aircrack-ng后台跑包, 成功后自动发送邮件通知

    我的思路是直接用nohup守护进程输出结构到指定文件, 然后判断文件中"KEY FOUND"的字段. 启动aircrack-ng方式 nohup aircrack-ng -w /o ...

  10. JavaWeb跨域访问问题

    转载: http://blog.csdn.net/zjq_1314520/article/details/65449279 最后的解决方案如下: 在 tomcat 的 conf目录下找到 web.xm ...