当您将日期分配给命名 SQL 参数时,Hibernate 会自动将其转换为 GMT 时间。你如何让它在所有日期都使用当前服务器时区?
假设您有一个查询:
Query q = session.createQuery("from Table where date_field < :now");
q.setDate("now", new java.util.Date());
“now” 将设置为 GMT 时间,而“new Date()” 获取您当前的服务器时间。
谢谢。
事实证明,Hibernate 不会自动将日期转换为 GMT,如果你使用它只会切断时间query.setDate()
,所以如果你通过 "2009-01-16 12:13:14" 它变成 "2009-01-16 00:00 :00”。
要考虑时间,您需要query.setTimestamp("date", dateObj)
改用。
Hibernate 不知道时区。任何时区转换都应在执行查询之前完成。
例如,如果您的数据库服务器设置为 CST,但用户使用的是 EST,则您需要将 1 小时添加到作为查询输入的任何时间戳。
我们使用自定义的 Hibernate 日期类型。每当我们在查询上设置参数时,我们都会使用基类或实用程序方法,这样我们就可以将用户的时区传递给自定义类型参数。
您可以通过手动调整实用程序方法中的时间来进行查询,但是这样读取或写入数据库的日期也可以正确转换。此方法还处理数据库将日期存储在其本地时区的情况。因此,即使您在一个时区有一个用户,在另一个时区有一个数据库服务器,并且 Java 使用 GMT,它也可以让一切变得简单。它最终看起来像:
Properties properties = new Properties();
properties.setProperty("timeZone", databaseTimeZone);
query.setParameter("from", dateEnteredByUser, Hibernate.custom(LocalizedDateType.class, properties));
作为额外的奖励,我们使用它来处理 SQL Server 将 23:59:59.999 转换为第二天的事实。在自定义类型中,我们检查并取消它。
如果您需要时区同步值,您可以在 HQL 中使用now()。另外我建议您使用 Joda 库。它有一个休眠插件模块。
自5.2版以来, Hibernate 团队已弃用setTimestamp(String name, Date val)方法以及org.hibernate.Query接口:
/* @deprecated (since 5.2) use {@link #setParameter(int, Object)} or
{@link #setParameter(int, Object, Type)} instead
*/
所以你可以使用下面的代码:
import org.hibernate.query.Query;
...
Query query = session.createQuery("from Table where date_field < :now");
query.setParameter("now", new Date(), TimestampType.INSTANCE );
值得注意的是,减少时间部分的setDate方法也被弃用,可以用这个选项替换(来自相同的接口 org.hibernate.query.Query):
query.setParameter("firstMomentOfToday", new Date(), DateType.INSTANCE);
If you are going to use it with java 8 and the relevent jdbc drivers like Oracle 'ojdbc8.jar' and supported hibernate versions this might not work as expected, so it's wise to use new java.time.LocalDate and LocalDateTime instead.