Answers:
恭喜,您已经通过JDBC达到了我最喜欢的功能:Date类处理。
基本上,数据库通常至少支持三种形式的日期时间字段,即日期,时间和时间戳。它们中的每一个在JDBC中都有一个对应的类,并且它们各自都进行扩展java.util.Date
。这三个中的每一个的快速语义如下:
java.sql.Date
对应于SQL DATE,这表示它存储年,月和日,而时,分,秒和毫秒被忽略。此外,sql.Date
它与时区无关。java.sql.Time
对应于SQL TIME,并且应该很明显,它仅包含有关小时,分钟,秒和毫秒的信息。java.sql.Timestamp
对应于SQL TIMESTAMP,它是可自定义精度的精确日期,以纳秒为单位(请注意,util.Date
仅支持毫秒!)。在将JDBC驱动程序用于这三种类型时,最常见的错误之一是对这些类型的处理不正确。这意味着sql.Date
特定于时区,sql.Time
包含当前的年,月和日等。
确实取决于字段的SQL类型。PreparedStatement
对所有三个值都有设置器,#setDate()
分别是for sql.Date
,#setTime()
for sql.Time
和#setTimestamp()
for sql.Timestamp
。
请注意,如果使用,ps.setObject(fieldIndex, utilDateObject);
您实际上可以util.Date
为大多数JDBC驱动程序提供一个普通的驱动程序,它会很高兴地吞噬它,就好像它是正确的类型一样,但是当您随后请求数据时,您可能会注意到实际上丢失了一些东西。
我的意思是将毫秒/纳秒保存为普通的long,并将其转换为您正在使用的任何对象(强制性joda-time插件)。一种可行的方法是将日期部分存储为一个长期时间部分,将日期部分存储为另一个时间部分,例如现在将存储为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 -a快速搜索说它不会)。
如果您觉得引入像Joda这样的新依赖关系是过大的,则将long
s用于对象中的时间戳字段并不是很糟糕,尽管我本人通常在传递它们时将它们包装在juD中,以用于类型安全和用作文档。
java.sql.Date
与PreparedStatement
等!但是,当您将其传递时,请使用LocalDate
转换时使用java.sql.Date.valueOf
和java.sql.Date.valueOf
进行设置时,然后java.sql.Date.toLocalDate
再次使用- 尽快将其转换回原来的位置,因为您希望尽可能少地涉及java.sql,并且它是可变的。
唯一可以使用的时间java.sql.Date
是PreparedStatement.setDate
。否则,请使用java.util.Date
。它告诉您ResultSet.getDate
返回a,java.sql.Date
但可以将其直接分配给a java.util.Date
。
java.sql.Date
a 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
请将set设置ZoneOffset.UTC
用于相同的目的:以UTC表示时刻。
OffsetDateTime odt = OffsetDateTime.now( ZoneOffset.UTC ) ;
您可以通过使用这个对象发送到数据库PreparedStatement::setObject
与JDBC 4.2或更高版本。
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年11月25日16:30:45降至毫秒),但是数据库中的DATE数据类型仅表示日期(例如, 2013年11月25日)。为了防止错误地向数据库提供java.util.Date对象,Java不允许您直接将SQL参数设置为java.util.Date:
PreparedStatement st = ...
java.util.Date d = ...
st.setDate(1, d); //will not work
但是它仍然允许您通过强制/意图来执行此操作(然后DB驱动程序将忽略小时和分钟)。这是通过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
如果调用这些方法,则会抛出所有这些方法。