Java日期时间API系列42-----一种高效的中文日期格式化和解析方法
中文日期(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-----一种高效的中文日期格式化和解析方法的更多相关文章
- Java日期时间API系列19-----Jdk8中java.time包中的新的日期时间API类,ZonedDateTime与ZoneId和LocalDateTime的关系,ZonedDateTime格式化和时区转换等。
通过Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类中时间范围示意图:可以很清晰的看出ZonedDateTime相当于LocalDateTime+ZoneI ...
- Java日期时间API系列8-----Jdk8中java.time包中的新的日期时间API类的LocalDate源码分析
目录 0.前言 1.TemporalAccessor源码 2.Temporal源码 3.TemporalAdjuster源码 4.ChronoLocalDate源码 5.LocalDate源码 6.总 ...
- Java日期时间API系列11-----Jdk8中java.time包中的新的日期时间API类,使用java8日期时间API重写农历LunarDate
通过Java日期时间API系列7-----Jdk8中java.time包中的新的日期时间API类的优点,java8具有很多优点,现在网上查到的农历转换工具类都是基于jdk7及以前的类写的,下面使用ja ...
- Java日期时间API系列12-----Jdk8中java.time包中的新的日期时间API类,日期格式化,常用日期格式大全
通过Java日期时间API系列10-----Jdk8中java.time包中的新的日期时间API类的DateTimeFormatter, 可以看出java8的DateTimeFormatter完美解决 ...
- Java日期时间API系列13-----Jdk8中java.time包中的新的日期时间API类,时间类转换,Date转LocalDateTime,LocalDateTime转Date等
从前面的系列博客中可以看出Jdk8中java.time包中的新的日期时间API类设计的很好,但Date由于使用仍非常广泛,这就涉及到Date转LocalDateTime,LocalDateTime转D ...
- Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类
因为Jdk7及以前的日期时间类的不方便使用问题和线程安全问题等问题,2005年,Stephen Colebourne创建了Joda-Time库,作为替代的日期和时间API.Stephen向JCP提交了 ...
- Java日期时间API系列7-----Jdk8中java.time包中的新的日期时间API类的特点
1.不变性 新的日期/时间API中,所有的类都是不可变的,这对多线程环境有好处. 比如:LocalDateTime 2.关注点分离 新的API将人可读的日期时间和机器时间(unix timestamp ...
- Java日期时间API系列21-----Jdk8中java.time包中的新的日期时间API类,xk-time时间转换,计算,格式化,解析的工具
通过工作之余,对Java8中java.time包源码的不断学习,使用和总结,开发了xk-time,初步完成,欢迎试用和提出建议! xk-time xk-time is a datetime conve ...
- Java日期时间API系列2-----Jdk7及以前的日期时间类在mysql数据库中的应用
1.java中与数据库相关的时间类 java提供与mysql方便交互的三种数据类型: java.sql.Date java.sql.Time java.sql.Timestamp 它们都是继承java ...
随机推荐
- springboot自定义ObjectMapper序列化、配置序列化对LocalDateTime的支持
背景 问题1:项目中使用默认自带的jackson进行前后端交互,实现数据对象的序列化和反序列化,默认的ObjectMapper采用小驼峰的格式,但是调用其他业务的http接口时,ObjectMappe ...
- JavaGUI输入框事件监听的使用
JavaGUI输入框事件监听的使用 package GUI; import java.awt.*; import java.awt.event.ActionEvent; import java.awt ...
- MySQL-12-innodb引擎补充
innodb引擎保证事务的ACID 概念 redo log ---> 重做日志 ib_logfile0~1 50M 轮询使用 redo log buffer ---> redo内存区域 i ...
- Windows注册表内容详解(转载)
(关于windows注册表的整理,来源网络) 前提 一.什么是注册表 注册表是windows操作系统.硬件设备以及客户应用程序得以正常运行和保存设置的核心"数据库",也可以说是 ...
- miniFTP项目实战五
项目简介: 在Linux环境下用C语言开发的Vsftpd的简化版本,拥有部分Vsftpd功能和相同的FTP协议,系统的主要架构采用多进程模型,每当有一个新的客户连接到达,主进程就会派生出一个ftp服务 ...
- SIM900A—基础指令
文章目录 1.ATE指令设置回显 2.ATQ指令设置返回 3.ATV指令设置返回格式 4.AT+CFUN设置模块功能 5.AT+IPR设置波特率 6.AT+CMEE设置上报错误格式 7.各种码(IME ...
- 题解—God Knows
考场上以为就是转化成一个无向图然后以为无向图有什么性质可以搞出来来着. 果然应验了那句话,一个思路想太久想不出来一般是假的. 所以这种一看就需要转化的题要多尝试能往哪转化,而不是按住一个思路不动. 只 ...
- ManagementEventWatcher throws ManagementException with call to Stop()
参考网址:https://stackoverflow.com/questions/46100105/managementeventwatcher-throws-managementexception- ...
- [ASP.NET MVC]@Partial 和@RenderPartial的区别
@Partial 和@RenderPartial的区别 Html.partial和RenderPartial的用法与区别 Html.partial和RenderPartial都是输出html片段,区别 ...
- Spring之JDBC Template
时间:2017-2-5 18:16 --Spring对不同持久化技术的支持Spring为各种支持的持久化技术都提供了简单操作的模板和回调.ORM持久化技术: JDBC: org.s ...