在创建 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);
}

方法说明

  • getYear:返回年份,值为年份减去1900,如当前年份为 2017,则返回值为 2017 - 1900 = 117;
  • getMonth:返回月份,月份是从 0 开始的,如当前月份为 1 月,则返回值为 0;
  • getDate:返回日期,一月中的某天,取值范围为 1 - 31,如日期为 1 月 1 日,则返回值为 1;
  • getDay:返回一周中的某天,取值范围为 0 - 6,对应的星期数:0 = Sunday, 1 = Monday, 2 = Tuesday, 3 = Wednesday, 4 = Thursday, 5 = Friday, 6 = Saturday,如当前是星期一,则返回 1;
  • getHours:返回小时数,取值范围为 0 - 23,如当前时间为 16:17:10,则返回 16;
  • getMinutes:返回分钟数,取值范围为 0 - 59,如当前时间为 16:17:10,则返回 17;
  • getSeconds:返回秒数,取值范围为 0 - 61,61 是由于闰秒的缘故,如当前时间为 16:17:10,则返回 10;
  • getTime:返回从 1970-1-1 00:00:00 GMT 开始到目标时间的毫秒数;
  • getNanos:返回当前时间的毫微秒数,1毫秒 = 1000000毫微秒,1秒 = 1000000000 毫微秒。

示例

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,后续的文章会对其进行分析。