zoukankan      html  css  js  c++  java
  • 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技术干货!

      ▼微信扫一扫下图↓↓↓二维码关注

     

  • 相关阅读:
    记一次oracle新建用户及分配指定表权限的操作记录
    [转]word中不显示mathtype公式,只显示方框,双击后可以再mathtype里面看到公式
    C、C++成员变量对齐
    include头文件:C++标准库与C标准库
    [转]本专业部分国际会议及刊物影响因子排名
    使用Winbase.h
    [转]printf 字符串格式化
    1.6.2如何使用位逻辑运算(例如与、或、位移)来实现位向量?
    文章中图表自动编号
    取样问题 总数n事先不知道,等概率取样 (编程珠玑chapter12 课后题10)
  • 原文地址:https://www.cnblogs.com/bingyimeiling/p/10420752.html
Copyright © 2011-2022 走看看