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));
}
}