在创建 Date 对象的时候,总会有两个选择 java.util.Date、java.sql.Date,我们直观的认为在操作数据库时间字段时,我们使用 java.sql.Date 创建 Date 对象,其他情况下使用 java.util.Date 创建 Date 对象。
类的关系如下图:
java.util.Date 是 java.sql.Date java.sql.Time java.sql.Timestamp 的父类,java.security.Timestamp 集成与 java.lang.Object 类。
java.util.Date: 提供了完整的日期时间功能,通过 getTime() 方法可以获取到毫秒数。该类提供了以下几种构造方法:
public Date() {
this(System.currentTimeMillis());
}
public Date(long date) {
fastTime = date;
}
@Deprecated
public Date(int year, int month, int date) {
this(year, month, date, 0, 0, 0);
}
@Deprecated
public Date(int year, int month, int date, int hrs, int min) {
this(year, month, date, hrs, min, 0);
}
@Deprecated
public Date(int year, int month, int date, int hrs, int min, int sec) {
int y = year + 1900;
// month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
if (month >= 12) {
y += month / 12;
month %= 12;
} else if (month < 0) {
y += CalendarUtils.floorDivide(month, 12);
month = CalendarUtils.mod(month, 12);
}
BaseCalendar cal = getCalendarSystem(y);
cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
getTimeImpl();
cdate = null;
}
@Deprecated
public Date(String s) {
this(parse(s));
}
java.sql.Date: 该类屏蔽了时间值,只返回年月日,如:yyyy-MM-dd,该类的主要作用是为了与数据库字段的 Date 类型进行匹配。该类没有提供无参的构造函数,只能通过 long 值或者 year month day 进行初始化。我们可以使用 java.util.Date.getTime() 获取到 long 值,然后构造 java.sql.Date 对象。该类提供了以下几种构造方法:
public Date(long date) {
// If the millisecond date value contains time info, mask it out.
super(date);
}
public Date(int year, int month, int day) {
super(year, month, day);
}
java.sql.Time: 该类屏蔽了日期值,只返回时分秒,如:HH:mm:ss,该类的主要作用是为了与数据库字段的 Time 类型进行匹配。该类没有提供无参的构造函数,只能通过 long 值或者 hour minute second 进行初始化。我们可以使用 java.util.Date.getTime() 获取到 long 值,然后构造 java.sql.Time 对象。该类提供了以下几种构造方法:
@Deprecated
public Time(int hour, int minute, int second) {
super(70, 0, 1, hour, minute, second);
}
public Time(long time) {
super(time);
}
java.sql.Timestamp: 该类对 java.util.Date 类进行了扩充,该类提供了 getNanos() 方法,通过它可以访问毫微秒数(注:1秒 = 10亿毫微秒),该类的主要作用是为了与数据库字段的 Time 类型进行匹配。该类没有提供无参的构造函数,只能通过 long 值或者 year month date hour minute second nano 进行初始化。我们可以使用 java.util.Date.getTime() 获取到 long 值,然后构造 java.sql.Time 对象。该类提供了以下几种构造方法:
@Deprecated
public Timestamp(int year, int month, int date,
int hour, int minute, int second, int nano) {
super(year, month, date, hour, minute, second);
if (nano > 999999999 || nano < 0) {
throw new IllegalArgumentException("nanos > 999999999 or < 0");
}
nanos = nano;
}
public Timestamp(long time) {
super((time/1000)*1000);
nanos = (int)((time%1000) * 1000000);
if (nanos < 0) {
nanos = 1000000000 + nanos;
super.setTime(((time/1000)-1)*1000);
}
}
通过 setTime() 函数可以重设日期时间值,方法如下:
public void setTime(long date) {
// If the millisecond date value contains time info, mask it out.
super.setTime(date);
}
java.util.Date 示例:
import java.text.SimpleDateFormat;
public class DateDemo {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
java.util.Date utilDate = new java.util.Date();
System.out.println(sdf.format(utilDate));
System.out.println("year:" + utilDate.getYear());
System.out.println("month:" + utilDate.getMonth());
System.out.println("date:" + utilDate.getDate());
System.out.println("day:" + utilDate.getDay());
System.out.println("hours:" + utilDate.getHours());
System.out.println("minutes:" + utilDate.getMinutes());
System.out.println("seconds:" + utilDate.getSeconds());
System.out.println("time:" + utilDate.getTime());
}
}
执行结果:
2017-01-16 16:37:55 520
year:117
month:0
date:16
day:1
hours:16
minutes:37
seconds:55
time:1484555875520
java.sql.Timestamp 示例:
import java.text.SimpleDateFormat;
public class TimestampDemo {
public static void main(String[] args) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS");
java.util.Date utilDate = new java.util.Date();
java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(utilDate.getTime());
System.out.println(sdf.format(sqlTimestamp));
System.out.println("year:" + sqlTimestamp.getYear());
System.out.println("month:" + sqlTimestamp.getMonth());
System.out.println("date:" + sqlTimestamp.getDate());
System.out.println("day:" + sqlTimestamp.getDay());
System.out.println("hours:" + sqlTimestamp.getHours());
System.out.println("minutes:" + sqlTimestamp.getMinutes());
System.out.println("seconds:" + sqlTimestamp.getSeconds());
System.out.println("nanos:" + sqlTimestamp.getNanos());
System.out.println("time:" + utilDate.getTime());
}
}
执行结果:
2017-01-16 16:38:59 571
year:117
month:0
date:16
day:1
hours:16
minutes:38
seconds:59
nanos:571000000
time:1484555939571
可以看出 571毫秒 = 571000000毫微秒,1毫秒 = 1000000毫微秒,1秒 = 1000000000 毫微秒。
如何将 java.sql.Date 和 java.sql.time 的值转化为 java.util.Date,网上有人提出的方案是获取 java.sql.Date java.sql.Time 两个对象的毫秒数进行相加,然后通过该值构造 java.util.Date 对象,实现代码如下:
public class DateDemo {
public static void main(String[] args) {
java.sql.Date date = new java.sql.Date(new java.util.Date().getTime());
java.sql.Time time = new java.sql.Time(new java.util.Date().getTime());
java.util.Date utilDate = new java.util.Date(date.getTime() + time.getTime());
System.out.println("date:" + date.getTime());
System.out.println("time:" + time.getTime());
System.out.println("utilDate:" + utilDate);
}
}
执行结果如下:
date:1484557195481
time:1484557195481
utilDate:Sat Feb 02 01:59:50 CST 2064
经验证该方案是错误的,java.sql.Date java.sql.time 本身都存储了距离 1970-1-1 00:00:00 GMT的绝对毫秒数,显然通过 getTime 方法取到毫秒数的方案是错误的。最原始的实现方式是通过 getYear getMonth getDate getHours getMinutes getSeconds 实现。
java.util.Date 是 java 中标准的日期时间类,java.sql.Date java.sql.Time java.sql.Timestamp 是 Java为了适配数据库字段类型对 java.util.Date 类的封装。
java.util.Date 中的很多方法已经不被推荐使用了(@Deprecated),取而代之的是 java.util.Calendar,后续的文章会对其进行分析。
关于闰秒请参考http://baike.baidu.com/link?url=s_ln_DdJiQ3Od7YcvIUA2P0rhyDTU63tNQE7zeOTW7UhNRd3NutEjbWUh2LrIRMNrI9ZdqmD8ptMuOtTNXyAhQdr8kxwT_vW0Bf9q0dHR7C