use*_*862 6 java jpa spring-data-jpa java-time spring-repositories
我寻找一种方法来获取在 Postgresql 数据库中 TIMESTAMPTZ 类型的字段中保存的某个 LocalDateTime 日期上创建的对象列表。
为此,我尝试使用 JpaRepository:
List<Object> findByCreationDate(LocalDate date);
Run Code Online (Sandbox Code Playgroud)
但我收到错误:
java.lang.IllegalArgumentException: Parameter value [2020-12-12] did not match expected type [java.time.LocalDateTime (n/a)]
Run Code Online (Sandbox Code Playgroud)
我也尝试用相同的结果自己编写查询。
到目前为止我想到的解决方案:
在 Java 中获取所有对象和过滤器(但我不想去那里,所以不)
在 LocalDateTime 中转换 LocalDate 参数(但我假设在这种情况下我只会看到在同一时间创建的对象,所以不会。只有当我确定时间字段是午夜时,我才会考虑这个选项)。
创建一个方法findByCreationDateBetween(LocalDateTime startOfTheDay, LocalDateTime endOfTheDay)
(有趣的选项,但我想在不修改 LocalDate 并在一天开始和结束时将其转换为 LocalDateTime 的情况下进行查询。)
我还试图找到一些能够在查询中“转换”LocalDate 中的 LocalDateTime 或比较 LocalDate 和 LocalDateTime 的年、月和日的函数,但没有成功。creationDate 的类型应保持 LocalDateTime 和 TIMESTAMPTZ 类型的数据库字段。
是否还有其他 Jpa @Query 替代方案,总体而言,这种情况下的最佳方法是什么?
use*_*862 10
使用发布后很快被删除的答案(我必须使用列而不是属性名称,将查询标记为nativeQuery,并使用“.*”进行选择以避免org.postgresql.util.PSQLException: The column name id was not found in this ResultSet
错误),我找到了这个解决方案:
@Query(value = "SELECT e.* FROM Entity e WHERE DATE(creation_date) =:date", nativeQuery = true)
List<Entity> findByCreationDate(LocalDate date);
Run Code Online (Sandbox Code Playgroud)
或者,按照这个答案,我成功测试了第二个解决方案:
default List<Entity> findByCreationDate(LocalDate localDate) {
return findByPublicationDateBetween(localDate.atStartOfDay(), localDate.plusDays(1).atStartOfDay());
}
List<Entity> findByCreationDateBetween(LocalDateTime from, LocalDateTime to);
Run Code Online (Sandbox Code Playgroud)
您当前的解决方案很好。但@Query
你可以使用DATE()
@Query(value = "SELECT * FROM Entity u WHERE DATE(creation_date) = ?1", nativeQuery = true)
List<Entity> findByCreationDate(LocalDate date);
Run Code Online (Sandbox Code Playgroud)
我不使用 JPA、Hibernate 或 Spring,所以我必须忽略你问题的那个方面。我使用的是直接的 JDBC。
您似乎忽略了时区的关键问题。对于任何给定时刻,日期在全球各地因时区而异。在某个时刻,在日本东京可能是“明天”,而在美国俄亥俄州托莱多仍然是“昨天”。
因此,当您指定从一天开始到第二天开始的日期范围时,您必须考虑一个时区。
你说:
TIMESTAMPTZ 类型字段中的 Postgresql 数据库
TIMESTAMPTZ
Postgres 中的类型名称是标准类型名称的非标准缩写TIMESTAMP WITH TIME ZONE
。
Postgres 将所有提交的数据以 UTC 格式存储在该类型的列中,与 UTC 的偏移量为零时-分-秒。随提交输入的任何偏移量或时区首先用于将值调整为 UTC 以进行存储。存储后,任何提交的区域/偏移量信息都将被丢弃。PostgresTIMESTAMP WITH TIME ZONE
以 UTC格式存储所有值。
因此,如果您想查询一天中的值,您必须首先在所需时区中定义一天,然后将该天的开始和结束调整为 UTC 值。
String input = "2020-12-12" ;
LocalDate ld = LocalDate.parse( input ) ;
Run Code Online (Sandbox Code Playgroud)
确定在您选择的时区中看到的第一个时刻。始终让java.time确定一天中的第一个时刻,永远不要假设一天从 00:00:00 开始。某些区域中某些日期的某些天在其他时间开始,例如 01:00:00。
通常最好在日期时间处理中使用半开方法定义时间跨度。开始是包容的,而结束是排他的。这允许跨距整齐地相互邻接。
所以,你的SQL查询并不能使用BETWEEN
。您的 SQL 将类似于以下内容。请注意,更短的说法“等于或晚于”是“不在之前”(!<
在 SQL 中)。
SELECT *
FROM event_
WHERE when_ !< ?
AND when_ < ?
;
Run Code Online (Sandbox Code Playgroud)
您的 Java 看起来像这样。
ZoneId z = ZoneId.of( "Pacific/Auckland" ) ;
ZonedDateTime zdtStart = ld.atStartOfDay( z ) ;
ZonedDateTime zdtEnd = ld.plusDays( 1 ).atStartOfDay( z ) ;
Run Code Online (Sandbox Code Playgroud)
2020-12-12T00:00+13:00[太平洋/奥克兰]/2020-12-13T00:00+13:00[太平洋/奥克兰]
通过提取Instant
对象调整到 UTC 。Instant
根据定义,对象始终采用 UTC 格式。
Instant start = zdtStart.toInstant() ;
Instant end = zdtEnd.toInstant() ;
Run Code Online (Sandbox Code Playgroud)
2020-12-11T11:00:00Z/2020-12-12T11:00:00Z
您的 JDBC 如下所示:
myPreparedStatement.setObject( 1 , start ) ;
myPreparedStatement.setObject( 2 , end ) ;
Run Code Online (Sandbox Code Playgroud)
在那个 JDBC 代码中,我们传递Instant
对象。这可能有效,也可能无效,具体取决于您的 JDBC 驱动程序。奇怪的是,JDBC 4.2规范要求的支持OffsetDateTime
而不是更常用Instant
或ZonedDateTime
类型。没关系,我们可以轻松转换。
myPreparedStatement.setObject( 1 , start.atOffset( ZoneOffset.UTC ) ) ;
myPreparedStatement.setObject( 2 , end.atOffset( ZoneOffset.UTC ) ) ;
Run Code Online (Sandbox Code Playgroud)
我们可以通过调用从ZonedDateTime
到。但是这些对象的偏移量不会是UTC(零)。您的 JDBC 驱动程序和数据库应该能够处理。但出于谨慎考虑,为了调试和日志记录,我将使用 UTC,如上所示。但仅供参考,代码:OffsetDateTime
ZonedDateTime::toOffsetDateTime
myPreparedStatement.setObject( 1 , zdtStart.toOffsetDateTime() ) ;
myPreparedStatement.setObject( 2 , zdtEnd.toOffsetDateTime() ) ;
Run Code Online (Sandbox Code Playgroud)
LocalDateTime
的时刻LocalDateTime
处理时刻时切勿使用时间轴上的特定点。缺少区域/偏移量的上下文,aLocalDateTime
不能代表片刻。
归档时间: |
|
查看次数: |
14953 次 |
最近记录: |