博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java8的时间和`Date`的对比
阅读量:7254 次
发布时间:2019-06-29

本文共 5894 字,大约阅读时间需要 19 分钟。

java8提供了新的时间接口。相对Date,Calendar,个人感觉最大的好处是对时间操作的学习成本很低,比Calendar低。

1.LocalDate,LocalTime,LocalDateTime

LocalDate 代表日期,LocalTime表示时刻,类似11:23这样的时刻。 LocalDateTime就是前面2个的结合,这个可以从java.time.LocalDateTime#toString的代码看出一二:

@Overridepublic String toString() {    return date.toString() + 'T' + time.toString();}date,time 在java.time.LocalDateTime中/** * The date part. */private final LocalDate date;/** * The time part. */

private final LocalTime time;

实际使用中,计算日期就用LocalDate,计算日期加时刻用LocalDateTime,如果只有时刻就是LocalTime(感觉在说废话)
这三个的用法基本上一样,通过方法名就知道用法那种

1.1 获取当前时间的对象

LocalDateTime localDateTime = LocalDateTime.now();Date date = new Date();

localDateTime相比Date更像是一个工具类,就是为了时间操作使用。其构造方法是私有的。

1.2 从字符串中解析

字符串 2019-01-11 解析成时间对象

String str = "2019-01-11";DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");LocalDate localDate = LocalDate.parse(str, formatter);SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");try {    Date date = simpleDateFormat.parse(str);} catch (ParseException e) {    e.printStackTrace();}

DateTimeFormatter的包路径是java.time.format和LocalDate一样在java.time下面,而SimpleDateFormat和Date是不同的。所以当判断引入路径的时候更容易判断。

当解析失败的时候,两个异常的抛出不一样,DateTimeFormatter抛出的是DateTimeParseException,继承自RuntimeException,而ParseException明显继承的是Exception。
个人感觉这个思路是,前者如果抛出异常那就是编程上错误,而后者则是的程序代码的不稳定性。我更倾向于第一种的异常设计,应该加强对入参的检测判断,而不是通过捕获异常去处理入参的错误。(类似NumberFormatException)

1.3 LocalDate比Date更强的初始化时间

Date 设置某个日期,基本上3个方式,时间戳/Calendar/字符串解析。相对的LocalDate就简单了很多

LocalDate.of(2019,1,12);

其他的也一样
java8的时间和`Date`的对比

1.4 时间戳的转换

在这里时间戳的转换不如Date直接。主要因为LocalDate本身是没有时区的。

时间戳传LocalDateTime

long timestamp = System.currentTimeMillis();Instant instant = Instant.ofEpochMilli(timestamp);LocalDateTime.ofInstant(instant, ZoneId.systemDefault());

LocalDateTime转时间戳

LocalDateTime dateTime = LocalDateTime.now();dateTime.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();dateTime.toInstant(ZoneOffset.of("+08:00")).toEpochMilli();dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

关于时区的计算也很简单,就是相差几个小时就加上多少秒

java8的时间和`Date`的对比

有些时区计算的时候,不妨自己加时间也一样,elasticsearch+logstash设置@timestamp时间是默认UTC Z的时间,和咱们差了8个小时

LocalDateTime.parse(json.getString("@timestamp"), DateTimeFormatter.ISO_DATE_TIME).plusHours(8L)

1.5 和Date互转

import java.time.Instant;import java.util.Date;public class Main {  public static void main(String[] args) {    Date  dt =  new Date();     System.out.println("Date: "  + dt);    Instant in = dt.toInstant();     System.out.println("Instant: "  + in);    Date  dt2  = Date.from(in);     System.out.println("Date: "  + dt2);  }}

Instant 和 LocalDate或LocalDateTime 就不赘述了...

1.6 更好的理解和操作方式

Date、Calendar的操作,例如设置月份,day of week 都有些让人迷惑,例如1月的定义是0,周一是0。1号好像也是0吧(我真没咋用过这东西,现用现百度...

LocalDate感觉好多了。例如DayOfWeek是枚举类型。使用枚举就不会理解错了吧 java8的时间和`Date`的对比

很多日期和时间操作,无非就是加减时间和比较.

使用‘加’的示例:
java8的时间和`Date`的对比

不用再去使用一个不熟悉的Calendar去操作了(Calendar提供的接口都是啥玩意,get,set的)

Calendar cal = Calendar.getInstance();cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + 1)
  1. 线程安全性比较
    LocalDate...系列是线程安全的
    额..每一个字段都用了final关键字了,都变不了... 所以进行操作后都是返回新的copy对象 java8的时间和`Date`的对比

至于说Date线程不安全,get,set的肯定在多线程的时候容易出现问题,不过set方法已经都@Deprecated废弃了。当然不是因为线程安全问题废弃的,是因为有了更好的替代

Calendar.set(Calendar.DAY_OF_MONTH, int date)

不过感觉还是不如这个更清晰明了

LocalDate.of(2019,1,12);

2.1 SimpleDateFormat的线程安全性
参考:深入理解Java:SimpleDateFormat安全的时间格式化

在一定负载情况下,SimpleDateFormat会出问题的。简单测试一下

package open.note;import java.text.SimpleDateFormat;import java.time.LocalDateTime;import java.time.format.DateTimeFormatter;import java.util.Date;import java.util.concurrent.CountDownLatch;import java.util.function.Consumer;public class UnSafeTest {    private static String time = "2019-01-11 11:11:11";    private static long timestamp = 1547176271000L;    private static LocalDateTime dateTime = LocalDateTime.of(2019,1,11,11,11,11);    private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");    public static void main(String[] args) {        dateFormatTest((obj)->{            try {                Date date = dateFormat.parse(time);                if (date.getTime() != timestamp){                    System.out.println(date);                }            } catch (Exception e) {                System.out.println(e.getMessage());            }        });        System.out.println("---------------");        dateFormatTest((obj)->{            try {                LocalDateTime dateTime = LocalDateTime.parse(time,formatter);                if (!dateTime.isEqual(UnSafeTest.dateTime)){                    System.out.println(dateTime);                }            } catch (Exception e) {                System.out.println(e.getMessage());            }        });    }    private static void dateFormatTest(Consumer runnable){        CountDownLatch countDownLatch = new CountDownLatch(1000);        for (int i = 0; i < 1000; i++) {            new Thread(()->{                runnable.accept(null);                countDownLatch.countDown();            }).start();        }        try {            countDownLatch.await();        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

输出结果

multiple pointsmultiple pointsempty StringSat Jan 11 11:11:11 CST 111Fri Jan 04 11:11:11 CST 2019For input string: ""Mon Dec 31 11:11:11 CST 2018Mon Dec 31 11:11:11 CST 2018For input string: ""Tue Jan 11 11:11:11 CST 42101

测试过程中,SimpleDateFormat 1000个线程里,有5次,时间解析错了,5次异常了(时间错了,比抛出异常还可怕)

DateTimeFormatter只是对比参考一下,未出现异常(人家已经声明是线程安全了...)
当然SimpleDateFormat线程不安全应该人尽皆知的,但依然有不安全的使用,但每次使用都new一个实例,当负载大的时候也不好。所以一个线程一个SimpleDateFormat实例应该可以的。

最后

java8 对时间操作的类还有很多 到java.time包下去看看,以后总会用得到的地方。

Instant:时间戳Duration:持续时间,时间差LocalDate:只包含日期,比如:2016-10-20LocalTime:只包含时间,比如:23:12:10LocalDateTime:包含日期和时间,比如:2016-10-20 23:14:21Period:时间段ZoneOffset:时区偏移量,比如:+8:00ZonedDateTime:带时区的时间

Clock:时钟,比如获取目前美国纽约的时间

感兴趣的可以自己来我的Java架构群,可以获取免费的学习资料,群号:855801563 对Java技术,架构技术感兴趣的同学,欢迎加群,一起学习,相互讨论。

转载于:https://blog.51cto.com/13981400/2355810

你可能感兴趣的文章
[HP-UX]清空FIN_WAIT_2的连接
查看>>
大白话Vue源码系列(02):编译器初探
查看>>
[Sdoi2016]平凡的骰子
查看>>
20159208《网络攻防实践》第二周学习总结
查看>>
C#中创建、打开、读取、写入、保存Excel的一般性代码
查看>>
mysql定义游标
查看>>
两个有序数组合并算法
查看>>
面向对象设计原则之五:迪米特法则
查看>>
GitHub for Windows简单使用
查看>>
c#操作XML
查看>>
微软职位内部推荐-SW Engineer for Skype
查看>>
作为一个测试leader平时应该注意哪些方面
查看>>
【DOM编程艺术】Ajax(Hijax)
查看>>
微信公众平台开发(十) 消息回复总结——用其xml模板
查看>>
iOS.CM5.CM4.CM2
查看>>
菜鸟学T-SQL---------SQL2005读书笔记1
查看>>
Python--函数(全局变量和局部变量)
查看>>
PLSQL Developer 不能连接 oracle 11g 64位 的解决办法
查看>>
byobu相关操作
查看>>
父页面操作嵌套iframe子页面的HTML标签元素
查看>>