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()));
     }
    ​
    }
    
  • 相关阅读:
    投影变换 到 uv坐标 xy/w 齐次坐标
    GdiPlus[19]: IGPPathGradientBrush 之 SetCenterPoint
    GdiPlus[21]: IGPPathGradientBrush 之 InterpolationColors
    GdiPlus[24]: IGPPrivateFontCollection: 分别从文件和内存加载字体
    GdiPlus[23]: IGPFontFamily
    GdiPlus[25]: IGPInstalledFontCollection: 获取已安装的字体列表
    GdiPlus[20]: IGPPathGradientBrush 之 SetFocusScales
    GdiPlus[22]: IGPFont
    可爱的 CreateMessageDialog
    GdiPlus[18]: IGPPathGradientBrush 之 CenterColor、SurroundColors
  • 原文地址:https://www.cnblogs.com/happy4java/p/11205918.html
Copyright © 2011-2022 走看看