Java中日期格式化的实现算法

package com.study.test;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 实现Java中日期的简单格式化,支持以下字段:
 * yyyy:年
 * MM:月
 * dd:日
 * hh:1~12小时制(1-12)
 * HH:24小时制(0-23)
 * mm:分
 * ss:秒
 * S:毫秒
 * E:星期几
 * a: 上午/下午
 */
public class DateFormatter implements Serializable {

    private static Map tokenFieldMap = new HashMap<>();
    private static final int NO_LENGTH = 1000;            //不用自动补0的属性,例如毫秒
    private static final int LOCALE = NO_LENGTH + 1000;  //用Locale获取值的属性,例如星期

    //tokenFieldMap,将字符与Calendar中的field对应
    static {
        tokenFieldMap.put('y', Calendar.YEAR);
        tokenFieldMap.put('M', Calendar.MONTH);
        tokenFieldMap.put('d', Calendar.DATE);
        tokenFieldMap.put('h', Calendar.HOUR);
        tokenFieldMap.put('H', Calendar.HOUR_OF_DAY);
        tokenFieldMap.put('m', Calendar.MINUTE);
        tokenFieldMap.put('s', Calendar.SECOND);
        tokenFieldMap.put('a', Calendar.AM_PM + LOCALE);
        tokenFieldMap.put('S',Calendar.MILLISECOND + NO_LENGTH);
        tokenFieldMap.put('E',Calendar.DAY_OF_WEEK + LOCALE);
    }

    private static class Token implements Serializable {
        int field;   // Calendar中的field对应
        int length; // 自动补0的长度

        public Token(int field, int length) {
            this.field = field;
            this.length = length;
        }
    }

    //解析出的token,可能是token或者是String
    private List tokens;

    private String format;

    public DateFormatter(String format) {
        this.format = format;
        parseTokens();
    }

    public String getFormat() {
        return format;
    }

    public String format(Date date){
        if(date == null){
            throw new IllegalArgumentException("null argument!");
        }
        StringBuilder sb = new StringBuilder();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        for(Object token : tokens){
            if(token instanceof Token){
                token2String(sb,(Token)token,calendar);
            }else{
                sb.append(token);
            }
        }
        return sb.toString();
    }

    private void parseTokens() {
        tokens = new ArrayList<>();
        StringBuilder temp = new StringBuilder();
        for (int i = 0; i < format.length(); i++) {
            char c = format.charAt(i);
            Integer field = tokenFieldMap.get(c);
            if (field != null) {
                checkStr(temp);
                if(field < NO_LENGTH){
                    int num = 1;
                    while (i < format.length() - 1 && format.charAt(i + 1) == c) {
                        i++;
                        num++;
                    }
                    tokens.add(new Token(field, num));
                }else{
                    tokens.add(new Token(field, 0));
                }
            }else{
                temp.append(c);
            }
        }
        checkStr(temp);
    }

    private void checkStr(StringBuilder temp) {
        if (temp.length() > 0) {
            tokens.add(temp.toString());
            temp.setLength(0);
        }
    }

    @SuppressWarnings("MagicConstant")
    private void token2String(StringBuilder sb, Token token, Calendar calendar){
        int field = token.field;
        if(field > LOCALE){
            sb.append(calendar.getDisplayName(field  - LOCALE,Calendar.SHORT,Locale.getDefault()));
        }else if(field > NO_LENGTH){
            sb.append(calendar.get(field - NO_LENGTH));
        }else{
            int val = calendar.get(field);
            if(field == Calendar.MONTH){
                val++;  //如果是月,取出的范围是0-11,需要加一
            }
            String value = String.valueOf(val);
            if(value.length() > token.length){
                if(token.field == Calendar.YEAR){       //如果是年,才截取,比如2018可以截取成18年,小时分钟不能截取
                    sb.append(value.substring(value.length() - token.length));
                }else{
                    sb.append(value);
                }
            }else{
                for(int i=0;i//根据length自动补0
                    sb.append('0');
                }
                sb.append(value);
            }
        }
    }

    public static void main(String[] args)throws Exception {
        String fmt = "yy-M-dd a h:m:s E";
        Date date = new Date();

        DateFormatter formatter = new DateFormatter(fmt);
        String result = formatter.format(date);
        System.out.println(result);

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(fmt);
        System.out.println(simpleDateFormat.format(date));

        //性能测试
        long t1 = System.currentTimeMillis();
        for(int i=0;i){
            simpleDateFormat.format(new Date(System.currentTimeMillis() + i * 3000 ));
        }
        long t2 = System.currentTimeMillis();
        for(int i=0;i){
            formatter.format(new Date(System.currentTimeMillis() + i * 3000));
        }
        long t3 = System.currentTimeMillis();

        System.out.println("formatter cost : " + (t3 - t2));
        System.out.println("java format cost : " + (t2 - t1));

    }
},>

Original: https://www.cnblogs.com/xcr1234/p/9657042.html
Author: &nbsp;
Title: Java中日期格式化的实现算法

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/620534/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 「学习笔记」字符串基础:Hash,KMP与Trie

    「学习笔记」字符串基础:Hash,KMP与Trie 点击查看目录 「学习笔记」字符串基础:Hash,KMP与Trie Hash 算法 代码 KMP 算法 前置知识:(\text{B…

    数据结构和算法 2023年6月8日
    0198
  • 【学习笔记】网络流

    前言:网络流就像自来水厂到你家的水管,自来水厂(源点S) 源源不断的提供水,水通过不同水管 汇集于你家(设自来水厂的水全到你家, 汇点T)。自来水厂到你家的水管网是一个复杂的有向图…

    数据结构和算法 2023年6月12日
    079
  • CF1610C-Keshi Is Throwing a Party

    设 (f[j]) 中的 (j) 表示你所选出的数列的已知最大长度限制,而且是只管右限制的最大长度限制。 比如说第一个数右限制是 (4),那么最大长度限制是 (5),因为要算上它本身…

    数据结构和算法 2023年6月12日
    073
  • 【AcWing】第 62 场周赛 【2022.07.30】

    给定一个长度为 (n) 的数组 (r_1,r_2,…,r_n)。 请你找到其中的三个元素 (r_a,r_b,r_c),使得 (r_a < r_b < r_c…

    数据结构和算法 2023年6月8日
    074
  • 复杂度分析

    复杂度 复杂度分析是数据结构与算法的核心精髓,指在不依赖硬件、宿主环境、数据集的情况下,粗略推导,考究出算法的效率和资源消耗情况, 包括时间复杂度和空间复杂度 时间复杂度 首先从C…

    数据结构和算法 2023年6月8日
    0125
  • MySQL的主从复制和分库分表初探

    主从复制 + 分库分表 要讲主从复制,首先来看看MySQL自带的日志文件。 日志 错误日志 错误日志是 MySQL 中最重要的日志之一,它记录了当 mysqld 启动和停止时,以及…

    数据结构和算法 2023年6月8日
    098
  • 初识设计模式-适配器模式

    适配器在生活中经常见到,如手机、笔记本电脑的电源适配器,USB 转接头都是常见的适配器。 在设计模式当中,适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。 在类适配器模…

    数据结构和算法 2023年6月8日
    097
  • 剑指 Offer II 001. 整数除法

    太恶心了这题,处理边界处理了半天,这里提到不能用 *, /, %,所以就考虑了使用减法来模拟除法。思路是首先需要做特判,比如 a被除数等于0,可以直接返回, b除数等于0,则不是有…

    数据结构和算法 2023年6月7日
    075
  • udp可靠性传输设计之kcp

    udp传输本身是不可靠的,要做到可靠性传输,需要参考tcp的原理在用户层进行修改,所以在可靠性设计之前,需要弄明白tcp传输的一些原理。 tcp传输有一些机制可以保证可靠性传输:1…

    数据结构和算法 2023年6月16日
    0120
  • 初识C++01:初探C++

    c++介绍 c++支持面向过程编程(如c),面向对象编程(OOP)和泛型编程; c/c++编译器比较多,window下是微软编译器cl.exe,Linux机下是GCC编译器,mac…

    数据结构和算法 2023年6月12日
    093
  • 18. 二叉树和二叉搜索树的最近公共祖先

    📃 题目一描述 题目链接:236. 二叉树的最近公共祖先 🔔 解题思路 思考两个节点散布在二叉树上,应该是回溯 自底向上 遍历,才会得到结果; 要明白有一种情况是:必有也仅存在这样…

    数据结构和算法 2023年6月12日
    077
  • 相机控制, 相机跟随

    实现的功能 (1) 滚轮拉近, 推远相机(带惯性) (2) 鼠标左键左右,上下转动相机(带惯性) (3) 相机跟随角色 待实现功能 (1) 转动相机时,如果相机和跟随角色间出现了障…

    数据结构和算法 2023年6月7日
    084
  • copy依赖资源到指定位置

    using System.IO; using UnityEditor; using UnityEngine; namespace xui.Editor { public class…

    数据结构和算法 2023年6月7日
    078
  • [LC1161]最大层内元素和

    题目概述 给你一个二叉树的根节点 root。设根节点位于二叉树的第 1 层,而根节点的子节点位于第 2 层,依此类推。 请返回层内元素之和 最大 的那几层(可能只有一层)的层号,并…

    数据结构和算法 2023年6月8日
    0117
  • springmvc controller自动打印出入参数以及打印其他有用信息

    com.xxx包下加了@RestController注解的controller 打印的日志规格如下:包含:ip地址、url、全限定类名+方法名、请求时间、请求参数(支持多个)、响应…

    数据结构和算法 2023年6月7日
    083
  • 欧拉回路

    (0.) 由来 哥尼斯堡七桥问题。如图 在所有桥都只能走一遍的前提下,如何才能把这个地方所有的桥都走遍?。显然是不行。如果可以满足一笔画,必须使除了起点和终点的所有点的度数必须是偶…

    数据结构和算法 2023年6月12日
    087
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球