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-----一种高效的中文日期格式化和解析方法

上一篇:C#析构函数(方法)


下一篇:win10电脑时间同步设置方法