简体   繁体   English

Java compareTo日期不能相等

[英]Java compareTo Dates cannot be equal

I am trying to compare 2 dates, the first date is from the MySQL database, and the second is from the current date. 我想比较2个日期,第一个日期来自MySQL数据库,第二个日期来自当前日期。

as you can see below, there are different dates in the database 如下所示,数据库中有不同的日期

日期记录在数据库中 But the problem is that I got 3 if statements, which should tell my program if the Database date is before, after or equal the current date. 但问题是我得到3个if语句,它应该告诉我的程序数据库日期是在当前日期之前,之后还是等于当前日期。 The Before and After statements should work, but it can see the date 2018-06-12 should be equal to the current date so it ends in the "before statement". Before和After语句应该有效,但是它可以看到2018-06-12的日期应该等于当前日期,因此它以“before statement”结束。

Hope you can see what I have done wrong. 希望你能看到我做错了什么。

private static void Resetter() throws ParseException, SQLException {
    String host = "****";
    String username = "root";
    String mysqlpassword = "";

    //Querys
    String query = "select * from accounts";
    String queryy = "update accounts set daily_search_count = 0 where id = ?";
    Connection con = DriverManager.getConnection(host, username, mysqlpassword);
    Statement st = con.createStatement();
    ResultSet rs = st.executeQuery(query);

    DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
    dateFormat.setTimeZone( TimeZone.getTimeZone( "UTC" ));
    Date currentDate = new Date();

    while(rs.next()){
        System.out.println(dateFormat.format(currentDate));
        if (rs.getDate(5).compareTo(currentDate) > 0) {
           // System.out.println("Database-date is after currentDate");
        } else if (rs.getDate(5).compareTo(currentDate) < 0) {
           // System.out.println("Database-date is before currentDate");
            PreparedStatement updatexdd = con.prepareStatement(queryy);
            updatexdd.setInt(1, rs.getInt(1));
            int updatexdd_done = updatexdd.executeUpdate();
        } else if (rs.getDate(5).compareTo(currentDate) == 0) {
           // System.out.println("Database-date is equal to currentDate");
        } else {
            System.out.println("Any other");
        }
    }
}

ResultSet#getDate returns a date with the time part removed. ResultSet#getDate返回删除时间部分的日期。 Instantiating a new Date object does contain the time, so you'll have to remove it yourself. 实例化一个新的Date对象确实包含时间,因此您必须自己删除它。 Eg: 例如:

Calendar cal = Calendar.getInstance();
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
Date currentDate = cal.getTime();

tl;dr TL;博士

LocalDate today = LocalDate.now( ZoneOffset.UTC ) ;
Instant instant = myResultSet.getObject( … , Instant.class ) ;  // Retrieve a `TIMESTAMP WITH TIME ZONE` value in database as an `Instant` for a date with time-of-day in UTC with a resolution as fine as nanoseconds.
LocalDate ld = instant.atOffset( ZoneOffset.UTC ).toLocalDate() ;  // Extract a date-only value without time-of-day and without time zone.

if ( ld.isBefore( today ) ) { … }       // Compare `LocalDate` objects.
else if ( ld.isEqual( today ) ) { … }
else if ( ld.isAfter( today ) ) { … }
else { … handle error }

java.time java.time

You are using, and misusing, troublesome old date-time classes. 您正在使用并滥用麻烦的旧日期时间类。

As others pointed out: 正如其他人指出:

  • A SQL-standard DATE type holds only a date without a time-of-day and without a timezone SQL标准DATE类型仅包含没有时间和没有时区的日期
  • The legacy java.util.Date class is misnamed, holding both a date and a time-of-day in UTC . 遗留的java.util.Date类名称错误,以UTC格式保存日期时间。
  • The legacy java.sql.Date class pretends to hold only a date but actually has a time-of-day because this class inherits from the one above, while the documentation tells us to ignore that fact in our usage. 遗留的java.sql.Date类假装只保留一个日期但实际上有一个时间,因为这个类继承了上面的那个,而文档告诉我们在我们的用法中忽略这个事实。 (Yes, this is confusing, and is a bad design, a clumsy hack.) (是的,这很令人困惑,而且是一个糟糕的设计,一个笨拙的黑客。)

Never use the java.util.Date , java.util.Calendar , java.sql.Timestamp , java.sql.Date , and related classes. 切勿使用java.util.Datejava.util.Calendarjava.sql.Timestampjava.sql.Date和相关类。 Instead, use only the sane java.time classes. 相反,只使用理智的java.time类。 They lead the industry in clean-design and depth of understanding of date-time handling gleaned from the experience of their predecessor, the Joda-Time project. 他们从其前身Joda-Time项目的经验中获得了清洁设计和对日期时间处理的深入理解,引领行业发展。

For date-only value, stored in SQL-standard database type of DATE , use java.time.LocalDate . 对于仅限日期的值,存储在DATE SQL标准数据库类型中,请使用java.time.LocalDate

LocalDate ld = myResultSet.get( … , LocalDate.class ) ;  // Retrieving from database.
myPreparedStatement.setObject( … , ld ) ;  // Storing in database.

For a date with time-of-day in UTC value, stored in a SQL-standard database type of TIMESTAMP WITH TIME ZONE , use java.time.Instant . 对于具有UTC时间值的日期,存储在SQL标准数据库类型TIMESTAMP WITH TIME ZONE ,请使用java.time.Instant The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction). Instant类表示UTC时间轴上的一个时刻,分辨率为纳秒 (最多九(9)位小数)。

Instant instant = myResultSet.get( … , Instant.class ) ;  // Retrieving from database.
myPreparedStatement.setObject( … , instant ) ;  // Storing in database.

For comparing in Java, use the isEqual , isBefore , isAfter , equals , or compare methods. 要在Java中进行比较,请使用isEqualisBeforeisAfterequalscompare方法。

Boolean overdue = someLocalDate.isAfter( otherLocalDate ) ;

Time zone 时区

Time zone is crucial in determining a date and a time-of-day from a moment ( Instant / TIMESTAMP WITH TIME ZONE ). 时区对于确定日期和时刻( Instant / TIMESTAMP WITH TIME ZONE )至关重要。

After retrieving your TIMESTAMP WITH TIME ZONE value from the database as an Instant , adjust into the time zone or offset-from-UTC whose wall-clock time you want to use in perceiving a date & time-of-day. 从数据库中检索TIMESTAMP WITH TIME ZONE值作为Instant ,调整为时区UTC偏移量,您想要使用它的挂钟时间来感知日期和时间。 For a time zone, apply a ZoneId to get a ZonedDateTime object. 对于时区,应用ZoneId以获取ZonedDateTime对象。 For an offset-from-UTC, apply a ZoneOffset to get a OffsetDateTime object. 对于UTC的偏移量,应用ZoneOffset来获取OffsetDateTime对象。 In either case, extract a date-only value by calling toLocalDate to get a LocalDate object. 在任何一种情况下,通过调用toLocalDate来获取LocalDate对象来提取仅日期值。

In your case, you apparently want to perceive the date as UTC. 在您的情况下,您显然希望将日期视为UTC。 So apply the constant, ZoneOffset.UTC to get an OffsetDateTime 因此,应用常量ZoneOffset.UTC来获取OffsetDateTime

OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;  
LocalDate ld = odt.toLocalDate() ;   // Extract a date-only value without time-of-day and without time zone.

We want to compare with current date in UTC. 我们希望与UTC中的当前日期进行比较。

LocalDate today = LocalDate.now( ZoneOffset.UTC ) ;  // Specify the offset/zone by which you want to perceive the current date.

Compare. 相比。

if ( ld.isBefore( today ) ) { … }
else if ( ld.isEqual( today ) ) { … }
else if ( ld.isAfter( today ) ) { … }
else { … handle error }

ISO 8601 ISO 8601

Avoid unnecessarily using custom formats such as "yyyy/MM/dd". 避免不必要地使用自定义格式,例如“yyyy / MM / dd”。 Use standard ISO 8601 formats whenever possible. 尽可能使用标准ISO 8601格式。

For a date-only value, that would be YYYY-MM-DD. 对于仅限日期的值,即YYYY-MM-DD。

String output = LocalDate.now().toString() ;  // Ex: 2018-01-23

Example with H2 H2的例子

Here is a full example of writing, querying, and reading LocalDate objects from a database column of SQL-standard DATE type. 以下是从SQL标准DATE类型的数据库列中编写,查询和读取LocalDate对象的完整示例。

Using the H2 Database Engine , as I am not a MySQL user. 使用H2数据库引擎 ,因为我不是MySQL用户。 Creating an in-memory database rather than writing to storage. 创建内存数据库而不是写入存储。 I assume the code would be nearly the same for MySQL. 我假设MySQL的代码几乎相同。

try (
    Connection conn = DriverManager.getConnection( "jdbc:h2:mem:trashme" )
) {
    String sql = "CREATE TABLE " + "tbl_" + " (\n" +
                     "  uuid_ UUID DEFAULT random_uuid() , \n" +  // Every table should have a primary key.
                     "  when_ DATE \n" +                          // Three columns per the Question.
                     " );";
    try (
        Statement stmt = conn.createStatement() ;
    ) {
        stmt.execute( sql );
    }

    sql = "INSERT INTO tbl_ ( when_ ) VALUES ( ? ) ;";
    LocalDate start = LocalDate.of( 2018 , Month.JANUARY , 23 );
    LocalDate ld = start;  // Keep the `start` object for use later.
    try (
        PreparedStatement ps = conn.prepareStatement( sql )
    ) {
        for ( int i = 1 ; i <= 10 ; i++ ) {
            ps.setObject( 1 , ld );
            ps.executeUpdate();
            // Prepare for next loop.
            int randomNumber = ThreadLocalRandom.current().nextInt( 1 , 5 + 1 ); // Pass minimum & ( maximum + 1 ).
            ld = ld.plusDays( randomNumber ); // Add a few days, an arbitrary number.
        }
    }

    // Dump all rows, to verify our populating of table.
    System.out.println( "Dumping all rows: uuid_ & when_ columns." );
    sql = "SELECT uuid_ , when_ FROM tbl_ ; ";
    int rowCount = 0;
    try (
        Statement stmt = conn.createStatement() ;
        ResultSet rs = stmt.executeQuery( sql ) ;
    ) {
        while ( rs.next() ) {
            rowCount++;
            UUID uuid = rs.getObject( 1 , UUID.class );
            LocalDate localDate = rs.getObject( 2 , LocalDate.class );
            System.out.println( uuid + " " + localDate );
        }
    }
    System.out.println( "Done dumping " + rowCount + " rows." );


    // Dump all rows, to verify our populating of table.
    System.out.println( "Dumping rows where `when_` is after " + start + ": uuid_ & when_ columns." );
    sql = "SELECT uuid_ , when_ FROM tbl_ WHERE when_ > ? ; ";
    rowCount = 0; // Reset count.
    final PreparedStatement ps = conn.prepareStatement( sql );
    ps.setObject( 1 , start );
    try (
        ps ;
        ResultSet rs = ps.executeQuery() ;
    ) {
        while ( rs.next() ) {
            rowCount++;
            UUID uuid = rs.getObject( 1 , UUID.class );
            LocalDate localDate = rs.getObject( 2 , LocalDate.class );
            System.out.println( uuid + " " + localDate );
        }
    }
    System.out.println( "Done dumping " + rowCount + " rows." );

} catch ( SQLException eArg ) {
    eArg.printStackTrace();
}

When run. 跑步时

Dumping all rows: uuid_ & when_ columns.
e9c75998-cd67-4ef9-9dce-6c1eed170387 2018-01-23
741c1452-e224-4e5e-95bc-904d8db58b39 2018-01-27
413de43c-a1be-40b6-9ccf-a9b7d9ba873c 2018-01-31
e2aa148f-48b6-4be6-a0fe-f2881b6b5a63 2018-02-03
f498003c-2d8b-446e-ac55-6d7568ce61c3 2018-02-06
c41606d7-8c05-4bba-9f8e-2a0d1f1bb31a 2018-02-09
3df3abe3-1865-4632-99c4-6cd74883c1ee 2018-02-10
914153fe-34f2-4e4f-a91b-944314994839 2018-02-13
96436bdf-80ee-4afe-b55d-f240140ace6a 2018-02-16
82b43f7b-077d-45c1-8c4f-f5b30dfdd44a 2018-02-19
Done dumping 10 rows.
Dumping rows where `when_` is after 2018-01-23: uuid_ & when_ columns.
741c1452-e224-4e5e-95bc-904d8db58b39 2018-01-27
413de43c-a1be-40b6-9ccf-a9b7d9ba873c 2018-01-31
e2aa148f-48b6-4be6-a0fe-f2881b6b5a63 2018-02-03
f498003c-2d8b-446e-ac55-6d7568ce61c3 2018-02-06
c41606d7-8c05-4bba-9f8e-2a0d1f1bb31a 2018-02-09
3df3abe3-1865-4632-99c4-6cd74883c1ee 2018-02-10
914153fe-34f2-4e4f-a91b-944314994839 2018-02-13
96436bdf-80ee-4afe-b55d-f240140ace6a 2018-02-16
82b43f7b-077d-45c1-8c4f-f5b30dfdd44a 2018-02-19
Done dumping 9 rows.

About java.time 关于java.time

The java.time framework is built into Java 8 and later. java.time框架内置于Java 8及更高版本中。 These classes supplant the troublesome old legacy date-time classes such as java.util.Date , Calendar , & SimpleDateFormat . 这些类取代了麻烦的旧遗留日期时间类,如java.util.DateCalendarSimpleDateFormat

The Joda-Time project, now in maintenance mode , advises migration to the java.time classes. 现在处于维护模式Joda-Time项目建议迁移到java.time类。

To learn more, see the Oracle Tutorial . 要了解更多信息,请参阅Oracle教程 And search Stack Overflow for many examples and explanations. 并搜索Stack Overflow以获取许多示例和解释。 Specification is JSR 310 . 规范是JSR 310

You may exchange java.time objects directly with your database. 您可以直接与数据库交换java.time对象。 Use a JDBC driver compliant with JDBC 4.2 or later. 使用符合JDBC 4.2或更高版本的JDBC驱动程序 No need for strings, no need for java.sql.* classes. 不需要字符串,不需要java.sql.*类。

Where to obtain the java.time classes? 从哪里获取java.time类?

The ThreeTen-Extra project extends java.time with additional classes. ThreeTen-Extra项目使用其他类扩展了java.time。 This project is a proving ground for possible future additions to java.time. 该项目是未来可能添加到java.time的试验场。 You may find some useful classes here such as Interval , YearWeek , YearQuarter , and more . 您可以在这里找到一些有用的类,比如IntervalYearWeekYearQuarter ,和更多

It all depends on the Java version that you are using. 这一切都取决于您使用的Java版本。 If you are using Java 6 or Java 7 then this approach will be the easiest: 如果您使用的是Java 6或Java 7,那么这种方法将是最简单的方法:

As you are dealing with java.sql.Date anyways, you can use this quick approach to get Date without time part and compare java.sql.Date to java.sql.Date: 无论如何,当你正在处理java.sql.Date时,你可以使用这种快速方法来获取没有时间部分的Date,并将java.sql.Date与java.sql.Date进行比较:

Date currentDate = new java.sql.Date(System.currentTimeMillis());

You can also use java.util.Date#before and java.util.Date#after methods for the better code readability: 您还可以java.util.Date#after方法java.util.Date#before使用java.util.Date#beforejava.util.Date#after以获得更好的代码可读性:

while(rs.next()){
    System.out.println(dateFormat.format(currentDate));
    if (rs.getDate(5).after(currentDate)) {
       // System.out.println("Database-date is after currentDate");
    } else if (rs.getDate(5).before(currentDate)) {
       // System.out.println("Database-date is before currentDate");
        PreparedStatement updatexdd = con.prepareStatement(queryy);
        updatexdd.setInt(1, rs.getInt(1));
        int updatexdd_done = updatexdd.executeUpdate();
    } else {
       // System.out.println("Database-date is equal to currentDate");
    }
}

If you are using Java 8 then you can use new Java time API. 如果您使用的是Java 8,则可以使用新的Java时间API。

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

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