zoukankan      html  css  js  c++  java
  • 还在用SimpleDateFormat?Java8都发布N年了,转LocalDateTime吧

    前言

    Java8发布,已有数年之久,但是发现很多人都还是坚持着用SimpleDateFormat和Date进行时间操作。SimpleDateFormat这个类不是线程安全的,在使用的时候稍不注意,就会产生致命的问题。Date这个类,是可以重新设置时间的,这对于一些类内部的属性来说,是非常不安全的。

    SimpleDateFormat是线程不安全的类

    在阿里巴巴规约手册里,强制规定SimpleDateFormat是线程不安全的类,当定义为静态变量时,必须加锁处理。忽略线程安全问题,正是大多数Java初学者在进行时间转化时容易踩坑的点。

    还在用SimpleDateFormat?Java8都发布N年了,转LocalDateTime吧

    Date属性可以重新设置时间

    比如有User.java如下:

    public class User {
    ​
     private String username;
    ​
     private Date birthday;
    ​
     public User(String username, Date birthday) {
     this.username = username;
     this.birthday = birthday;
     }
    ​
     public String getUsername() {
     return username;
     }
    ​
     public void setUsername(String username) {
     this.username = username;
     }
    ​
     public Date getBirthday() {
     return birthday;
     }
    ​
     public void setBirthday(Date birthday) {
     this.birthday = birthday;
     }
    }
    

    我们实例化该User

    public class Main {
    ​
     public static void main(String[] args) {
     User user = new User("happyjava", new Date());
     }
    ​
    }
    

    这当然没什么问题,但是我可以通过user.getBirthday()方法获取到birthday的引用,从而修改直接修改birthday的值。如下:

    public static void main(String[] args) {
     User user = new User("happyjava", new Date());
     System.out.println(user.getBirthday());
     Date birthday = user.getBirthday();
     birthday.setTime(11111111L);
     System.out.println(user.getBirthday());
    }
    

    输出结果如下:

    还在用SimpleDateFormat?Java8都发布N年了,转LocalDateTime吧

    这里可以看到,user对象的birthday属性被修改掉了。这也是Date对象的弊端所在,我们可以通过改写getter方法,使它返回一个新的Date对象即可解决,如下:

     public Date getBirthday() {
    // return birthday;
     return new Date(birthday.getTime());
     }
    

    切记这里是不可以用clone方法来生成返回一个新的Date对象的,因为Date类可以被继承,你不能确定调用者是否给birthday设置了一个Date的子类。

    Java8提供的新的时间类库LocalDateTime

    Java8提供了LocalDateTime来替代传统的Date来处理时间,下面,我们就来探讨下这个类库的使用方法吧。

    1.获取当前时间

    可以通过 LocalDateTime localDateTime = LocalDateTime.now();方法来获取当前时间,测试如下:

    @Test
    public void testNow() {
     LocalDateTime localDateTime = LocalDateTime.now();
     System.out.println(localDateTime);
    }
    

    输出结果

    2019-05-06T22:25:07.309
    

    2.根据时间戳初始化时间

    @Test
    public void testNewFromTimestamp() {
     Instant instant = Instant.ofEpochMilli(System.currentTimeMillis());
     LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.of("+8"));
     System.out.println(dateTime);
    }
    

    这里的+8意思是东八区,下同。

    输出结果:

    2019-05-06T22:27:34.567
    

    3.根据字符串获取时间

    可以使用LocalDateTime.parse方法对字符串进行转化成时间,如果不传pattern,默认是2019-05-06T11:16:12.361格式。

    @Test
    public void testNewFromString() {
     // 1.默认格式 2019-05-06T11:16:12.361
     String dateStr = "2019-05-06T11:16:12.361";
     LocalDateTime localDateTime = LocalDateTime.parse(dateStr);
     System.out.println(localDateTime);
     // 2. 自定义格式
     String pattern = "yyyy-MM-dd HH:mm:ss";
     dateStr = "2019-01-01 12:12:12";
     localDateTime = LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(pattern));
     System.out.println(localDateTime);
    }
    

    输出结果:

    2019-05-06T11:16:12.361
    2019-01-01T12:12:12
    

    4.时间转化成字符串

    可以通过DateTimeFormatter的format方法,将LocalDateTime转化成字符串。

    @Test
    public void testToString() {
     LocalDateTime now = LocalDateTime.now(ZoneId.of("+8"));
     String pattern = "yyyy-MM-dd HH:mm:ss";
     DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
     String format = formatter.format(now);
     System.out.println(format);
    }
    

    输出结果:

    2019-05-06 22:33:03
    

    5.LocalDateTime转时间戳

    @Test
    public void testDateToTimeMillis() {
     LocalDateTime dateTime = LocalDateTime.now();
     long epochMilli = dateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli();
     System.out.println(epochMilli);
    }
    

    输出结果:

    1557153504304
    

    总结

    因为DateTimeFormatter是线程安全的,所以在实际使用LocalDateTime的时候,可以把DateTimeFormatter定义成静态常量的方式进行使用。以上列举了比较常用的时间操作,LocalDateTime还可以做很多事情,这个就让读者自行去挖掘吧。我自己封装了个LocalDateTime工具类,只做过简单的自测,大家可以参考一下:

    package happy.localdatetime;
    ​
    ​
    import java.time.Instant;
    import java.time.LocalDateTime;
    import java.time.ZoneOffset;
    import java.time.format.DateTimeFormatter;
    ​
    /**
     * @author Happy
     */
    public class DateTimeUtils {
    ​
     private DateTimeUtils() {
     }
    ​
     private final static String COMMON_PATTERN = "yyyy-MM-dd HH:mm:ss";
    ​
     private final static DateTimeFormatter COMMON_FORMATTER = DateTimeFormatter.ofPattern(COMMON_PATTERN);
    ​
     private final static ZoneOffset DEFAULT_ZONE_OFFSET = ZoneOffset.of("+8");
    ​
     /**
     * 默认 yyyy-MM-dd HH:mm:ss 格式
     */
     public static String dateToString(LocalDateTime dateTime) {
     assert dateTime != null;
     return COMMON_FORMATTER.format(dateTime);
     }
    ​
     /**
     * 默认 yyyy-MM-dd HH:mm:ss 格式
     */
     public static LocalDateTime stringToDate(String dateStr) {
     assert dateStr != null;
     return LocalDateTime.parse(dateStr, COMMON_FORMATTER);
     }
    ​
     public static String dateToString(LocalDateTime dateTime, DateTimeFormatter formatter) {
     assert dateTime != null;
     return formatter.format(dateTime);
     }
    ​
     public static LocalDateTime stringToDate(String dateStr, DateTimeFormatter formatter) {
     assert dateStr != null;
     return LocalDateTime.parse(dateStr, formatter);
     }
    ​
     public static long dateToTimeMillis(LocalDateTime dateTime) {
     assert dateTime != null;
     return dateTime.toInstant(DEFAULT_ZONE_OFFSET).toEpochMilli();
     }
    ​
     public static LocalDateTime timeMillisToDate(long timeMillis) {
     Instant instant = Instant.ofEpochMilli(timeMillis);
     return LocalDateTime.ofInstant(instant, DEFAULT_ZONE_OFFSET);
     }
    ​
     public static void main(String[] args) {
     String s = dateToString(LocalDateTime.now());
     System.out.println(s);
     System.out.println();
     String dateStr = "2019-01-01 12:12:12";
     LocalDateTime localDateTime = stringToDate(dateStr);
     System.out.println(localDateTime);
     System.out.println();
     System.out.println(dateToTimeMillis(localDateTime));
     System.out.println();
     System.out.println(timeMillisToDate(System.currentTimeMillis()));
     }
    ​
    }
    
  • 相关阅读:
    结巴分词 0.14 版发布,Python 中文分词库
    Lazarus 1.0.2 发布,Pascal 集成开发环境
    Android全屏 去除标题栏和状态栏
    服务器日志现 Android 4.2 传将添多项新特性
    Percona XtraBackup 2.0.3 发布
    长平狐 Android 强制设置横屏或竖屏 设置全屏
    NetBeans 7.3 Beta 发布,全新的 HTML5 支持
    CppDepend现在已经支持Linux
    GromJS 1.7.18 发布,服务器端的 JavaScript
    Apache OpenWebBeans 1.1.6 发布
  • 原文地址:https://www.cnblogs.com/happy4java/p/11205918.html
Copyright © 2011-2022 走看看