Java 还提供了一系列用于处理日期、时间的类,包括创建日期、时间对象,获取系统当前日期、时间等操作。
1,Date 类
Java 提供了 Date 类来处理日期、时间(此处的 Date 是指 java.util 包下的 Date 类,而不是 java.sql 包下的 Date 类),Date对象既包含日期,也包含时间。Date 类从 JDK 1.0 起就开始存在了。但正因为它历史悠久,所以它的大部分构造器、方法都已经过时,不再推荐使用了。
Date 类还提供了 6 个构造器,其中 4 个已经 Deprecated(Java 不再推荐使用,使用不再推荐的构造器时编译器会提出警告信息,并导致程序性能、安全性等方面的问题),剩下的两个构造器如下所示。
Date():生成一个代表当前日期时间的 Date 对象。该构造器在底层调用 System.currentTimeMillis() 获得 long 整数作为日期参数。
Date(long date):根据指定的 long 型整数来生成一个 Date 对象。该构造器的参数表示创建的 Date 对象和 GMT 1970 年 1 月 1 日 00:00:00 之间的时间差,以毫秒作为计时单位。
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 对象的时间。
package com.demo;
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 工具类。
2,Calendar 类
因为 Date 类在设计上存在一些缺陷,所以 Java 提供了 Calendar 类来更好地处理日期和时间。Calendar 是一个抽象类,它用于表示日历。
Calendar 类是一个抽象类,所以不能使用构造器来创建 Calendar 对象。但它提供了几个静态 getInstance() 方法来获取 Calendar 对象,这些方法根据 TimeZone,Local 类来获取特定的 Calendar,如果不指定 TimeZone、Local,则使用默认的 TimeZone、Local 来创建 Calendar。
Calendar 与 Date 都是表示日期的工具类,它们直接可以自由转换。
//创建一个默认的 Calendar 对象
Calendar calendar = Calendar.getInstance();
//从 Calendar 对象中取出 Date 对象
Date date = calendar.getTime();
//通过 Date 对象获取得对应的 Calendar 对象
//因为 Calendar/GregorianCalendar 没有构造器函数可以接受 Date 对象
//所以必须先获得一个 Calendar 实例,然后调用其 setTime() 方法
Calendar calendar2 = Calendar.getInstance();
calendar2.setTime(date);
Calendar 类提供了大量访问、修改日期时间的方法,常用方法如下。
void add(int field, int amount):根据日历的规则,为给定的日历字段添加或减去指定的时间量。
int get(int field):返回指定日历字段的值。
int getActualMaximun(int field):返回指定日历字段可能拥有的最大值。
int getActualMinimun(int field):返回指定日历字段可能拥有的最小值。
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。
a,add 与 roll 的区别
add(int field, int amount)的功能非常强大,add 主要用于改变 Calendar 的特定字段的值。如果需要增加某字段的值,则让 amount 为正数;如果需要减少某字段的值,则让 amount 为负数即可。
add(int field, int amount)有如下两条规则。
当被修改的字段超出它运行的范围时,会发生进位,即上一级字段也会增大。
如果下一几字段也需要改变,那么该字段会修正到变化最小的值。
roll的规格与 add 的处理规则不同:当被修改的字段超出它允许的范围时,上一级字段不会增大。
下一级字段的处理规则与 add 相似:
b,设置 Calendar 的容错性
当我们调用 Calendar 对象的 set 方法来改变指定时间字段上的值时,有可能传入一个不合法的参数,例如为 MONTH 字段设置 13,这将会导致怎样的结果呢?看如下程序。
package com.demo;
import java.util.Calendar;
public class LenientTest {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
//结果是 YEAE 字段加 1,MONTH 字段为 1(2月)
cal.set(MONTH, 13); //①
System.out.println(cal.getTime());
//关闭容错性
cal.setLenient(false);
//导致运行时异常
cal.set(MONTH, 13); //②
System.out.println(cal.getTime());
}
}
上面程序1,2两处的代码完全相似,但它们运行的结果不一样:1处代码可以正常运行,因为设置 MONTH 字段的值为 13,将会导致 YEAR字段加 1;2出代码将会导致运行时异常,因为设置的 MONTH 字段值超出了 MONTH 字段运行的范围。关键在于程序中粗体字代码行,Calendar 提供了一个 setLenient() 用于设置它的容错性,Calendar 默认支持较好的容错性,通过 setLenient(false) 可以关闭 Calendar 的容错性,让它进行严格的参数检查。
c,set 方法延迟修改
set(f, value) 方法将日历字段 f 更改为 -- value,此外,它还设置了一个内部成员变量,以知识日历字段 f 已经被更改,但该 Calendar 所代表的的时间却不会立即修改,直到下次调用 get()、getTime()、getTimeMillis()、add() 或 roll() 时才会重新计算日历的时间。这被称为 set 方法的延迟修改,此阿勇延迟修改的优势是多次调用 set() 不会触发多次不必要的计算(需要计算出一下代表实际时间的 long 型整数)。
3,TimeZone 类
在地理上,地球被划分成 24 个时区,中国北京时间属于东八区,而程序中对时间的默认实现是以格林威治时间为标准的,这样就产生了 8 小时的时间差。为了让程序更加通用,可以使用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 类的例子程序。
package com.demo;
import java.util.Arrays;
import java.util.TimeZone;
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 对应的时区。