前言

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

SimpleDateFormat是线程不安全的类

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

Date属性可以重新设置时间

比如有User.java如下:

  1. public class User {

  2. private String username;

  3. private Date birthday;

  4. public User(String username, Date birthday) {
  5. this.username = username;
  6. this.birthday = birthday;
  7. }

  8. public String getUsername() {
  9. return username;
  10. }

  11. public void setUsername(String username) {
  12. this.username = username;
  13. }

  14. public Date getBirthday() {
  15. return birthday;
  16. }

  17. public void setBirthday(Date birthday) {
  18. this.birthday = birthday;
  19. }
  20. }

我们实例化该User

  1. public class Main {

  2. public static void main(String[] args) {
  3. User user = new User("happyjava", new Date());
  4. }

  5. }

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

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

输出结果如下:

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

  1. public Date getBirthday() {
  2. // return birthday;
  3. return new Date(birthday.getTime());
  4. }

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

Java8提供的新的时间类库LocalDateTime

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

1.获取当前时间

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

  1. @Test
  2. public void testNow() {
  3. LocalDateTime localDateTime = LocalDateTime.now();
  4. System.out.println(localDateTime);
  5. }

输出结果

  1. 2019-05-06T22:25:07.309

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

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

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

输出结果:

  1. 2019-05-06T22:27:34.567

3.根据字符串获取时间

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

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

输出结果:

  1. 2019-05-06T11:16:12.361
  2. 2019-01-01T12:12:12

4.时间转化成字符串

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

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

输出结果:

  1. 2019-05-06 22:33:03

5.LocalDateTime转时间戳

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

输出结果:

  1. 1557153504304

总结

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

  1. package happy.localdatetime;


  2. import java.time.Instant;
  3. import java.time.LocalDateTime;
  4. import java.time.ZoneOffset;
  5. import java.time.format.DateTimeFormatter;

  6. /**
  7. * @author Happy
  8. */
  9. public class DateTimeUtils {

  10. private DateTimeUtils() {
  11. }

  12. private final static String COMMON_PATTERN = "yyyy-MM-dd HH:mm:ss";

  13. private final static DateTimeFormatter COMMON_FORMATTER = DateTimeFormatter.ofPattern(COMMON_PATTERN);

  14. private final static ZoneOffset DEFAULT_ZONE_OFFSET = ZoneOffset.of("+8");

  15. /**
  16. * 默认 yyyy-MM-dd HH:mm:ss 格式
  17. */
  18. public static String dateToString(LocalDateTime dateTime) {
  19. assert dateTime != null;
  20. return COMMON_FORMATTER.format(dateTime);
  21. }

  22. /**
  23. * 默认 yyyy-MM-dd HH:mm:ss 格式
  24. */
  25. public static LocalDateTime stringToDate(String dateStr) {
  26. assert dateStr != null;
  27. return LocalDateTime.parse(dateStr, COMMON_FORMATTER);
  28. }

  29. public static String dateToString(LocalDateTime dateTime, DateTimeFormatter formatter) {
  30. assert dateTime != null;
  31. return formatter.format(dateTime);
  32. }

  33. public static LocalDateTime stringToDate(String dateStr, DateTimeFormatter formatter) {
  34. assert dateStr != null;
  35. return LocalDateTime.parse(dateStr, formatter);
  36. }

  37. public static long dateToTimeMillis(LocalDateTime dateTime) {
  38. assert dateTime != null;
  39. return dateTime.toInstant(DEFAULT_ZONE_OFFSET).toEpochMilli();
  40. }

  41. public static LocalDateTime timeMillisToDate(long timeMillis) {
  42. Instant instant = Instant.ofEpochMilli(timeMillis);
  43. return LocalDateTime.ofInstant(instant, DEFAULT_ZONE_OFFSET);
  44. }

  45. public static void main(String[] args) {
  46. String s = dateToString(LocalDateTime.now());
  47. System.out.println(s);
  48. System.out.println();
  49. String dateStr = "2019-01-01 12:12:12";
  50. LocalDateTime localDateTime = stringToDate(dateStr);
  51. System.out.println(localDateTime);
  52. System.out.println();
  53. System.out.println(dateToTimeMillis(localDateTime));
  54. System.out.println();
  55. System.out.println(timeMillisToDate(System.currentTimeMillis()));
  56. }

  57. }

还在用SimpleDateFormat?Java8都发布N年了,转LocalDateTime吧的更多相关文章

  1. CentOS 8 都发布了,你还不会用 nftables?

    原文链接:CentOS 8 都发布了,你还不会用 nftables? 如果你没有生活在上个世纪,并且是云计算或相关领域的一名搬砖者,那你应该听说最近 CentOS 8 官方正式版已经发布了,CentO ...

  2. [转帖]CentOS 8 都发布了,你还不会用 nftables?

    CentOS 8 都发布了,你还不会用 nftables? https://www.cnblogs.com/ryanyangcs/p/11611730.html 改天学习一下 原文链接:CentOS ...

  3. 还在用SimpleDateFormat格式化时间?小心经理锤你

    还在用SimpleDateFormat格式化时间?小心经理锤你 场景 本来开开心心的周末时光,线上突然就疯狂报错,以为程序炸了,截停日志,发现是就是类似下述一段错误 java.lang.NumberF ...

  4. java8新特性LocalDate、LocalTime、LocalDateTime的学习

    以前操作时间都是使用SimpleDateFormat类改变Date的时间格式,使用Calendar类操作时间.但是SimpleDateFormat是线程不安全的,源码如下: private Strin ...

  5. JDK10都发布了,nio你了解多少?

    前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 本来我预想是先来回顾一下传统的IO模式的,将传统的IO模式的相关类理清楚(因为IO的类很多). 但是,发现在整理 ...

  6. 还在使用SimpleDateFormat?

    阅读本文大概需要 3.2 分钟. 前言 日常开发中,我们经常需要使用时间相关类,想必大家对SimpleDateFormat并不陌生.主要是用它进行时间的格式化输出和解析,挺方便快捷的,但是Simple ...

  7. 什么,你还使用 webpack?别人都在用 vite 搭建项目了

    一.vite 到底是干嘛的? vite 实际上就是一个面向现代浏览器,基于 ES module 实现了一个更轻快的项目构建打包工具. vite 是法语中轻快的意思. vite 的特点: 1.轻快的冷服 ...

  8. 还在使用SimpleDateFormat?你的项目崩没?

    如果是在多线程环境下,就需要注意了. 要点: 1.加Synchronized同步: 2.使用ThreadLocal: 3.jdk8使用DateTimeFormatter替代SimpleDateForm ...

  9. 从代码都发布遇到的问题总结(C#调用非托管dll文件,部署项目) 转

    http://www.cnblogs.com/Purple_Xiapei/archive/2012/06/30/2570928.html

随机推荐

  1. js下false情况

    //为false的情况 false null NaN undefined "" 0

  2. webpack中使用babel

    step one: https://babeljs.io/setup Choose your tool (try CLI) select webpack Step two: npm install - ...

  3. go开发工具goclipse的安装

    (1) 安装Eclipse 建议下载Eclipse时直接下载"Eclipse IDE for Java Developers"的package,而不要下载较小的Installer. ...

  4. Java7任务并行执行神器:Fork&Join框架

    原 Java7任务并行执行神器:Fork&Join框架 2018年01月12日 17:25:03 Java技术栈 阅读数:426 标签: JAVAFORKJOIN 更多 个人分类: Java ...

  5. buu Crypto 刷题记录

    1.MD5 直接解. 2.url编码 直接解. 3.一眼就解密 base64. 4.看我回旋踢 对文本内容全部CaesarDecode. 5.摩丝 直接MorseDecode. 6.Quoted-pr ...

  6. matplotlib学习(1)

    1.基本学习(1)1.1 代码: import matplotlib.pyplot as plt import numpy as np x=np.linspace(-1,1,50) #从-1到1,共5 ...

  7. 吴裕雄--天生自然Numpy库学习笔记:NumPy 创建数组

    import numpy as np x = np.empty([3,2], dtype = int) print (x) import numpy as np # 默认为浮点数 x = np.zer ...

  8. eclipse修改工作空间编码格式

    一.修改workspace默认编码 eclipse打开window -> 打开preferences 二.修改jsp默认编码 eclipse打开window -> 打开preference ...

  9. Codeforces Round #620 (Div. 2) C. Air Conditioner

    Gildong owns a bulgogi restaurant. The restaurant has a lot of customers, so many of them like to ma ...

  10. lc 0219

    目录 ✅ 463. 岛屿的周长 描述 解答 cpp py ✅ 1122. 数组的相对排序 描述 解答 cpp py ✅ 876. 链表的中间结点 描述 解答 cpp ✅ 1160. 拼写单词 描述 解 ...