java日历比较不正确



我正在比较java中的两个Calendar对象。这就是我设置每个的方式

Calendar calendar1 = Calendar.getInstance();
calendar1.set(2012, 6, 17, 13, 0);

我从表列"2012-07-17 13:00:00"中获得以下值,并将其设置为Date Java对象,然后使用此Date对象设置第二个Calander对象。

Calendar calendar2 = Calendar.getInstance();
calendar2.setTime(/*Above date object who value is '2012-07-17 13:00:00'*/);

现在,当我比较时,我希望这是真的,因为两个日历对象都是相同的

calendar2.compareTo(calendar1) >= 0

但相反,我看到这正在成为真正的

calendar2.compareTo(calendar1) < 0

有人能帮忙吗?

以下内容将让您了解发生了什么(假设您正在解析字符串以生成calendar1的日期对象):

Calendar calendar1 = Calendar.getInstance();
calendar1.set(2012, 6, 17, 13, 0);
System.out.println(calendar1.getTime());
Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2012-07-17 13:00:00");
System.out.println(date);
Calendar calendar2 = Calendar.getInstance();
calendar2.setTime(date);
System.out.println(calendar2.compareTo(calendar1));
calendar1.set(Calendar.SECOND, 0); //setting second to 0
calendar1.set(Calendar.MILLISECOND, 0); //setting millisecond to 0
System.out.println(calendar2.compareTo(calendar1));

测试运行结果:

2012年7月17日星期二13:00:47 CDT2012年7月17日星期二13:00:00-10

根据@Bhesh Gurung的建议,我使用了以下

calendar1.set(Calendar.MILLISECOND,0);calendar1.set(Calendar.SECOND,0);

calendar2.set(Calendar.MILLISECOND,0);calendar2.set(Calendar.SECOND,0);

它奏效了。

tl;dr

ZonedDateTime.of(                              // Represent a specific moment using the wall-clock time observed by the people of a specific region (a time zone).
    2012 , Month.JULY , 17, 13 , 0 , 0 , 0 ,   // Hard-code the date and time-of-day, plus zone.
    ZoneId.of( "America/Montreal" )            // Specify time zone by Continent/Region name, never by 3-4 letter pseudo-one such as PST or CST. 
)                                              // Returns a `ZonedDateTime` object. 
.toInstant()                                   // Adjust into UTC.
.equals(
    myResultSet.getObject( … , Instant.class ) // Retrieve an `Instant` object for a date-time value stored in your database.
)

时区

你没有提供足够的信息来确定答案,但正如其他人所说,你可能看到了时区的问题。您的代码没有明确地解决这个关键问题。但是,隐含地,您创建的Calendar项目会分配一个时区。

java.time

更重要的是,您正在使用麻烦的旧日期时间类,现在被java.time类所取代。

InstantZonedDateTime替换您对Calendar的使用。

对于ZonedDateTime,显式指定所需/预期的时区,而不是隐式应用JVM的当前默认时区。默认值可能随时更改,因此您的结果可能会有所不同。最好将您想要/期望的时区明确指定为参数。

continent/region的格式指定适当的时区名称,例如America/MontrealAfrica/CasablancaPacific/Auckland。千万不要使用3-4个字母的缩写,如ESTIST,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。

ZoneId z = ZoneId.of( "America/Montreal" ) ;  
ZonedDateTime zdt = ZonedDateTime.of( 2012 , Month.JULY , 17, 13 , 0 , 0 , 0 , z );

通过提取Instant调整为UTC。Instant类表示以UTC为单位的时间线上的一个时刻,分辨率为纳秒(最多九(9)位小数)。

Instant instant = zdt.toInstant() ;

数据库

从数据库中交换对象,而不仅仅是字符串。从JDBC 4.2及更高版本开始,您可以交换java.time对象。

大多数数据库存储一个时刻,例如SQL标准类型TIMESTAMP WITH TIME ZONE,作为UTC值。所以使用Instant对象通常是最好的。

存储Instant对象的值。

myPreparedStatement.setObject( … , instant ) ;

检索。

Instant instantDb = myResultSet.getObject( … , Instant.class ) ;

使用Instant方法equalsisBeforeisAfter进行比较。

boolean sameMoment = instant.equals( instantDb ) ;

关于java.time

java.time框架构建在Java8及更高版本中。这些类取代了诸如java.util.DateCalendar、&SimpleDateFormat

现在处于维护模式的JodaTime项目建议迁移到java.Time类。

要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。

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

从哪里获得java.time类?

  • Java SE 8Java SE 9和更高版本
    • 内置
    • 标准Java API的一部分,带有捆绑实现
    • Java 9添加了一些小功能和修复程序
  • Java SE 6Java SE 7
    • 大部分java.time功能都是向后移植到Java6&7英寸ThreeTen背包
  • 安卓
    • java.time类的Android捆绑包实现的后续版本
    • 对于早期的Android(<26),ThreeTenABP项目适用于ThreeTen Backport(如上所述)。请参阅如何使用ThreeTenABP…

ThreeTen Extra项目通过附加类扩展java.time。这个项目是将来可能添加到java.time的试验场。您可以在这里找到一些有用的类,如IntervalYearWeekYearQuarter等等。

最新更新