[英]java.util.Date vs java.sql.Date
java.util.Date
vs java.sql.Date
:何时使用哪个以及为什么?
恭喜,您已经对 JDBC:日期类处理感到不满。
基本上数据库通常支持至少三种形式的日期时间字段,即日期、时间和时间戳。 其中每一个在 JDBC 中都有一个相应的类,并且每一个都扩展java.util.Date
。 这三个中的每一个的快速语义如下:
java.sql.Date
对应于 SQL DATE,这意味着它存储年、月和日,而忽略时、分、秒和毫秒。 此外sql.Date
与时区sql.Date
。java.sql.Time
对应于 SQL TIME,应该很明显,只包含有关小时、分钟、秒和毫秒的信息。java.sql.Timestamp
对应于 SQL TIMESTAMP,它是精确到纳秒的日期(注意util.Date
只支持毫秒! ),具有可定制的精度。 对这三种类型使用 JDBC 驱动程序时最常见的错误之一是类型处理不正确。 这意味着sql.Date
是特定sql.Date
时区的, sql.Time
包含当前的年、月和日等等。
取决于字段的 SQL 类型,真的。 PreparedStatement
具有所有三个值的设置器, #setDate()
是sql.Date
, #setTime()
是sql.Time
, #setTimestamp()
是sql.Timestamp
。
请注意,如果您使用ps.setObject(fieldIndex, utilDateObject);
实际上,您可以为大多数 JDBC 驱动程序提供一个普通的util.Date
,它们会很高兴地将其吞噬,就好像它是正确的类型一样,但是当您之后请求数据时,您可能会注意到您实际上丢失了一些东西。
我所说的是将毫秒/纳秒保存为普通 long 并将它们转换为您正在使用的任何对象(强制性 joda-time plug )。 一种可行的方法是将日期组件存储为一个长时间组件,将时间组件存储为另一个组件,例如现在将是 20100221 和 154536123。这些幻数可以在 SQL 查询中使用,并且可以从数据库移植到另一个和将让您完全避免 JDBC/Java Date API:s 的这一部分。
后期编辑:从 Java 8 开始,如果可以避免的话,您不应该使用java.util.Date
和java.sql.Date
,而是更喜欢使用java.time
包(基于 Joda)而不是其他任何东西。 如果您不是在 Java 8 上,以下是原始回复:
java.sql.Date
- 当您调用使用它的库的方法/构造函数时(如 JDBC)。 不是别的。 您不想为不显式处理 JDBC 的应用程序/模块引入对数据库库的依赖关系。
java.util.Date
- 使用使用它的库时。 否则,尽可能少,原因如下:
它是可变的,这意味着每次将它传递给方法或从方法返回它时,都必须制作一个防御性副本。
它不能很好地处理日期,这让像你这样的人真正倒退,认为日期处理类应该这样做。
现在,因为 juD 不能很好地完成它的工作,所以引入了可怕的Calendar
类。 它们也是可变的,并且很难使用,如果您别无选择,应该避免使用它们。
有更好的选择,比如Joda Time API (它甚至可能进入 Java 7 并成为新的官方日期处理 API - 快速搜索说它不会)。
如果您觉得引入像 Joda 这样的新依赖项有点过头,那么将long
s 用于对象中的时间戳字段并不是那么糟糕,尽管我自己通常在传递它们时将它们包装在 juD 中,以确保类型安全和作为文档。
唯一一次使用java.sql.Date
是在PreparedStatement.setDate
。 否则,使用java.util.Date
。 它告诉我们ResultSet.getDate
返回一个java.sql.Date
但它可以直接分配给一个java.util.Date
。
我遇到了同样的问题,我发现将当前日期插入到准备好的语句中的最简单方法是:
preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
都不用。
java.time.Instant
替换java.util.Date
java.time.LocalDate
替换java.sql.Date
java.util.Date 与 java.sql.Date:何时使用哪个以及为什么?
这两个类都很糟糕,在设计和实现上都有缺陷。 避免像
瘟疫
冠状病毒一样。
而是使用 JSR 310 中定义的java.time类。这些类是用于处理日期时间的行业领先框架。 这些完全取代了诸如Date
、 Calendar
、 SimpleDateFormat
等该死的可怕的遗留类。
java.util.Date
第一个java.util.Date
表示 UTC 中的一个时刻,这意味着与 UTC 零时分秒的偏移量。
java.time.Instant
现在由java.time.Instant
取代。
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC.
java.time.OffsetDateTime
Instant
是java.time的基本构建块类。 为了更灵活,使用OffsetDateTime
设置为ZoneOffset.UTC
为了同样的目的:代表UTC片刻。
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
您可以通过在JDBC 4.2 或更高版本中使用PreparedStatement::setObject
将此对象发送到数据库。
myPreparedStatement.setObject( … , odt ) ;
取回。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
java.sql.Date
java.sql.Date
类也很糟糕而且已经过时了。
此类仅用于表示日期,没有时间和时区。 不幸的是,在一个可怕的设计黑客中,这个类继承自java.util.Date
,它代表一个时刻(UTC 时间的日期)。 所以这个类只是假装只有日期,而实际上携带了一个时间和 UTC 的隐式偏移量。 这引起了很多混乱。 永远不要使用这个类。
java.time.LocalDate
相反,使用java.time.LocalDate
只跟踪日期(年、月、月日),没有任何时间、任何时区或偏移量。
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
LocalDate ld = LocalDate.now( z ) ; // Capture the current date as seen in the wall-clock time used by the people of a particular region (a time zone).
发送到数据库。
myPreparedStatement.setObject( … , ld ) ;
取回。
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
java.time框架内置于 Java 8 及更高版本中。 这些类取代麻烦的老传统日期时间类,如java.util.Date
, Calendar
,和SimpleDateFormat
。
要了解更多信息,请参阅Oracle 教程。 并在 Stack Overflow 上搜索许多示例和解释。 规范是JSR 310 。
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
您可以直接与您的数据库交换java.time对象。 使用符合JDBC 4.2或更高版本的JDBC 驱动程序。 不需要字符串,不需要java.sql.*
类。
从哪里获得 java.time 类?
Java 中的 java.util.Date 类表示特定的时刻(例如,2013 Nov 25 16:30:45 到毫秒),但 DB 中的 DATE 数据类型仅表示日期(例如, 2013 年 11 月 25 日)。 为了防止您错误地向 DB 提供 java.util.Date 对象,Java 不允许您直接将 SQL 参数设置为 java.util.Date:
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, d); //will not work
但它仍然允许您通过强制/意图来做到这一点(然后小时和分钟将被数据库驱动程序忽略)。 这是通过 java.sql.Date 类完成的:
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, new java.sql.Date(d.getTime())); //will work
java.sql.Date 对象可以存储一个时刻(这样很容易从 java.util.Date 构造)但是如果您尝试询问它的小时数(以强制其概念为仅限日期)。 数据库驱动程序应该识别这个类并且只使用 0 来表示小时。 尝试这个:
public static void main(String[] args) {
java.util.Date d1 = new java.util.Date(12345);//ms since 1970 Jan 1 midnight
java.sql.Date d2 = new java.sql.Date(12345);
System.out.println(d1.getHours());
System.out.println(d2.getHours());
}
java.util.Date
表示具有毫秒精度的特定时刻。 它表示没有时区的日期和时间信息。 java.util.Date 类实现了 Serializable、Cloneable 和 Comparable 接口。 它由java.sql.Date
、 java.sql.Time
和java.sql.Timestamp
接口继承。
java.sql.Date
扩展了 java.util.Date 类,它表示没有时间信息的日期,它应该只在处理数据库时使用。 为了符合 SQL DATE 的定义, java.sql.Date
实例包装的毫秒值必须通过在实例关联的特定时区中将小时、分钟、秒和毫秒设置为零来“标准化” .
它继承了java.util.Date
所有公共方法,例如getHours()
、 getMinutes()
、 getSeconds()
、 setHours()
、 setMinutes()
、 setSeconds()
。 由于java.sql.Date
不存储时间信息,它会覆盖java.util.Date
所有时间操作,如果从它们的实现细节中可以明显看出,所有这些方法都会抛出java.lang.IllegalArgumentException
异常。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.