日期字符串转换格式化的总结

基础代码

   /**
     * 时间转字符串
     * @param date
     * @param format
     * @return
     */
    public static String format(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

   /**
     * 字符串转时间
     * @param dateStr
     * @param format
     * @return
     */
    public static  Date parse(String dateStr,String format){
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Date date=null;
        try {
            date = sdf.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return  date;
    }

注意:

1.SimpleDateFormat是线程不安全。

原因

  // 全局时间对象
   protected Calendar calendar;
 
  // Called from Format after creating a FieldDelegate
    private StringBuffer format(Date date, StringBuffer toAppendTo,
                                FieldDelegate delegate) {
        // Convert input date to time field list
        // 重点是这个位置,calendar是一个全局对象这就导致了并发情况下
        // 多线程设置的date会被覆盖
        // 导致下面的subFormat解析时间时按照被覆盖的数据进行处理
        calendar.setTime(date);

        boolean useDateFormatSymbols = useDateFormatSymbols();

        for (int i = 0; i < compiledPattern.length; ) {
            int tag = compiledPattern[i] >>> 8;
            int count = compiledPattern[i++] & 0xff;
            if (count == 255) {
                count = compiledPattern[i++] << 16;
                count |= compiledPattern[i++];
            }

            switch (tag) {
            case TAG_QUOTE_ASCII_CHAR:
                toAppendTo.append((char)count);
                break;

            case TAG_QUOTE_CHARS:
                toAppendTo.append(compiledPattern, i, count);
                i += count;
                break;

            default:
            // 他的代码太多了就不粘贴了 大家自己看下
                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
                break;
            }
        }
        return toAppendTo;
    }

解决办法

1.最简单的解决方案我们可以把static去掉,这样每个新的线程都会有一个自己的sdf实例,从而避免线程安全的问题。然而,使用这种方法,在高并发的情况下会大量的new sdf以及销毁sdf,这样是非常耗费资源的。

2.下面是一个使用ThreadLocal解决sdf多线程问题的例子

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 
 * @version $Id$
 */
public class DateUtil {

    /** 锁对象 */
    private static final Object lockObj = new Object();

    /** 存放不同的日期模板格式的sdf的Map */
    private static Map<String, ThreadLocal<SimpleDateFormat>> sdfMap = new HashMap<String, ThreadLocal<SimpleDateFormat>>();

    /**
     * 返回一个ThreadLocal的sdf,每个线程只会new一次sdf
     * 
     * @param pattern
     * @return
     */
    private static SimpleDateFormat getSdf(final String pattern) {
        ThreadLocal<SimpleDateFormat> tl = sdfMap.get(pattern);

        // 此处的双重判断和同步是为了防止sdfMap这个单例被多次put重复的sdf
        if (tl == null) {
            synchronized (lockObj) {
                tl = sdfMap.get(pattern);
                if (tl == null) {
                    // 只有Map中还没有这个pattern的sdf才会生成新的sdf并放入map
                    System.out.println("put new sdf of pattern " + pattern + " to map");

                    // 这里是关键,使用ThreadLocal<SimpleDateFormat>替代原来直接new SimpleDateFormat
                    tl = new ThreadLocal<SimpleDateFormat>() {

                        @Override
                        protected SimpleDateFormat initialValue() {
                            System.out.println("thread: " + Thread.currentThread() + " init pattern: " + pattern);
                            return new SimpleDateFormat(pattern);
                        }
                    };
                    sdfMap.put(pattern, tl);
                }
            }
        }

        return tl.get();
    }

    /**
     * 是用ThreadLocal<SimpleDateFormat>来获取SimpleDateFormat,这样每个线程只会有一个SimpleDateFormat
     * 
     * @param date
     * @param pattern
     * @return
     */
    public static String format(Date date, String pattern) {
        return getSdf(pattern).format(date);
    }

    public static Date parse(String dateStr, String pattern) throws ParseException {
        return getSdf(pattern).parse(dateStr);
    }

}

2.yyyy和YYYY的区别

Y表示的是本周所属的年份,Java语言中一周从周日开始,周六结束,假如本周跨年,那么这一周获取的年份都是第二年。所以正常情况下都是用y

3.HH和hh的区别

H是24小时制格式化时间

h是12小时制格式化时间

4.常见的时间表达式

以下来自SimpleDateFormat的注释

Date and Time PatternResult
yyyy.MM.dd G 'at' HH:mm:ss z2001.07.04 AD at 12:08:56 PDT
"EEE, MMM d, ''yy"
Wed, Jul 4, '01
"h:mm a"
12:08 PM
"hh 'o''clock' a, zzzz"12 o'clock PM, Pacific Daylight Time
"K:mm a, z"
0:08 PM, PDT
"yyyyy.MMMMM.dd GGG hh:mm aaa"02001.July.04 AD 12:08 PM
"EEE, d MMM yyyy HH:mm:ss Z"
Wed, 4 Jul 2001 12:08:56 -0700
"yyMMddHHmmssZ"
010704120856-0700
"yyyy-MM-dd'T'HH:mm:ss.SSSZ"
20

2001-07-04T12:08:56.235-0700
"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"2001-07-04T12:08:56.235-07:00
"YYYY-'W'ww-u"
2001-W27-3

5.SimpleDateFormat Locale 参数 区别

SimpleDateFormat s1 = new SimpleDateFormat("GGGG yyyy/MMMM/dd HH:mm:ss EEE aaa  zzzz",Locale.CHINA);
SimpleDateFormat s2 = new SimpleDateFormat("GGGG yyyy/MMMM/dd HH:mm:ss EEE aaa  zzzz",Locale.US);
 

//结果

公元 2016/三月/27 23:32:10 星期日 下午  中国标准时间
AD 2016/March/27 23:32:10 Sun PM  China Standard Time

String datdString1="Tue Feb 14 2017 14:06:32 GMT+0800";
String  datdString2="Fri Mar 11 09:06:46 +0800 2022";
datdString1 = datdString1.replace("GMT", "").replaceAll("\\(.*\\)", "");
String pattern1 = "EEE MMM dd yyyy hh:mm:ss z";
String pattern2 = "EEE MMM dd hh:mm:ss z yyyy";
SimpleDateFormat format1 = new SimpleDateFormat(pattern1, Locale.ENGLISH);
SimpleDateFormat format2 = new SimpleDateFormat(pattern2, Locale.ENGLISH);
Date dateTrans1 = format1.parse(datdString1);
Date dateTrans2 = format2.parse(datdString2);
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(dateTrans1));
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(dateTrans2));
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值