java.util.Date 与 java.sql.Date
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2305973/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
java.util.Date vs java.sql.Date
提问by flybywire
java.util.Date
vs java.sql.Date
: when to use which and why?
java.util.Date
vs java.sql.Date
:何时使用哪个以及为什么?
采纳答案by Esko
Congratulations, you've hit my favorite pet peeve with JDBC: Date class handling.
恭喜,您已经对 JDBC:日期类处理感到不满。
Basically databases usually support at least threeforms of datetime fields which are date, time and timestamp. Each of these have a corresponding class in JDBC and each of them extend java.util.Date
. Quick semantics of each of these three are the following:
基本上数据库通常支持至少三种形式的日期时间字段,即日期、时间和时间戳。其中每一个在 JDBC 中都有一个相应的类,并且每一个都扩展java.util.Date
. 这三个中的每一个的快速语义如下:
java.sql.Date
corresponds to SQL DATE which means it stores years, months and dayswhile hour, minute, second and millisecondare ignored. Additionallysql.Date
isn't tied to timezones.java.sql.Time
corresponds to SQL TIME and as should be obvious, only contains information about hour, minutes, seconds and milliseconds.java.sql.Timestamp
corresponds to SQL TIMESTAMP which is exact date to the nanosecond (note thatutil.Date
only supports milliseconds!) with customizable precision.
java.sql.Date
对应于 SQL DATE,这意味着它存储年、月和日,而忽略小时、分钟、秒和毫秒。此外sql.Date
与时区无关。java.sql.Time
对应于 SQL TIME 并且应该很明显,只包含有关小时、分钟、秒和毫秒的信息。java.sql.Timestamp
对应于 SQL TIMESTAMP,它是精确到纳秒的日期(请注意,util.Date
仅支持毫秒!)并具有可自定义的精度。
One of the most common bugs when using JDBC drivers in relation to these three types is that the types are handled incorrectly.This means that sql.Date
is timezone specific, sql.Time
contains current year, month and day et cetera et cetera.
对这三种类型使用 JDBC 驱动程序时最常见的错误之一是类型处理不正确。这意味着sql.Date
特定于时区,sql.Time
包含当前的年、月和日等等。
Finally: Which one to use?
最后:使用哪个?
Depends on the SQL type of the field, really. PreparedStatement
has setters for all three values, #setDate()
being the one for sql.Date
, #setTime()
for sql.Time
and #setTimestamp()
for sql.Timestamp
.
取决于字段的 SQL 类型,真的。PreparedStatement
具有所有三个值的设置器,#setDate()
即 for sql.Date
、#setTime()
forsql.Time
和#setTimestamp()
for sql.Timestamp
。
Do note that if you use ps.setObject(fieldIndex, utilDateObject);
you can actually give a normal util.Date
to most JDBC drivers which will happily devour it as if it was of the correct type but when you request the data afterwards, you may notice that you're actually missing stuff.
请注意,如果您使用,ps.setObject(fieldIndex, utilDateObject);
您实际上可以util.Date
为大多数 JDBC 驱动程序提供一个标准,这些驱动程序会很高兴地吞食它,就好像它是正确的类型一样,但是当您之后请求数据时,您可能会注意到您实际上丢失了一些东西。
I'm really saying that none of the Dates should be used at all.
我真的是说根本不应该使用任何日期。
What I am saying that save the milliseconds/nanoseconds as plain longs and convert them to whatever objects you are using (obligatory joda-time plug). One hacky way which can be done is to store the date component as one long and time component as another, for example right now would be 20100221 and 154536123. These magic numbers can be used in SQL queries and will be portable from database to another and will let you avoid this part of JDBC/Java Date API:s entirely.
我所说的是将毫秒/纳秒保存为普通 long 并将它们转换为您正在使用的任何对象(强制 joda-time plug)。一种可行的方法是将日期组件存储为一个长时间组件,将时间组件存储为另一个组件,例如现在将是 20100221 和 154536123。这些幻数可以在 SQL 查询中使用,并且可以从数据库移植到另一个和将让您完全避免 JDBC/Java Date API:s 的这一部分。
回答by Paul Tomblin
The only time to use java.sql.Date
is in a PreparedStatement.setDate
. Otherwise, use java.util.Date
. It's telling that ResultSet.getDate
returns a java.sql.Date
but it can be assigned directly to a java.util.Date
.
唯一使用的时间java.sql.Date
是在PreparedStatement.setDate
. 否则,使用java.util.Date
. 它告诉我们ResultSet.getDate
返回 ajava.sql.Date
但它可以直接分配给 a java.util.Date
。
回答by gustafc
LATE EDIT:Starting with Java 8 you should use neither java.util.Date
nor java.sql.Date
if you can at all avoid it, and instead prefer using the java.time
package (based on Joda) rather than anything else. If you're not on Java 8, here's the original response:
后期编辑:从 Java 8 开始,您既不应该使用,java.util.Date
也不 应该java.sql.Date
完全避免使用它,而是更喜欢使用java.time
包(基于 Joda)而不是其他任何东西。如果您不是在 Java 8 上,以下是原始回复:
java.sql.Date
- when you call methods/constructors of libraries that use it (like JDBC). Not otherwise. You don't want to introduce dependencies to the database libraries for applications/modules that don't explicitly deal with JDBC.
java.sql.Date
- 当您调用使用它的库的方法/构造函数时(如 JDBC)。不是别的。您不想为不显式处理 JDBC 的应用程序/模块引入对数据库库的依赖关系。
java.util.Date
- when using libraries that use it. Otherwise, as little as possible, for several reasons:
java.util.Date
- 使用使用它的库时。否则,尽可能少,原因如下:
It's mutable, which means you have to make a defensive copy of it every time you pass it to or return it from a method.
It doesn't handle dates very well, which backwards people like yours truly, think date handling classes should.
Now, because j.u.D doesn't do it's job very well, the ghastly
Calendar
classes were introduced. They are also mutable, and awful to work with, and should be avoided if you don't have any choice.There are better alternatives, like the Joda Time API(
which might even make it into Java 7 and become the new official date handling API- a quick searchsays it won't).
它是可变的,这意味着每次将它传递给方法或从方法返回它时,都必须制作一个防御性副本。
它不能很好地处理日期,这让像你这样的人真正倒退,认为日期处理类应该这样做。
现在,因为 juD 不能很好地完成它的工作,所以
Calendar
引入了可怕的类。它们也是可变的,并且很难使用,如果您别无选择,应该避免使用它们。有更好的选择,比如Joda Time API(
它甚至可能进入 Java 7 并成为新的官方日期处理 API-快速搜索说它不会)。
If you feel it's overkill to introduce a new dependency like Joda, long
s aren't all that bad to use for timestamp fields in objects, although I myself usually wrap them in j.u.D when passing them around, for type safety and as documentation.
如果您觉得引入像 Joda 这样的新依赖项有点过分,那么将long
s 用于对象中的时间戳字段并不是那么糟糕,尽管我自己通常在传递它们时将它们包装在 juD 中,以确保类型安全和作为文档。
回答by Kent Tong
The java.util.Date class in Java represents a particular moment in time (e,.g., 2013 Nov 25 16:30:45 down to milliseconds), but the DATE data type in the DB represents a date only (e.g., 2013 Nov 25). To prevent you from providing a java.util.Date object to the DB by mistake, Java doesn't allow you to set a SQL parameter to java.util.Date directly:
Java 中的 java.util.Date 类表示特定时刻(例如,2013 年 11 月 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
But it still allows you to do that by force/intention (then hours and minutes will be ignored by the DB driver). This is done with the java.sql.Date class:
但它仍然允许您通过强制/意图来做到这一点(然后数据库驱动程序将忽略小时和分钟)。这是通过 java.sql.Date 类完成的:
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, new java.sql.Date(d.getTime())); //will work
A java.sql.Date object can store a moment in time (so that it's easy to construct from a java.util.Date) but will throw an exception if you try to ask it for the hours (to enforce its concept of being a date only). The DB driver is expected to recognize this class and just use 0 for the hours. Try this:
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());
}
回答by Israelm
I had the same issue, the easiest way i found to insert the current date into a prepared statement is this one:
我遇到了同样的问题,我发现将当前日期插入到准备好的语句中的最简单方法是:
preparedStatement.setDate(1, new java.sql.Date(new java.util.Date().getTime()));
回答by Abdul Alim Shakir
java.util.Date
represents a specific instant in time with millisecond precision. It represents both date and time information without timezone. The java.util.Date class implements Serializable, Cloneable and Comparable interface. It is inherited by java.sql.Date
, java.sql.Time
and java.sql.Timestamp
interfaces.
java.util.Date
表示具有毫秒精度的特定时刻。它表示没有时区的日期和时间信息。java.util.Date 类实现了 Serializable、Cloneable 和 Comparable 接口。它由java.sql.Date
、java.sql.Time
和java.sql.Timestamp
接口继承。
java.sql.Date
extends java.util.Date class which represents date without time information and it should be used only when dealing with databases. To conform with the definition of SQL DATE, the millisecond values wrapped by a java.sql.Date
instance must be 'normalized' by setting the hours, minutes, seconds, and milliseconds to zero in the particular time zone with which the instance is associated.
java.sql.Date
扩展 java.util.Date 类,它表示没有时间信息的日期,只应在处理数据库时使用。为了符合 SQL DATE 的定义,java.sql.Date
必须通过在实例关联的特定时区将小时、分钟、秒和毫秒设置为零来“规范化”实例包装的毫秒值。
It inherits all public methods of java.util.Date
such as getHours()
, getMinutes()
, getSeconds()
, setHours()
, setMinutes()
, setSeconds()
. As java.sql.Date
does not store the time information, it override all the time operations from java.util.Date
and all of these methods throw java.lang.IllegalArgumentException
if invoked as evident from their implementation details.
它继承了java.util.Date
诸如getHours()
, getMinutes()
, getSeconds()
, setHours()
, setMinutes()
,之类的所有公共方法setSeconds()
。由于java.sql.Date
不存储时间信息,它会覆盖所有时间操作,java.util.Date
并且所有这些方法java.lang.IllegalArgumentException
在调用时都会抛出,从它们的实现细节可以看出。
回答by Basil Bourque
tl;dr
tl;博士
Use neither.
都不用。
java.time.Instant
replacesjava.util.Date
java.time.LocalDate
replacesjava.sql.Date
java.time.Instant
替换java.util.Date
java.time.LocalDate
替换java.sql.Date
Neither
两者都不
java.util.Date vs java.sql.Date: when to use which and why?
java.util.Date 与 java.sql.Date:何时使用哪个以及为什么?
Both of these classes are terrible, flawed in design and in implementation. Avoid like the Plague.
Instead use java.timeclasses, defined in in JSR 310. These classes are an industry-leading framework for working with date-time handling. These supplant entirely the bloody awful legacy classes such as Date
, Calendar
, SimpleDateFormat
, and such.
而是使用JSR 310 中定义的java.time类。这些类是用于处理日期时间的行业领先框架。这些完全取代血腥可怕的遗产类,如Date
,Calendar
,SimpleDateFormat
,和这样的。
java.util.Date
java.util.Date
java.util.Date
java.util.Date
The first, java.util.Date
is meant to represent a moment in UTC, meaning an offset from UTC of zero hours-minutes-seconds.
第一个,java.util.Date
用于表示 UTC 中的一个时刻,这意味着与 UTC 的零时分秒偏移量。
java.time.Instant
java.time.Instant
Now replaced by java.time.Instant
.
现在换成了java.time.Instant
。
Instant instant = Instant.now() ; // Capture the current moment as seen in UTC.
java.time.OffsetDateTime
java.time.OffsetDateTime
Instant
is the basic building-block class of java.time. For more flexibility, use OffsetDateTime
set to ZoneOffset.UTC
for the same purpose: representing a moment in UTC.
Instant
是java.time的基本构建块类。为了获得更大的灵活性,请使用OffsetDateTime
set toZoneOffset.UTC
来实现相同的目的:用 UTC 表示一个时刻。
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
You can send this object to a database by using PreparedStatement::setObject
with JDBC4.2 or later.
您可以通过使用这个对象发送到数据库PreparedStatement::setObject
与JDBC4.2或更高版本。
myPreparedStatement.setObject( … , odt ) ;
Retrieve.
取回。
OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;
java.sql.Date
java.sql.Date
java.sql.Date
java.sql.Date
The java.sql.Date
class is also terrible and obsolete.
这java.sql.Date
门课也很糟糕而且过时了。
This class is meant to represent a date only, without a time-of-day and without a time zone. Unfortunately, in a terrible hack of a design, this class inherits from java.util.Date
which represents a moment (a date with time-of-day in UTC). So this class is merely pretending to be date-only, while actually carrying a time-of-day and implicit offset of UTC. This causes so much confusion. Never use this class.
此类仅用于表示日期,没有时间和时区。不幸的是,在一个可怕的设计黑客中,这个类继承自java.util.Date
which 代表一个时刻(UTC 中的日期时间)。所以这个类只是假装只有日期,而实际上携带了一个时间和 UTC 的隐式偏移量。这引起了很多混乱。永远不要使用这个类。
java.time.LocalDate
java.time.LocalDate
Instead, use java.time.LocalDate
to track just a date (year, month, day-of-month) without any time-of-day nor any time zone or offset.
相反,使用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).
Send to the database.
发送到数据库。
myPreparedStatement.setObject( … , ld ) ;
Retrieve.
取回。
LocalDate ld = myResultSet.getObject( … , LocalDate.class ) ;
About java.time
关于java.time
The java.timeframework is built into Java 8 and later. These classes supplant the troublesome old legacydate-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
该java.time框架是建立在Java 8和更高版本。这些类取代了麻烦的旧的遗留日期时间类,例如java.util.Date
, Calendar
, & SimpleDateFormat
。
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
要了解更多信息,请参阅Oracle 教程。并在 Stack Overflow 上搜索许多示例和解释。规范是JSR 310。
The Joda-Timeproject, now in maintenance mode, advises migration to the java.timeclasses.
现在处于维护模式的Joda-Time项目建议迁移到java.time类。
You may exchange java.timeobjects directly with your database. Use a JDBC drivercompliant with JDBC 4.2or later. No need for strings, no need for java.sql.*
classes.
您可以直接与您的数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC 驱动程序。不需要字符串,不需要类。java.sql.*
Where to obtain the java.time classes?
从哪里获得 java.time 类?
- Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6and Java SE 7
- Most of the java.timefunctionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- Later versions of Android bundle implementations of the java.timeclasses.
- For earlier Android (<26), the ThreeTenABPproject adapts ThreeTen-Backport(mentioned above). See How to use ThreeTenABP….
- Java SE 8、Java SE 9、Java SE 10、Java SE 11和更高版本 - 标准 Java API 的一部分,具有捆绑实现。
- Java 9 添加了一些小功能和修复。
- Java SE 6和Java SE 7
- 大部分java.time功能在ThreeTen-Backport中向后移植到 Java 6 & 7 。
- 安卓
- 更高版本的 Android 捆绑实现java.time类。
- 对于早期的 Android(<26),ThreeTenABP项目采用了ThreeTen-Backport(上面提到过)。请参阅如何使用ThreeTenABP ...。