JAVA中日期转换SimpleDateFormat和DateTimeFormatter

一. SimpleDateFormat
想必大家对 SimpleDateFormat 并不陌生。SimpleDateFormat 是 Java 中一个非常常用的类,他是以区域敏感的方式格式化和解析日期的具体类。 它允许格式化 (date -> text)、语法分析 (text -> date)和标准化。

1. 日期时间格式(例如:yyyy-MM-dd HH:mm:ss)

å¨è¿éæå¥å¾çæè¿°
2. 实例说明(Date–>Text)
SimpleDateFormat myFmt = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
SimpleDateFormat myFmt1 = new SimpleDateFormat("yy/MM/dd HH:mm");
SimpleDateFormat myFmt2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//等价于now.toLocaleString()
SimpleDateFormat myFmt3 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 E ");
SimpleDateFormat myFmt4 = new SimpleDateFormat("一年中的第 D 天 一年中第w个星期 一月中第W个星期 在一天中k时 z时区");
Date now = new Date();
System.out.println(myFmt.format(now));
System.out.println(myFmt1.format(now));
System.out.println(myFmt2.format(now));
System.out.println(myFmt3.format(now));
System.out.println(myFmt4.format(now));
System.out.println(now.toGMTString());
System.out.println(now.toLocaleString());
System.out.println(now.toString());

å¨è¿éæå¥å¾çæè¿°


3. 实例说明(Text–>Date)
 String time1 = "2018年06月19日 23时10分05秒";
 String time2 = "18/06/19 23:10";
 String time3 = "2018-06-19 23:10:05";
 String time4 = "2018年06月19日 23时10分05秒 星期二";        SimpleDateFormat myFmt = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒");
 SimpleDateFormat myFmt1 = new SimpleDateFormat("yy/MM/dd HH:mm");
 SimpleDateFormat myFmt2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//等价于now.toLocaleString()
 SimpleDateFormat myFmt3 = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒 E");
 Date date1 = null;
 try {
     date1 = myFmt.parse(time1);
 } catch (ParseException e) {
     e.printStackTrace();
 }
 System.out.println(date1);

 Date date2 = null;
 try {
     date2 = myFmt1.parse(time2);
 } catch (ParseException e) {
     e.printStackTrace();
 }
 System.out.println(date2);

 Date date3 = null;
 try {
     date3 = myFmt2.parse(time3);
 } catch (ParseException e) {
     e.printStackTrace();
 }
 System.out.println(date3);

 Date date4 = null;
 try {
     date4 = myFmt3.parse(time4);
 } catch (ParseException e) {
     e.printStackTrace();
 }
 System.out.println(date4);
结果:

å¨è¿éæå¥å¾çæè¿°


4.线程不安全
多个线程同时对一个SimpleDateFormat对象进行操作的时候,就会出现错乱。
例如全局的private static final SimpleDateFormat df = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”);
查看SimpleDateFormat 源码:calendar为protected类型的全局变量,当线程A设置了calendar.setTime(date);
线程B又设置了一次,那么calendar值就变了,线程A在subFormat方法中用到的calendar就不是自己设置的而是线程B设置的。

å¨è¿éæå¥å¾çæè¿°

这个问题背后隐藏着一个更为重要的问题–无状态:无状态方法的好处之一,就是它在各种环境下,都可以安全的调用。衡量一个方法是否是有状态的,就看它是否改动了其它的东西,比如全局变量,比如实例的字段。format 方法在运行过程中改动了 SimpleDateFormat 的 calendar 字段,所以,它是有状态的。

5. 解决办法
1.每个线程使用的时候创建新的SimpleDateFormat,将有线程安全问题的对象由共享变为局部私有都能避免多线程问题
2.使用同步:同步 SimpleDateFormat 对象

public class DateSyncUtil {
        private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        public static String formatDate(Date date) throws ParseException {
            synchronized (sdf) {
                return sdf.format(date);
            }
        }
        public static Date parse(String strDate) throws ParseException {
            synchronized (sdf) {
                return sdf.parse(strDate);
            }
        }
}
说明:当线程较多时,当一个线程调用该方法时,其他想要调用此方法的线程就要 block 等待,多线程并发量大的时候会对性能有一定的影响
 
3.使用 ThreadLocal

public class DateSyncUtil {
        private ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>(){
            @Override
            protected DateFormat initialValue() {
                return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            }
        };
        public Date parse(String dateStr){
            return threadLocal.get().parse(dateStr);
        }
        public String format(Date date) {
            return threadLocal.get().format(date);
        }
 }
 说明:使用 ThreadLocal, 也是将共享变量变为独享,线程独享肯定能比方法独享在并发环境中能减少不少创建对象的开销。如果对性能要求比较高的情况下,一般推荐使用这种方法。


二. DateTimeFormatter
Java 8 提供了新的日期时间 API,其中包括用于日期时间格式化的 DateTimeFormatter,它与 SimpleDateFormat 最大的区别在于:DateTimeFormatter 是线程安全的,而 SimpleDateFormat 并不是线程安全。

//Text-->Date
String dateStr= "2018-06-20 11:25:56";
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.parse(dateStr, dateTimeFormatter);
ZoneId zone = ZoneId.systemDefault();
Instant instant = localDateTime.atZone(zone).toInstant();
Date date = Date.from(instant);

//Date-->Text
Date date = new Date();
Instant instant = date.toInstant();
ZoneId zone = ZoneId.systemDefault();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String nowStr = localDateTime.format(format);
System.out.println(nowStr);

//LocalDateTime获取毫秒
System.out.println(localDateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli());

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DateTimeFormatterSimpleDateFormat是用于日期和时间格式化的类,但它们有一些重要的区别。 1. 线程安全性: - SimpleDateFormat不是线程安全的。如果多个线程同时使用同一个SimpleDateFormat对象进行日期和字符串的转换,可能会导致异常。 - DateTimeFormatter是线程安全的。多个线程可以同时使用同一个DateTimeFormatter对象进行日期和字符串的转换,而不会出现线程安全问题。 2. API设计: - SimpleDateFormatJava早期提供的日期和时间格式化类,其API设计相对简单。 - DateTimeFormatterJava 8引入的新类,其API设计更加灵活和强大。它提供了丰富的方法来处理日期和时间的格式化和解析,可以满足更多的需求。 3. 格式化模式: - SimpleDateFormat使用一种基于模式字符串的方式来定义日期和时间的格式化模式。例如,"yyyy-MM-dd HH:mm:ss"表示年份-月份-日期 小时:分钟:秒。 - DateTimeFormatter使用一种基于模式字符的方式来定义日期和时间的格式化模式,但它还提供了一些预定义的格式化模式,如ISO_DATE、ISO_TIME、ISO_DATE_TIME等。 4. 性能: - SimpleDateFormat的性能相对较低,特别是在多线程环境下。 - DateTimeFormatter的性能相对较高,特别是在多线程环境下。它使用了一些优化技术,如缓存和线程安全的解析器。 综上所述,DateTimeFormatter相比SimpleDateFormat具有更好的线程安全性、更灵活的API设计和更高的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值