Java8与传统的日期和时间类详解
一、传统的日期时间类(date和calendar)
1. date类
这里的date是位于java.util包下的类,而不是java.sql包下的date类,date对象即包含日期也包含时间,从jdk1.0就开始存在了,历史相当悠久,因此,它的大部分构造器和方法已经过时了,不在推荐使用。
date提供了6个构造器,其中4个已经deprecated(不推荐使用了,如果继续使用,编译器会提出警告信息,并导致程序性能和安全性方面的问题),剩下2个构造器如下:
♦ date():生成一个代表当前日期的date对象。该构造器在底层调用system.currenttimemillis()获得long长整数作为日期参数。
♦ date(long date):根据指定的long型整数生成一个date对象。该构造器的参数表示创建的date对象和gmt1970年1月1日00:00:00之间的时间差,以毫秒为单位。
date对象的大部分方法也已经过时了,仅剩下以下几个方法:
♦ boolean after(date when):测试该日期是否在指定的日期when之后。
♦ boolean before(date when):测试该日期是否在指定的日期when之前。
♦ long gettime():返回该时间对应的long 型整数,即从gmt 1970-01-01 00:00:00到该date对象之间的时间差,以毫秒为单位。
♦ void settine(long time):设置该date对象的时间。
date类常用用法如下面程序示例:
public class datetest { public static void main(string[] args) { date d1 = new date(); //获取当前时间后的200毫秒的时间 date d2 = new date(system.currenttimemillis() + 200); system.out.println(d2); system.out.println(d1.compareto(d2)); system.out.println(d1.before(d2)); } }
运行代码结果如下:
fri feb 22 21:32:14 cst 2019
-1
true
总体来说,date类不推荐使用,如果需要获取指定的时间或对时间进行加减运算,可使用calendar工具类。
2. calendar类
calendar类本身是一个抽象类,它是所有日历类的模板,但不能之间创建对象,但它提供了几个静态getinstance()方法来获取calendar对象。
calendar和date都是日期的工具类,它们之间可以*转换,如下代码所示:
calendar cal = calendar.getinstance(); //从calendar对象中取出date对象 date date = cal.gettime(); //通过date对象获取对应的calendar对象 //由于calendar没有构造器接收date对象 //所以必须先获得一个calendar实例,然后调用其settime()方法 calendar cal2 = calendar.getinstance(); cal2.settime(date);
calendar提供了大量的访问、修改日期的方法,常用的如下:
♦ void add(int field,int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。
♦ int get(int field):返回指定日历字段的值。
♦ int getactualmaximum(int field):返回指定的日历字段可能拥有的最大值。例如月,最大值为11。
♦ int getactualminimum(int field):返回指定的日历字段可能拥有的最小值。例如月,最小值为0。
♦ void roll(int field,int amount):与add方法类似,区别在于加上amount后如果超过了该字段的最大范围,也不会向上一个字段进位。
♦ void set(int field,int value):将给定的日历字段设置为给定值。
♦ void set(int year,int month,int date):设置calendar对象的年、月、日3个字段的值。
♦ void set(int year,int month,int date,int hour,int minute,int second):设置calendar对象的年、月、日、时、分、秒6个字段的值。
可以看出上面很多方法都需要一个int类型的field参数,field时calendar类的类变量,如calendar.year、calendar.month、calendar.date等分别代表了年、月、日、时、分、秒等字段,需要注意的是calendar.month月份的起始值是0,范围是0-11。下面程序示范了calendar的常规用法:
public class calendartest { public static void main(string[] args) { calendar cal = calendar.getinstance(); //取出年 system.out.print("取出年:"); system.out.println(cal.get(calendar.year)); //取出月:当前月减1 system.out.print("取出月:"); system.out.println(cal.get(calendar.month)); //取出日 system.out.print("取出日:"); system.out.println(cal.get(calendar.date)); //分别设置年、月、日、时、分、秒 system.out.print("设置时间:"); cal.set(2019, 02, 22, 22, 06, 34); system.out.println(cal.gettime()); //将calendar的年前推1年 system.out.print("将calendar的年前推1年:"); cal.add(calendar.year, -1); system.out.println(cal.gettime()); //将calendar的月前推3个月 system.out.print("将calendar的月前推3个月:"); cal.add(calendar.month, -3); system.out.println(cal.gettime()); } }
打印结果为:
取出年:2019
取出月:1
取出日:22
设置时间:fri mar 22 22:06:34 cst 2019
将calendar的年前推1年:thu mar 22 22:06:34 cst 2018
将calendar的月前推3个月:fri dec 22 22:06:34 cst 2017
calendar类需要注意的以下几点:
♦ add与roll的区别
add(int field,int amount)方法主要用于改变calendar的特定字段的值。如果要增加某个字段的值,则amount为正数,如果要减少某个字段的值,则amount为负数。此方法有如下两条规则:
1)当被修改的字段超出它允许的范围时,会发生进位,即上一级字段也会增大。例如:
calendar cal = calendar.getinstance();
cal.set(2008,7,23,0,0,0);//2008-8-23
cal.add(calendar.month,6);//2008-8-23 =>2009-2-23
2) 如果下一级字段也需要改变,则该字段会修正到变化最小的值。例如:
calendar cal = calendar.getinstance();
cal.set(2008,7,31,0,0,0);//2008-8-31
//因为进位后月份变为2,而2月没有31日,自动变成28
cal.add(calendar.month,6);//2008-8-31 =>2009-2-28
roll()的规则与add()规则处理不同:当被修改的字段超出它允许的范围时,上一级字段也不会增大,即不会发生进位。例如:
calendar cal = calendar.getinstance();
cal.set(2008,7,23,0,0,0);//2008-8-23
cal.add(calendar.month,6);//2008-8-23 =>2008-2-23
roll()下一级字段的处理与add()相同,都会修正到该字段变化的最小值,例如:
calendar cal = calendar.getinstance();
cal.set(2008,7,31,0,0,0);//2008-8-31
//2月没有31日,自动变成29,year字段不会改变
cal.add(calendar.month,6);//2008-8-31 =>2008-2-29
♦ 设置calendar的容错性
先看如下代码:
calendar cal = calendar.getinstance(); system.out.println("现在时间:"+cal.gettime()); cal.set(calendar.month, 13);//(1) system.out.println("月份加上13后的时间"+cal.gettime()); //关闭容错性 cal.setlenient(false); cal.set(calendar.month, 13);//(2) system.out.println(cal.gettime());
打印结果为:
现在时间:sat feb 23 22:06:13 cst 2019 月份加上13后的时间sun feb 23 22:06:13 cst 2020 exception in thread "main" java.lang.illegalargumentexception: month at java.util.gregoriancalendar.computetime(gregoriancalendar.java:2316) at java.util.calendar.updatetime(calendar.java:2468) at java.util.calendar.gettimeinmillis(calendar.java:1087) at java.util.calendar.gettime(calendar.java:1060) at com.bhyj.calendartest.main(calendartest.java:37)
从打印结果可以看出:月份加上13后,代码能正常执行,year字段加1,month字段为1即2月,但是加上cal.setlenient(false);这行代码后,代码运行时异常,因为月份超出了最大月份。calendar默认支持较好的容错性,可以关闭其容错性,让它进行严格的参数检查。
♦ set()方法延迟修改
通过set()方法设置某一个字段的值得时候,该字段的值不会立马修改,直到下次调用get()、gettime()等时才会重新计算日历的时间。延迟修改的优势是多次调用set()方法不会触发多次不必要的计算。下面程序演示了set()方法延迟修改的效果:
calendar cal = calendar.getinstance(); cal.set(2003,7,31);//2003-8-31 //将月份设为9,但9月31不存在 //如果立即修改,系统会把cal自动调整到10月1日 cal.set(calendar.month,8); //下面代码输出了10月1日 system.out.println(cal.gettime());//(1) //设置date字段为5 cal.set(calendar.date, 5);//(2) system.out.println(cal.gettime());//(3)
打印结果为:
wed oct 01 22:25:41 cst 2003
sun oct 05 22:25:41 cst 2003
如果将(1)处的代码注释掉,打印结果为:
fri sep 05 22:28:06 cst 2003
你看明白了吗?如果将(1)处的代码注释掉,因为set()方法具有延迟性,它内部只是先记录下month字段的值为8,接着程序将date字段设置为5,程序内部再次记录date字段的值为5——就是9月5日。
二、java8新增的日期、时间包
为了弥补传统java对日期、时间处理的不足,java8提供了一套全新的日期时间库。java8专门新增了一个java.time包,该包下包含了如下常用类。
♦ clock:该类用于获取指定时区的当前日期、时间。该类可以取代system类的currenttimemillis()方法,该类提供了大量的方法获取当前的日期和时间,如下图:
程序代码示例如下:
//获取当前clock clock clock = clock.systemutc(); //获取clock对应的毫秒数 //等于system.currenttimemillis() system.out.println(clock.millis()); system.out.println(system.currenttimemillis());
♦ duration:该类代表持续时间
示例代码如下:
duration d = duration.ofseconds(600); system.out.println("600秒="+d.tominutes()+"分"); system.out.println("600秒="+d.tohours()+"时"); system.out.println("600秒="+d.todays()+"天");
♦ instant:该类代表一个具体的时刻,可以精确到纳秒。该类主要提供了以下几个方法:
1)now():获取当前时刻。
2)now(clock clock):获取clock对应的时刻。
3)minusxxx():在当前时刻基础上减去一段时间。
4)plusxxx():在当前时刻基础上加上一段时间。
代码示例如下:
//获取当前时间 instant instant = instant.now(); system.out.println(instant); //instant增加600秒 instant instant2 = instant.plusseconds(600);
♦ localdate:该类代表不带时区的日期,如:2019-02-24。该类主要提供了以下几个方法:
1)now():获取当前日期。
2)now(clock clock):获取clock对应的日期。
3)minusxxx():在当前年份基础上减去几年、几月、几周或几日等。
4)plusxxx():在当前年份基础上加上几年、几月、几周或几日等。
♦ localtime:该类代表不带时区的时间,如:10:20:09。该类主要提供了以下几个方法:
1)now():获取当前时间。
2)now(clock clock):获取clock对应的时间。
3)minusxxx():在当前年份基础上减去几小时、几分、几秒等。
4)plusxxx():在当前年份基础上加上几小时、几分、几秒等。
♦ localdatetime:该类代表不带时区的日期、时间,如:2019-02-24t10:20:09。该类主要提供了以下几个方法:
1)now():获取当前日期、时间。
2)now(clock clock):获取clock对应的日期、时间。
3)minusxxx():在当前年份基础上减去几年、几月、几周或几日、几小时、几分、几秒等。
4)plusxxx():在当前年份基础上加上几年、几月、几周或几日、几小时、几分、几秒等。
♦ monthday:该类仅代表月日,如:--09-20。该类主要提供了以下几个方法:
1)now():获取当前月日。
2)now(clock clock):获取clock对应的月日。
♦ year:该类仅代表年,如:2019。该类主要提供了以下几个方法:
1)now():获取当前年份。
2)now(clock clock):获取clock对应的年份。
3)minusxxx():在当前年份基础上减去几年。
4)plusxxx():在当前年份基础上加上几年。
♦ yearmonth:该类仅代表年月,如:2019-02。该类主要提供了以下几个方法:
1)now():获取当前年月。
2)now(clock clock):获取clock对应的年月。
3)minusxxx():在当前年份基础上减去几年、几月。
4)plusxxx():在当前年份基础上加上几年、几月。
♦ zoneddatetime:该类代表一个时区化的日期、时间。
♦ zonedid:该类代表一个时区。
♦ dayofweek:该类是一个枚举类,定义了周日到周六的枚举值。
♦ month:该类是一个枚举类,定义了一月到十二月的枚举值。
欢迎关注微信公众号【java典籍】,收看更多java技术干货!
▼微信扫一扫下图↓↓↓二维码关注
下一篇: 喝红糖水的注意事项 你都清楚吗
推荐阅读
-
Java8日期和时间段的计算
-
详解Java中格式化日期的DateFormat与SimpleDateFormat类
-
详解Java中格式化日期的DateFormat与SimpleDateFormat类
-
asp.net下日期和时间处理的类库
-
Java中的日期和时间类以及Calendar类用法详解
-
asp.net下日期和时间处理的类库
-
Java中的日期和时间类以及Calendar类用法详解
-
把相片的详情列表里显示的时间与文件名和标题里指示的时间统一 日期格式string转longandroidcamera
-
mybatis如何使用Java8的日期LocalDate和LocalDateTime详解
-
mybatis如何使用Java8的日期LocalDate和LocalDateTime详解