Java compareTo日期不能相等

时间:2018-06-12 20:11:22

标签: java validation date compareto

我正在尝试比较2个日期,第一个日期来自MySQL数据库,第二个日期来自当前日期。

如下所示,数据库中有不同的日期

Dates records in database 但问题是我得到3个if语句,它应该告诉我的程序数据库日期是在当前日期之前,之后还是等于当前日期。 Before和After语句应该有效,但是它可以看到2018-06-12的日期应该等于当前日期,所以它在" before语句中结束"。

希望你能看到我做错了什么。

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");
        }
    }
}

3 个答案:

答案 0 :(得分:4)

ResultSet#getDate返回删除时间部分的日期。实例化新的Date对象确实包含时间,因此您必须自行删除它。 E.g:

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();

答案 1 :(得分:3)

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

你正在使用和滥用麻烦的旧日期时间课程。

正如其他人所指出的那样:

  • SQL标准DATE类型仅包含没有时间且没有时区的日期
  • 遗留java.util.Date类名称错误,日期的日期为UTC
  • 遗留java.sql.Date类假装只持有一个日期,但实际上有一个时间,因为这个类继承了上面的那个,而文档告诉我们在我们的用法中忽略这个事实。 (是的,这很令人困惑,而且是一个糟糕的设计,一个笨拙的黑客。)

切勿使用java.util.Datejava.util.Calendarjava.sql.Timestampjava.sql.Date及相关课程。相反,只使用理智的 java.time 类。他们从其前身Joda-Time项目的经验中获得了清洁设计和对日期时间处理的深入理解,引领行业发展。

对于仅限日期的值,存储在SQL标准数据库类型DATE中,请使用java.time.LocalDate

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

对于以UTC值表示时间的日期,存储在SQL标准数据库类型TIMESTAMP WITH TIME ZONE中,请使用java.time.InstantInstant类代表UTC中时间轴上的一个时刻,分辨率为nanoseconds(小数部分最多九(9)位)。

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

要在Java中进行比较,请使用isEqualisBeforeisAfterequalscompare方法。

Boolean overdue = someLocalDate.isAfter( otherLocalDate ) ;

时区

时区对于确定某个时刻(Instant / TIMESTAMP WITH TIME ZONE)的日期和时间至关重要。

TIMESTAMP WITH TIME ZONE中检索数据库中的Instant值后,请调整time zoneoffset-from-UTC,以便在感知日期时使用其挂钟时间&安培;时间的天。对于时区,请应用ZoneId以获取ZonedDateTime对象。对于来自UTC的偏移量,请应用ZoneOffset来获取OffsetDateTime对象。在任何一种情况下,都可以通过调用toLocalDate来获取LocalDate对象来提取仅限日期的值。

在您的情况下,您显然希望将日期视为UTC。因此,应用常量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.

我们希望与UTC中的当前日期进行比较。

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

比较

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

ISO 8601

避免不必要地使用自定义格式,例如“yyyy / MM / dd”。尽可能使用标准ISO 8601格式。

对于仅限日期的值,即YYYY-MM-DD。

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

H2

的示例

以下是从SQL标准LocalDate类型的数据库列中编写,查询和读取DATE对象的完整示例。

使用H2 Database Engine,因为我不是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();
}

跑步时。

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.

关于 java.time

java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.DateCalendar和&amp; SimpleDateFormat

现在位于Joda-Timemaintenance mode项目建议迁移到java.time类。

要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310

您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*类。

从哪里获取java.time类?

ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如IntervalYearWeekYearQuartermore

答案 2 :(得分:2)

这完全取决于您使用的Java版本。如果您使用的是Java 6或Java 7,那么这种方法将是最简单的方法:

当你正在处理java.sql.Date时,你可以使用这种快速方法来获取没有时间部分的Date并将java.sql.Date与java.sql.Date进行比较:

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

您还可以使用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");
    }
}

如果您使用的是Java 8,则可以使用新的Java时间API。