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<Character, Integer> 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<Object> 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<token.length - value.length();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<30000;i++){
            simpleDateFormat.format(new Date(System.currentTimeMillis() + i * 3000 ));
        }
        long t2 = System.currentTimeMillis();
        for(int i=0;i<30000;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));

    }
}

原文地址:https://www.cnblogs.com/xcr1234/p/9657042.html

时间: 2024-10-28 19:53:03

Java中日期格式化的实现算法的相关文章

Java中日期格式化YYYY-DD的坑

摘自:https://www.cnblogs.com/tonyY/p/12153335.html Java中日期格式化YYYY-DD的坑 2020-01-05 19:27  兔子托尼啊  阅读(115)  评论(0)  编辑  收藏 写这篇博文是记录下跨年的bug.去年隔壁组的小伙伴就是计算两个日期之间间隔的天数,因为跨年的原因计算有误. 当时测试组的小姐姐也没有模拟出来这种场景,导致上生产环境直接影响线上的数据. 今天逛技术论论坛正好遇到Java日期的操作bug. 1 yyyy 和 YYYY

(转)java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)

java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明);部分资料参考网络资源 1. java向MySQL插入当前时间的四种方式 第一种:将java.util.Date类型的时间转成mysql数据库识别的java.sql.Date类型时间 注:java.util.Date是java.sql.Date的父类 Date time= new java.sql.Date(newjava.util.Date().getTime()); 第二种: java用PreparedS

java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明)

java向MySQL插入当前时间的四种方式和java时间日期格式化的几种方法(案例说明);部分资料参考网络资源 1. java向MySQL插入当前时间的四种方式 第一种:将java.util.Date类型的时间转成mysql数据库识别的java.sql.Date类型时间 注:java.util.Date是java.sql.Date的父类 Date time= new java.sql.Date(newjava.util.Date().getTime()); 第二种: java用PreparedS

Java中日期的总结

#####1.日期 日期:主要使用的是*java.util.Date* 以及*java.sql.Date* , sql中的Date是util中Date的子类,关系如下,但是如果直接转换的话会出现Cast转换错误. - java.lang.Object - java.util.Date - java.sql.Date 之间的转换可以通过如: ```javajava.util.Date utildate=new java.util.Date(System.getCurrentTime());java

java中日期格式的转换和应用

java中主要有3个类用于日期格式转换    DateFormat .SimpleDateFormat.Calendar 1.SimpleDateFormat 该类是DateFormat的子类,一般日期的格式化都是实例化该类实现 具体应用如下 package com.gree.java; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.log

Java中的数据结构及排序算法

(明天补充) 主要是3种接口:List Set Map List:ArrayList,LinkedList:顺序表ArrayList,链表LinkedList,堆栈和队列可以使用LinkedList模拟 Set:HashSet没有重复记录的集合 Map:HashMap就是哈希表 Collection ├List │├LinkedList │├ArrayList │└Vector │ └Stack └Set Map ├Hashtable ├HashMap └WeakHashMap 数据结构参考链接

Java中日期类型和mysql中日期类型进行整合

1. java与mysql中日期.时间类型总结: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 mysql(版本:5.1.50)的时间日期类型如下: datetime 8bytes xxxx-xx-xx xx:xx:xx 1000-01-01 00:00:00到9999-12-31 23:59:59 timestamp 4bytes xxxx-xx-xx xx:xx:xx 1970-01-01 00:00:01到2038 date 3bytes xxxx-x

Java 中日期的几种常见操作 —— 取值、转换、加减、比较

Java 的开发过程中免不了与 Date 类型纠缠,准备总结一下项目经常使用的日期相关操作,JDK 版本 1.7,如果能够帮助大家节约那么几分钟起身活动一下,去泡杯咖啡,便是极好的,嘿嘿.当然,我只提供了可行的解决方案,并不保证是最佳实践,欢迎讨论. 1. 日期取值 在旧版本 JDK 的时代,有不少代码中日期取值利用了 java.util.Date 类,但是由于 Date 类不便于实现国际化,其实从 JDK1.1 开始,就更推荐使用 java.util.Calendar 类进行时间和日期方面的处

JAVA中日期处理

一.日期和long类型数据的相互转换 public class Hello { public static void main(String[] args) throws Exception { //日期转换为long Date currentDateInDate = new Date(); long currentDateInLong = currentDateInDate.getTime(); System.out.println(currentDateInDate); System.out