处理日期的类

Java还提供了一系列用于处理日期、时间的类,包括创建日期、时间对向,获取系统当前日期、时间等操作。

Date类

Java提供了Date类来处理日期、时间(指java.util.Date包),Date对象既包含日期,也包含时间。Date类历史悠久,所以它的大部分构造器、方法都已经过时,不再推荐使用了。
Date类提供了6个构造器,其中4个已经Deprecated(java不再推荐使用),剩下两个构造器如下:

  • Date():生成一个代表当前日期时间的Date对象。该构造器在底层调用System.currentTimeMillis()获得long整数作为日期参数。
  • Date(long date):根据指定的long型整数来生成一个Date对象。该构造器的参数表示创建的Date对象和GMT 1970年1月1日00:00:00之间的时间差,以毫秒作为计时单位。

与Date构造器相同的是,Date对象的大部分方法也Deprecated了,剩下为数不多的几个方法:

  • boolean after(Date when):测试该日期是否在指定日期when之后。
  • boolean before(Date when):测试该日期是否在指定日期when之前。
  • int compareTo(Date anotherDate):比较两个日期的大小,后面的时间大于前面的时间时返回-1,否则返回1。
  • boolean equals(Object obj):当两个时间表示同一时刻时返回true。
  • long getTime():返回该时间对应的long型整数,即从GMT 1970-01-01 00:00:00 到该Date对象之间的时间差,以毫秒作为计时单位。
  • void setTime(long time):设置该Date对象的时间。

下面程序示范了Date类的用法:

import java.util.Date;

public class DateTest {
    public static void main(String[] args){
        Date d1=new Date();
        //获取当前时间之后100ms的时间
        Date d2=new Date(System.currentTimeMillis()+100);
        System.out.println(d2);
        System.out.println(d1.compareTo(d2));
        System.out.println(d1.before(d2));
    }
}

因为Date类的很多方法已经不推荐使用了,所以Date类的功能已经被大大削弱。例如,对时间进行加减运算,获取指定Date对象年、月、日的所有方法都已被Deprecated,如果需要对日期进行这些运算,则应该使用Calendar工具类。

Calender类

Calendar类本身是一个抽象类,它是所有日历类的模板,并提供了一些所有日历通用的方法;但它本身不能直接实例化,程序只能创建Calendar子类的实例,Java本身提供了一个GregorianCalendar类,一个代表GregorianCalendar的子类,它代表了我们通常所说的公历。
当然,也可以创建自己的Calendar子类,然后将它作为Calendar对象使用(这就是多态)。
Calendar类是一个抽象类,所以不能使用构造器来创建Calendar对象。但它提供了几个静态getInstance()方法来获取Calendar对象,这些方法根据TimeZone,Locale类来获取特定的Calendar,如果不指定TimeZone、Locale,则使用默认的TimeZone、Locale来创建Calendar。
Calendar与Date都是表示日期的工具类,它们直接可以自由转换,如下代码所示:

//创建一个默认的Calendar对象
Calendar calender=Calendar.getInstance();
//从Calendar 对象中取出Date对象
Date date =calender.getTime();
//通过Date对象获得对应的Calendar对象
//因为Calendar、GregorianCalender没有构造函数可以接收Date对象
//所以必须先获得一个Calendar实例,然后调用其setTime()方法
Calendar calendar2=Calendar.getInstance();
calendar2.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 hourOfDay, int minute, int second):设置Calendar对象的年、月、日、时、分、秒6个字段的值。
    上面的很多方法都需要一个int类型的field参数,field是Calendar类的静态Field,如Calendar.YEAR、Calendar.MONTH等分别代表了年、月、日、小时、分钟、秒等时间字段。需要指出的是,Calendar.MONTH字段代表月份,月份的起始值不是1,而是0,所以要设置8月时,用7而不是8。如下为Calendar的常规用法:
import java.util.Calendar;

public class CalendarTest
{
    public static void main(String[] args)
    {
        Calendar c=Calendar.getInstance();
        // 取出年
        System.out.println(c.get(Calendar.YEAR));
        // 取出月份
        System.out.println(c.get(Calendar.MONTH));
        // 取出日
        System.out.println(c.get(Calendar.DATE));
        // 分别设置年、月、日、小时、分钟、秒
        c.set(2003 , 10 , 23 , 12, 32, 23);
        // 2003-11-23 12:32:23
        System.out.println(c.getTime());
        // 将Calendar的年前推1年
        c.add(Calendar.YEAR, -1);
        // 2002-11-23 12:32:23
        System.out.println(c.getTime());
        // 将Calendar的月前推8个月
        c.roll(Calendar.MONTH , -8);
        // 2002-03-23 12:32:23
        System.out.println(c.getTime());
    }
}

上面程序中粗体字代码示范了Calendar类的用法,Calendar可以灵活地改变它对应的Date。

add与roll的区别

add(int field, int amount)的功能非常强大,add主要用于改变Calendar的特定字段的值。如果需要增加某字段的值,则让amount为正数;如果需要减少某字段的值,则让amount为负数即可。
add(int field, int amount)有如下两条规则。

  • 当被修改的字段超出它允许的范围时,会发生进位,即上一级字段也会增大。例如:
Calendar cal1=Calendar.getInstance();
cal1.set(2003, 7, 23, 0, 0 , 0); //2003-8-23
cal1.add(Calendar.MONTH, 6); //2003-8-23=> 2004-2-23
  • 如果下一级字段也需要改变,那么该字段会修正到变化最小的值。例如:
Calendar cal2=Calendar.getInstance();
cal2.set(2003, 7, 31, 0, 0 , 0); //2003-8-31
//因为进位后月份改为2月,2月没有31日,自动变成29日
cal2.add(Calendar.MONTH, 6); //2003-8-31=> 2004-2-29

对于上面的例子,8-31就会变成2-29.因为MONTH的下一级字段是DATE,从31到29改变最小。
roll的规则与add的处理规则不同:当被修改的字段超出它允许的范围时,上一级字段不会增大:

Calendar cal3=Calendar.getInstance();
cal3.set(2003, 7, 23, 0, 0 , 0); //2003-8-23
//MONTH字段“进位”,但YEAR字段并不增加
cal3.roll(Calendar.MONTH, 6); //2003-8-23=> 2003-2-23

下一级字段的处理规则与add相似:

Calendar cal4=Calendar.getInstance();
cal4.set(2003, 7, 31, 0, 0 , 0); //2003-8-31
// MONTH字段“进位”后变成2,2月没有31日
// YEAR字段不会改变,2003年2月只有28天
cal4.roll(Calendar.MONTH, 6); //2003-8-31=> 2003-2-28

设置Calendar的容错性

当我们调用Calendar对象的set方法来改变指定时间字段上的值时,有可能传入一个不合法的参数,例如MONTH字段设置为13,这将会导致怎样的后果,看如下程序:

import java.util.Calendar;

public class LenientTest
{
    public static void main(String[] args)
    {
        Calendar cal=Calendar.getInstance();
        //结果是YEAR字段加1,MONTH字段为1(2月)
        cal.set(Calendar.MONTH , 13); //①
        System.out.println(cal.getTime());
        //关闭容错性
        cal.setLenient(false);
        //导致运行时异常
        cal.set(Calendar.MONTH , 13); //②
        System.out.println(cal.getTime());
    }
}

开启容错,因为设置MONTH字段的值为13,将会导致YEAR字段加1
关闭容错后,因为MONTH设置的字段超出了范围,故出现了异常。

set方法延迟修改

set(f, value)方法将日历字段f更改为value,此外,它还设置了一个内部成员变量,以指示日历字段f已经被更改。尽管日历字段f是立即更改的,但该Calendar所代表的时间却不会立即修改,直到下次调用get()、getTime()、getTimeInMillis()、add()或roll()时才会重新计算日历的时间。这被称为set方法的延迟修改,采用延迟修改的优势是多次调用set()不会触发多次不必要的计算(需要计算出一个代表实际时间的long型整数)。
下面程序演示了set方法延迟修改的效果:

import java.util.Calendar;

public class LazyTest {
    public static void main(String[] args){
        Calendar cal=Calendar.getInstance();
        cal.set(2003, 7, 31);   //2003-8-31
        System.out.println(cal.getTime());
        //将月份设为9,但是9月31日不存在
        //如果立即修改,系统将会把cal自动调整到10月1日
        cal.set(Calendar.MONTH, 8);
        System.out.println(cal.getTime());   //①
        //设置DATE字段为5
        cal.set(Calendar.DATE, 5);
        System.out.println(cal.getTime());
    }
}

如果程序将①处代码注释起来,因为Calendar的set()方法具有延迟修改的特性,即调用set()方法后Calendar实际上并未计算真实的日期,它只是使用内部成员变量表记录MONTH字段被修改为8,接着程序设置DATE字段值为5,程序内部再次记录DATE字段为5——就是9月5日,所以最终输出为2003-9-5

TimeZone类

在地里上,地球被划分为24个时区,中国北京时间属于东八区,而程序中对时间的默认实现是以格林威治时间为标准的,可以使用TimeZone设置程序中时间所属的时区,其中TimeZone就代表了时区
TimeZone是一个抽象类,不能调用其构造器来创建实例,但可以调用它的静态方法:getDefault()或getTimeZone()得到TimeZone实例。其中getDefault()方法用于获得运行机器上的默认时区,默认时区可以通过修改操作系统的相关配置来进行调整;getTimeZone()则根据时区ID来获取对应的时区。
对于Windows系统而言,用户打开“控制面板”,单击控制面板里的“日期和时间”按钮,即可打开设置时区对话框。
TimeZone类提供了一些有用的方法用于获取时区的相关信息。

  • static String[] getAvailableIDs():获取Java所支持的所有时区ID。
  • static TimeZone getDefault():获取运行机器上默认的时区。
  • String getDisplayName():获取该TimeZone对象的时区名称。
  • String getID():获取该时区的ID。
  • static TimeZone getTimeZone(String ID):获取指定ID对应的TimeZone对象。

下面看一个使用TimeZone类的例子程序:

import java.util.*;

public class TimeZoneTest {
    public static void main(String[] args){
        //取得Java所支持的所有时区ID
         String[] ids=TimeZone.getAvailableIDs();
         System.out.println(Arrays.toString(ids));
         TimeZone my=TimeZone.getDefault();
        // 获取系统默认时区的ID:Asia/Shanghai
         System.out.println(my.getID());
        // 获取系统默认时区的名称:中国标准时间
         System.out.println(my.getDisplayName());
        // 获取指定ID的时区名称:纽芬兰标准时间
        System.out.println(TimeZone.getTimeZone("CNT").getDisplayName());
    }
}

上面程序中示范了TimeZone类的基本用法,程序运行后可以看到Java所支持的所有时区ID;如果需要取得指定时区,则可以通过getTimeZone()方法获得指定ID对应的时区。

java实例练习

使用SimpleDateFormat类格式化输出时间

假如我们希望定制日期数据的格式,比如“星期三-十一月-07-2012”这样的通俗易懂的格式,就需要用到另外一个类:java.text.SimpleDateFormat。本例中我们就应用这个类实现日期的不同格式化输出。

1.

新建项目Simple_Date_Format,并在其中创建一个Simple_Date_Format.java文件。在该类的主方法中使用SimpleDateFormat类格式化输出了6种时间的表现方式:

package Simple_Date_Format;

import java.text.SimpleDateFormat;
import java.util.*;

public class Simple_Date_Format {
    public static void Simple_Format(){
        System.out.println("SimpleDateFormat类获取系统当前的时间如下:" );
        //创建一个日期格式化,日期的形式为EEEE-MMMM-dd-yyyy
        SimpleDateFormat bartDateFormat = new SimpleDateFormat("EEEE-MMMM-dd-yyyy");
        // 创建一个日期格式化,日期的形式为yyyy.MM.dd G 'at' HH:mm:ss z
        SimpleDateFormat b = new SimpleDateFormat(
                "yyyy.MM.dd G 'at' HH:mm:ss z");
        // 创建一个日期格式化,日期的形式为EEE, MMM d, ''yy
        SimpleDateFormat b1 = new SimpleDateFormat("EEE, MMM d, ''yy");
        // 创建一个日期格式化,日期的形式为h:mm a
        SimpleDateFormat b2 = new SimpleDateFormat("h:mm a");
        // 创建一个日期格式化,日期的形式为EEE, d MMM yyyy HH:mm:ss Z
        SimpleDateFormat b3 = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss Z");
        // 创建一个日期格式化,日期的形式为yyMMddHHmmssZ
        SimpleDateFormat b4 = new SimpleDateFormat("yyMMddHHmmssZ");
        Date date = new Date();
        System.out.println("日期的形式为 EEEE-MMMM-dd-yyyy:" + bartDateFormat.
                format(date));
        System.out.println("日期的形式为 yyyy.MM.dd G  'at' HH:mm:ss z:" +
                b.format(date));
        System.out.println("日期的形式为EEE, MMM d, ''yy:" + b1.format(date));
        System.out.println("日期的形式为h:mm a:" + b2.format(date));
        System.out.println("日期的形式为EEE, d MMM yyyy HH:mm:ssZ:" + b3.format(date));
        System.out.println("日期的形式为yyMMddHHmmssZ:" + b4.format(date));
    }
    public static void main(String[] args){
        Simple_Date_Format.Simple_Format();
    }
}

字符串对应表:

使用Calendar显示当前的时间和日期

Calendar类是一种功能比Date类功能更为强大的抽象类。它被设计成一个挂在墙壁上的典型日历,有很多月份和日期可以翻阅。而且它是构建在大量可以直接读取的属性上的,这些属性多是静态成员变量,可以使用它们来设置或获取某些值。本例我们将使用Calendar类来显示当前的时间和日期。

1.

新建项目DateAndTime,并在其中创建一个DateAndTime.java文件。在该类的主方法中使用Calendar.getInstance()方法的各种参数方法实现年月日以及时分秒的获取,然后将结果输出出来:

package DateAndTime;

import java.util.*;

public class DateAndTime {
    static final char days[] ={' ','日','一','二','三','四','五','六'};
    // 星期要转换成汉语形式显示,数字1表示星期日
    public static void main(String[] args) {
        Calendar cal = Calendar.getInstance();  // 获取当前时间,创建对象
        int year = cal.get(Calendar.YEAR);      // 获取年份
        int month = cal.get(Calendar.MONTH) + 1;// 获取月份,它是以0为第一个月,所以要加1
        int date = cal.get(Calendar.DATE);      // 获取日期
        int day = cal.get(Calendar.DAY_OF_WEEK);
        // 获取星期几,它是以1为第1天,要用数组days[]来换算
        int hour = cal.get(Calendar.HOUR_OF_DAY);   // 获取小时,这是24小时制
        int min = cal.get(Calendar.MINUTE);         // 获取分钟
        int sec = cal.get(Calendar.SECOND);         // 获取秒
        // 按照中国人的习惯来显示日期和时间
        System.out.println("今天是:"+year+"年"+month+"月"+date+"号"+"星期 "+days[day]);
        System.out.println("现在的时间是: "+hour+":"+min+":"+sec);
    }
}

Calendar类中月的表示是从0开始的,即Calendar.MONTH值为0表示1月,Calendar.MONTH值为1表示2月,以此类推。