我正在比较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类所取代。
用Instant
和ZonedDateTime
替换您对Calendar
的使用。
对于ZonedDateTime
,显式指定所需/预期的时区,而不是隐式应用JVM的当前默认时区。默认值可能随时更改,因此您的结果可能会有所不同。最好将您想要/期望的时区明确指定为参数。
以continent/region
的格式指定适当的时区名称,例如America/Montreal
、Africa/Casablanca
或Pacific/Auckland
。千万不要使用3-4个字母的缩写,如EST
或IST
,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
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
方法equals
、isBefore
和isAfter
进行比较。
boolean sameMoment = instant.equals( instantDb ) ;
关于java.time
java.time框架构建在Java8及更高版本中。这些类取代了诸如java.util.Date
、Calendar
、&SimpleDateFormat
。
现在处于维护模式的JodaTime项目建议迁移到java.Time类。
要了解更多信息,请参阅Oracle教程。并在Stack Overflow中搜索许多示例和解释。规范是JSR310。
您可以直接与数据库交换java.time对象。使用符合JDBC 4.2或更高版本的JDBC驱动程序。不需要字符串,也不需要java.sql.*
类。
从哪里获得java.time类?
- Java SE 8、Java SE 9和更高版本
- 内置
- 标准Java API的一部分,带有捆绑实现
- Java 9添加了一些小功能和修复程序
- Java SE 6和Java SE 7
- 大部分java.time功能都是向后移植到Java6&7英寸ThreeTen背包
- 安卓
- java.time类的Android捆绑包实现的后续版本
- 对于早期的Android(<26),ThreeTenABP项目适用于ThreeTen Backport(如上所述)。请参阅如何使用ThreeTenABP…
ThreeTen Extra项目通过附加类扩展java.time。这个项目是将来可能添加到java.time的试验场。您可以在这里找到一些有用的类,如Interval
、YearWeek
、YearQuarter
等等。