在java中,java.util
和java.sql
包都包含Date
类,那么它们之间的区别是什么?
如果Java中存在一个Date
类,那么另一个Date
类的需求是什么?
答案 0 :(得分:16)
来自the JavaDoc of java.sql.Date
:
一个围绕毫秒值的瘦包装器,允许JDBC将其标识为SQL DATE值。毫秒值表示自1970年1月1日00:00:00.000 GMT以来经过的毫秒数。
为了符合SQL DATE的定义,
java.sql.Date
实例包含的毫秒值必须通过在特定时区中将小时,分钟,秒和毫秒设置为零来“标准化”。实例是关联的。
说明:java.util.Date
表示日期和时间,java.sql.Date
仅表示日期(java.sql.Date的补码为java.sql.Time
,它只代表一天中的某个时间,但也会延伸java.util.Date
)。
答案 1 :(得分:4)
这些答案似乎已经过时了。
我刚刚阅读了一些API代码(Java版本1.8.0_91)并在java.sql.Date
中找到了它:
/**
* Creates a date which corresponds to the day determined by the supplied
* milliseconds time value {@code theDate}.
*
* @param theDate
* a time value in milliseconds since the epoch - January 1 1970
* 00:00:00 GMT. The time value (hours, minutes, seconds,
* milliseconds) stored in the {@code Date} object is adjusted to
* correspond to 00:00:00 GMT on the day determined by the supplied
* time value.
*/
public Date(long theDate) {
super(normalizeTime(theDate));
}
/*
* Private method which normalizes a Time value, removing all low
* significance digits corresponding to milliseconds, seconds, minutes and
* hours, so that the returned Time value corresponds to 00:00:00 GMT on a
* particular day.
*/
private static long normalizeTime(long theTime) {
return theTime;
}
标准化时间的方法仍然存在,甚至评论说时间将标准化为格林尼治标准时间00:00:00,但它什么也没做。出于某种原因,他们删除了归一化,这意味着,java.sql.Date
只包含java.util.Date
,只是自1.1.1970以来的毫秒数。所以有一个时间组件,但它不会在外部显示。
例如代码
java.util.Date utilDate = new java.util.Date();
java.sql.Date sqlDate = new java.sql.Date(Calendar.getInstance().getTimeInMillis())
System.out.println(utilDate);
System.out.println(sqlDate);
产生输出
Thu Jun 02 13:17:35 CEST 2016
2016-06-02
所以要小心sql日期,不要处理它们,就像它们只包含Date而没有时间信息一样。例如:
java.sql.Date sqlDate1 = new java.sql.Date(Calendar.getInstance().getTimeInMillis());
java.sql.Date sqlDate2 = new java.sql.Date(Calendar.getInstance().getTimeInMillis());
System.out.println(sqlDate1);
System.out.println(sqlDate2);
System.out.println(sqlDate1.equals(sqlDate2));
System.out.println(sqlDate1.toString().equals(sqlDate2.toString()));
打印:
2016-06-02
2016-06-02
false
true
答案 2 :(得分:2)
Java.util.Date是通用的通用Date对象。它存储一个日期(作为一个长),并允许您显示它。
java.sql.Date扩展了java.util.Date。需要注意的主要区别是java.sql.Date没有时间组件。
答案 3 :(得分:1)
java.util.Date
java.util.Date
类是旧日期时间类的一部分,它们被证明设计糟糕,令人困惑且麻烦。目的是在时间轴上表示一个时刻(日期和时间)。
该类似乎代表UTC中的一个时刻,除了它的toString
方法在生成String时默默地应用JVM的当前默认时区,这会产生java.util.Date具有时区的错觉。实际上并没有。好吧,实际上它确实在其源代码中深度分配了一个时区,用于内部的某些事情但不明显且不可设置也不可获取。令人困惑的混乱。
java.sql.Date
java.sql.Date
通过表示仅限日期的值(由“DATE” in the SQL database world表示)使情况更糟,但通过扩展{{ 1}}。但你应该假装它是不一个子类,如类doc中的指示。此外,它有时间,但假装不在UTC调整到当天的第一时刻。令人困惑的混乱。
还有一件事...... java.util.Date
类在小数秒内加上nanoseconds的分辨率。这超出了java.util.Date使用的milliseconds分辨率。许多数据库支持更精细的分辨率,例如microsecond或纳秒。
因此,在这些旧的日期时间类中,无法真正表示没有时间或时区的仅限日期的值。
java.time框架得到了拯救。受到非常成功的Joda-Time项目的启发。内置于Java 8及更高版本。 Back-ported to Java 6 & 7,以及adapted to Android。请参阅Oracle Tutorial。
java.sql.Date
Instant
类表示UTC时间轴上的一个时刻,分辨率为纳秒。简单明了。
Instant
instant.toString()→2016-06-19T02:34:55.564Z
如果使用旧代码需要Instant instant = Instant.now();
,您可以进行转换。查看添加到旧班级的新方法:java.util.Date::toInstant()和java.util.Date.from( Instant )。
要调整到某个地区的wall-clock time,请应用offset-from-UTC(ZoneOffset
)来获取OffsetDateTime
个对象。更妙的是,如果您知道正确的时区名称,请应用ZoneId
获取ZonedDateTime
。
例如,America/Montreal
在UTC夏季落后Daylight Saving Time (DST)四小时,因此我们在上一个日期中看到晚上10点(22:00)在上面的示例中,代码低于上午而不是凌晨2点。回到过去的四个小时,越过上午的日期。但是,上面显示的java.util.Date
对象和下一个所见的instant
对象都表示时间轴上的同时时刻。历史上的同一时刻,但在巴黎,加尔各答和奥克兰的“明天”,而在蒙特利尔,墨西哥城和檀香山的“昨天”。
zdt
zdt.toString()→2016-06-18T22:34:55.564-04:00 [美国/蒙特利尔]
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
对于仅限日期的值,请使用LocalDate
类。不保留时间和时区。
LocalDate
但请注意,时区对于确定日期至关重要,因为任何特定时刻日期可能会因时区而异。因此,上面关于指定时区的讨论。例如,请参阅接下来我们如何获得6月的 18th 而不是 19 。
localDate.toString()→2016-06-18
如果按时区区分日期对您的业务有重要意义,则应使用存储在数据库列类型LocalDate localDate = zdt.toLocalDate();
而不是TIMESTAMP WITH TIME ZONE
中的日期时间值。
搜索Stack Overflow以获取更多信息和许多java.time示例(标记:DATE
)。
因此请保存到数据库,使用符合JDBC driver的JDBC 4.2 spec(请参阅Guide)。在PreparedStatement
上调用java-time
和setObject
可直接使用java.time对象。
如果您的JDBC驱动程序尚不支持直接使用java.time类型,请使用添加到旧类的新方法来促进转换。但最大限度地减少对旧班级的使用;立即转换为java.time并在业务逻辑中仅使用java.time对象。
getObject
另一个方向。
java.sql.Date mySqlDate = java.sql.Date.valueOf( localDate );
答案 4 :(得分:0)
java.sql.Date接受一个长整数,表示自1970年1月1日以来的毫秒数。如果给定的数字为负,则表示1970年1月1日之前的时间。请记住,对象内的封装值仅表示日期比如1970年1月1日,没有存储时间信息。
java.util.Date存储日期和时间信息。 它比java.sql.Date更常用。