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 ...
随机推荐
- Server-Speaks-First 有点坑,Linkerd 2.10 中的协议检测和不透明端口
协议检测(Protocol detection),顾名思义,允许 Linkerd 自动检测 TCP 连接中使用的协议. Linkerd 的设计原则之一是"just work",协议 ...
- OOP面向对象程序设计原则
OOP面向对象程序设计原则 开闭原则(Open Close Principle) 对扩展开放,对修改关闭 里氏代换原则(Liskov Substitution Principle) 继承必须确保超累所 ...
- openssl常用命令行汇总
openssl常用命令行汇总 随机数 openssl rand -out rand.dat -base64 32 摘要 直接做摘要 openssl dgst -sha1 -out dgst.dat p ...
- MyBatis学习04(注解开发)
7.使用注解开发 7.1 面向接口编程 根本原因 : 解耦 , 可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的实现 , 大家都遵守共同的标准 , 使得开发变得容易 , 规范性更好 在一个面 ...
- AWS(amazon ec2)服务器流量查询
aws ec2流量监控 亚马逊云服务新用户绑定信用卡免费使用一年,相信很多人白嫖过,选用micro最低配置+流量免费15G,包含上下行.这种配置用来测试玩玩还行,生产使用的话容易超标.很多人想知道流量 ...
- HCNA Routing&Switching之PPPoE协议
前文我们了解了广域网中的HDLC和PPP协议相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15174240.html:今天我们来聊一聊PPPoE协议相 ...
- NOIP 模拟 $16\; \rm Lost My Music$
题解 \(by\;zj\varphi\) 一道凸包的题 设 \(\rm dep_u\) 表示节点 \(u\) 的深度,那么原式就可化为 \(-\frac{c_v-c_u}{dep_v-dep_u}\) ...
- git flow版本
feature 分支:开发者进行功能开发的分支. develop 分支:对开发的功能进行集成的分支. release 分支:负责版本发布的分支. hotfix 分支:对线上缺陷进行修复工作的分支,热修 ...
- .NET Core 微服务学习与实践系列文章目录索引(2019版)
参考网址: https://archy.blog.csdn.net/article/details/103659692 2018年,我开始学习和实践.NET Core,并开始了微服务的学习,以及通过各 ...
- SpringCloud分布式配置中心Config
统一管理所有配置. 1.微服务下的分布式配置中心 简介:讲解什么是配置中心及使用前后的好处 什么是配置中心: 一句话:统一管理配置, 快速切换各个环境的配置 相关产品: 百度的disconf 地址:h ...