简体   繁体   English

无法将 java.util.Date 值与 MySQL 日期时间列值进行比较

[英]Unable to compare java.util.Date value with MySQL datetime column values

I am trying to fetch the results from the table for a specific date.我正在尝试从表中获取特定日期的结果。 I am passing the Date in String format using the URL, then parsing the String date to java.util.Date and then using that to fetch the values from the table.我使用 URL 以字符串格式传递日期,然后将字符串日期解析为 java.util.Date,然后使用它从表中获取值。 Within the table, the values are stored in a column that has a data type of Datetime.在表中,值存储在数据类型为 Datetime 的列中。

@Query(value = "" +
        "FROM " +
        "   MarketingForm mf " +
        "WHERE " +
        "   (:createdAt is null OR mf.createdAt = :createdAt)" +
        "   AND (:verticalId is null OR mf.verticalId = :verticalId)" +
        "   AND (:tag is null OR mf.tag = :tag)"
)
List<MarketingForm> findAllByCreatedAtAndVerticalIdAndTag(@Param("createdAt") Date createdAt, @Param("verticalId") Long verticalId, @Param("tag") String tag);

Below is the String Date and the corresponding java.util.Date下面是字符串日期和对应的 java.util.Date

  • String Date = '2021-03-03'字符串日期 = '2021-03-03'
  • java.util.Date converted Date = 'Wed Mar 03 00:00:00 IST 2021' java.util.Date 转换日期 = 'Wed Mar 03 00:00:00 IST 2021'

Method that I am using to parse the String Date to java.util.Date -我用来将字符串日期解析为 java.util.Date 的方法 -

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
return formatter.parse(formCreatedDate);

Now I am not sure what is happening here.现在我不确定这里发生了什么。 The java.util.Date is not getting parsed correctly or whether I am doing comparison incorrectly, but the query is not able to fetch the results even though the records are there in the table. java.util.Date 未正确解析或我是否进行了不正确的比较,但即使表中有记录,查询也无法获取结果。

Why is the above SQL not able to fetch the records for the specified Date, even though there are records present in the table?为什么即使表中有记录,上面的 SQL 也无法获取指定日期的记录?

在此处输入图像描述

NOTE: The data in the table is timeformat, and I only need to compare the date component for the date.注意:表中的数据是时间格式的,我只需要比较日期的日期分量。

I am not sure exactly what you expected as your question is unclear, so I cannot give a precise answer.我不确定您的期望是什么,因为您的问题不清楚,所以我无法给出准确的答案。 But I can discuss some of the problems in your approach and your code.但我可以讨论您的方法和代码中的一些问题。

Firstly, never use java.util.Date .首先,永远不要使用java.util.Date That terrible class is part of the legacy date-time classes that were supplanted years ago by the modern java.time classes defined in JSR 310 .可怕的 class 是遗留日期时间类的一部分,多年前被JSR 310中定义的现代java.time类取代。 Likewise, never use Calendar , and never use SimpleDateFormat .同样,永远不要使用Calendar ,也永远不要使用SimpleDateFormat Sun , Oracle , and the JCP community gave up on those legacy classes upon the adoption of JSR 310, and so should you. SunOracleJCP社区在采用 JSR 310 后放弃了这些遗留类,您也应该如此。 JPA and Hibernate have both been updated to support java.time classes, as has the JDBC 4.2 specification. JPAHibernate都已更新为支持java.time类,正如Z82269B36B71AB4A1472规范一样。

Another possible problem, perhaps you are mixing up java.sql.Date with java.util.Date .另一个可能的问题,也许你正在混淆java.sql.Datejava.util.Date Be careful of your import statements there.请注意那里的import语句。 And, again, never use either of the Date classes.而且,再一次,永远不要使用任何一个Date类。

You mention a string of 2021-03-03 , but don't really explain where that is.您提到了一串2021-03-03 ,但并没有真正解释它在哪里。 At any rate, that represents a date-only value.无论如何,这代表了一个仅限日期的值。 But you say you accessing a DATETIME column in MySQL.但是您说您访问了 MySQL 中的DATETIME列。 According the the MySQL 8 documentation , that type represents a date with a time-of-day.根据MySQL 8 文档,该类型表示带有时间的日期。

The DATETIME type is used for values that contain both date and time parts. DATETIME 类型用于同时包含日期和时间部分的值。 MySQL retrieves and displays DATETIME values in 'YYYY-MM-DD hh:mm:ss' format. MySQL 以 'YYYY-MM-DD hh:mm:ss' 格式检索和显示 DATETIME 值。 The supported range is '1000-01-01 00:00:00' to '9999-12-31 23:59:59'.支持的范围是“1000-01-01 00:00:00”到“9999-12-31 23:59:59”。

So querying a date-with-time column by a date-only value makes no sense.因此,通过仅日期值查询日期时间列是没有意义的。 The database cannot compare a date-only value to a date-with-time.数据库无法将仅日期值与日期与时间进行比较。 You need to specify a span of time, a pair of date-with-time values for your start and end.您需要为您的开始和结束指定一个时间跨度,一对日期与时间值。

Another problem: You are trying to use java.util.Date which represents a moment, a specific date with time as seen in the context of UTC — but the DATETIME type in MySQL is a different animal.另一个问题:您正在尝试使用java.util.Date代表时刻,即在 UTC 上下文中看到的带有时间的特定日期 - 但 MySQL 中的DATETIME类型是不同的动物。 The DATETIME type in MySQL represents a date with a time-of-day but lacks the context of an offset or time zone. MySQL 中的DATETIME类型表示具有时间的日期,但缺少偏移量或时区的上下文。 This type is akin to the SQL type TIMESTAMP WITHOUT TIME ZONE .此类型类似于 SQL 类型TIMESTAMP WITHOUT TIME ZONE

Beware: If you are trying to represent moments in your database, specific points on the timeline, then you are using the wrong data type for your column.注意:如果您试图在数据库中表示时刻、时间线上的特定点,那么您为列使用了错误的数据类型 For moments, you must use a data type akin to the SQL-standard TIMESTAMP WITH TIME ZONE .对于时刻,您必须使用类似于 SQL 标准TIMESTAMP WITH TIME ZONE的数据类型。 In MySQL 8, that would be the TIMESTAMP type.在 MySQL 8 中,这将是TIMESTAMP类型。 The TIMESTAMP type in MySQL tracks moments as seen in UTC, always in UTC. MySQL 中的TIMESTAMP类型跟踪以 UTC 显示的时刻,始终以 UTC 为单位。 If your column in question is the one named createdAt , then you almost certainly are using the wrong data type, as tracking moments that passed as history must be done with SQL-standard TIMESTAMP WITH TIME ZONE .如果您有问题的列是名为createdAt的列,那么您几乎可以肯定使用了错误的数据类型,因为必须使用 SQL 标准TIMESTAMP WITH TIME ZONE来跟踪作为历史记录传递的时刻。 But I will ignore this crucial issue, and carry on with regard to the type you specified in your Question as written.但是我将忽略这个关键问题,并继续您在问题中指定的类型。

If you are not tracking moments, such as tracking future appointments alongside time zone saved in an additional column, then your use of DATETIME would be correct.如果您跟踪时刻,例如跟踪保存在附加列中的时区旁边的未来约会,那么您对DATETIME的使用是正确的。 If you are sure of this datatype for your purpose, then in Java the appropriate match would be LocalDateTime class.如果您确定此数据类型用于您的目的,那么在 Java 中,适当的匹配将是LocalDateTime class。

Do your query for a day's worth of data over a DATETIME column by using the half-open approach to defining a span of time.通过使用半开放方法定义时间跨度,查询DATETIME列上一天的数据。 The start is inclusive while the end is exclusive .开始是包容的,而结束是排斥的。 So a day starts at first moment of the day and runs up to, but does not include, the start of the next day.因此,一天从一天的第一刻开始,一直持续到但不包括第二天的开始。 With half-open, we do not use the SQL keyword BETWEEN .半开时,我们使用 SQL 关键字BETWEEN

Here is a simple code example to adapt to your situation.这是一个简单的代码示例以适应您的情况。 I use neither Spring nor Hibernate, so you will have to translate accordingly.我既不使用 Spring 也不使用 Hibernate,因此您必须进行相应的翻译。

For your date-only input string, parse as a LocalDate .对于仅限日期的输入字符串,解析为LocalDate

Tip: A short way of asking "Is greater than or equal" is "Is not less than".提示:询问“大于或等于”的简短方法是“不小于”。 We see this on the first case of the predicate in the SELECT statement below.我们在下面的 SELECT 语句中的谓词的第一个案例中看到了这一点。

LocalDate ld = LocalDate.parse( "2021-03-03" ) ;
LocalDateTime startOfDay = ld.atStartOfDay() ;
LocalDateTime startOfNextDay = ld.plusDays( 1 ).atStartOfDay() ;
String sql = "SELECT * FROM my_table WHERE when !< ? AND when < ? ;" ;  // Performing query over a span-of-time defined as Half-Open. 
…
myPreparedStatement.setObject( 1 , startOfDay ) ;
myPreparedStatement.setObject( 2 , startOfNextDay ) ;

Retrieving DATETIME values.检索DATETIME值。

LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class ) ;

All this has been discussed many many times already on Stack Overflow.所有这些已经在 Stack Overflow 上讨论过很多次了。 Search to learn more.搜索以了解更多信息。

Java(传统和现代)和标准 SQL 中的日期时间类型表

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM