我有一个记录列表,每个记录中都有日期对象。我正在检查第一条记录的日期应早于第二条记录,第二条记录的日期应少于第三条记录,依此类推。这是我的代码。
for(int i = 0; i < machines.size(); i++) {
for(int j = i + 1; j < machines.size(); j++) {
if((machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
* machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()) >= 0)
||
(machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
* machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()) >= 0)) {
throw new Exception("Dates are not as per criteria..");
}
}
}
我来自数据库的日期是:
STRT_DT END_DT
---------- ----------
2014-01-01 2014-12-31
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2016-12-31
2017-01-01 2017-12-31
2018-01-01 2018-02-01
我错过了什么吗?任何帮助将不胜感激..
答案 0 :(得分:3)
您过于复杂了。检查成对条目就足够了,因为a
for(int i = 0; i < machines.size() - 1; i++) {
if (! machines.get(i).getEnd_Dt().before(machines.get(i + 1).getStrt_Dt())) {
throw new IllegalStateException("Dates are not in chronological order");
}
}
我使用“不早于”来表示“在……上”。或者换一种说法,我要求每个开始日期必须在下一个开始日期之前严格,否则,我会抛出异常。 编辑:我不知道如何从您的对象类型中获取结束日期,因此请在我编写的getEnd_Dt()
处替换正确的getter调用。
如果您还需要检查每台机器的开始日期和结束日期的顺序正确(使用增强的for
循环):
for (Machine m : machines) {
if (m.getEnd_Dt().before(m.getStrt_Dt())) {
throw new IllegalStateException("Dates are not in chronological order");
}
}
顺便说一句,Java命名约定没有在名称中使用下划线(CONSTANT_NAME
除外),因此与getStrtDt
相比,getStrt_Dt
更受欢迎。甚至更好,getStartDate
。
也就是说,Embid123是正确的,您应该查看是否可以将Date
替换为LocalDate
。 Date
类存在设计问题,并且已经过时了。尽管它的名称不代表日期,但代表时间点。 LocalDate
是现代Java日期和时间API java.time的一部分,使用起来非常好。
您需要做的另一件事是让数据库查询按开始日期对条目进行排序,然后知道您以正确的顺序获得了它们。
首先,您的代码在不可读的边界上很复杂。
接下来,当两个条目i
和j
的开始日期顺序错误时,即j
日期早于i
日期,则{ {1}}为负,machines.get(j).getStrt_Dt().compareTo(machines.get(i).getStrt_Dt())
为正。确实是一样的比较,只是相反。因此乘积将为负,您的machines.get(i).getStrt_Dt().compareTo(machines.get(j).getStrt_Dt()
条件将为false,并且不会引发异常。
仅当两个条目具有完全相同的日期(以毫秒为单位)时,>= 0
返回0,乘积为0,compareTo
为true,并且将引发您的异常。
答案 1 :(得分:2)
使用现代的java.time.LocalDate
和org.threeten.extra.LocalDateRange
类将您的业务逻辑简化为基本上一行,询问列表中的上一个项目是否不在当前项目之前。
if (
!
prior
.getDateRange()
.isBefore(
current.getDateRange()
)
) { … handle rule violation … }
另请参阅correct Answer by Ole V.V.
切勿使用设计不良的旧类。 java.util.Date
类(尽管命名)代表一个时刻,一个带有UTC时间的日期。 java.sql.Date
类伪装为仅表示日期,但实际上还涉及时间和偏移量。
现代方法使用 java.time 类。
LocalDate
LocalDate
类表示没有日期,没有time zone或offset-from-UTC的仅日期值。
您可以用数字设置月份,一月至十二月的理智编号为1-12。
LocalDate ld = LocalDate.of( 1986 , 2 , 23 ) ; // Years use sane direct numbering (1986 means year 1986). Months use sane numbering, 1-12 for January-December.
或者更好的是,使用预定义的Month
枚举对象,每年的每个月使用一个。提示:在整个代码库中使用这些Month
对象,而不是仅使用整数,可以使您的代码更具自文档性,确保有效值并提供type-safety。
LocalDate ld = LocalDate.of( 1986 , Month.FEBRUARY , 23 ) ;
您可以直接解析标准ISO 8601格式的字符串:YYYY-MM-DD
LocalDate ld = LocalDate.parse( "2018-01-23" ) ;
要解析其他格式,请搜索堆栈溢出以了解DateTimeFormatter
。
LocalDateRange
您似乎在Machine
类中使用了一对日期,即开始日期和结束日期。
有一类。将ThreeTen-Extra库添加到您的项目中以访问LocalDateRange
类。此类具有一些非常有用的比较方法。使用此类大大简化了代码,并使业务逻辑的意图更加明显。
将您的停止/开始日期存储为LocalDateRange
对象上的Machine
对象。
private LocalDateRange dateRange;
通常,跟踪时间跨度的最佳方法是半开放式方法。开头是包含,结尾是包含。
因此,一周的定义是从一天(例如星期一)开始,一直到(但不包括)下周的同一天,例如下一个星期一。一年从一年的1月1日开始,一直到第二年的1月1日,但确实包括在内。
使用半开放式方法将意味着定义您的示例日期,如下所示。请注意,将第1、3和4行中的结束日期更改为全年值与您自己对第2行和第5行的明显月份值的定义相匹配。
STRT_DT END_DT
---------- ----------
2014-01-01 2015-01-01
2013-01-01 2013-02-01 (Here the second record is having the date less than first record), this should fail
2016-01-01 2017-01-01
2017-01-01 2018-01-01
2018-01-01 2018-02-01
Machine
以下是您的课程Machine
的一些示例代码。
package com.basilbourque.example;
import org.threeten.extra.LocalDateRange;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;
public class Machine {
private String name;
private LocalDateRange dateRange;
// Constructor
public Machine ( String name , LocalDate start , LocalDate stop ) {
Objects.requireNonNull( name );
Objects.requireNonNull( start );
Objects.requireNonNull( stop );
// TODO: Add checks to validate data, such as dates being not too far into the past or future, and name being non-empty.
this.name = name;
this.dateRange = LocalDateRange.of( start , stop );
}
// -------| Accessors |--------------------------
public String getName ( ) {
return this.name;
}
public LocalDateRange getDateRange ( ) {
return this.dateRange;
}
// -------| Object |--------------------------
@Override
public String toString ( ) {
return "Machine{ " +
"name='" + name + '\'' +
" | dateRange=" + dateRange +
" }";
}
}
让我们通过编写main
方法来尝试此类。
public static void main ( String[] args ) {
List < Machine > machines =
List.of(
new Machine( "one" , LocalDate.parse( "2014-01-01" ) , LocalDate.parse( "2015-01-01" ) ) ,
new Machine( "two" , LocalDate.parse( "2013-01-01" ) , LocalDate.parse( "2013-02-01" ) ) , // Violates rule, where date-range should be *after* the prior one.
new Machine( "three" , LocalDate.parse( "2016-01-01" ) , LocalDate.parse( "2017-01-01" ) ) ,
new Machine( "four" , LocalDate.parse( "2017-01-01" ) , LocalDate.parse( "2018-01-01" ) ) ,
new Machine( "five" , LocalDate.parse( "2018-01-01" ) , LocalDate.parse( "2018-02-01" ) )
);
// Compare
for ( int i = 1 ; i < machines.size() ; i++ ) { // Using annoying zero-based index counting.
Machine prior = machines.get( i - 1 );
Machine current = machines.get( i );
if ( ! prior.getDateRange().isBefore( current.getDateRange() ) ) {
System.out.println( "BAD: Machine at index " + ( i - 1 ) + " is not before Machine at index " + i + " ➙ " + prior.getDateRange().toString() + " versus " + current.getDateRange().toString() );
}
}
}
运行时。
不良:索引0的计算机不在索引1的计算机之前➙2014-01-01 / 2015-01-01与2013-01-01 / 2013-02-01
从JDBC 4.2及更高版本开始,我们可以直接与数据库交换 java.time 对象。
LocalDate start = myResultSet.getObject( "start_date" , LocalDate.class ) ;
java.time框架已内置在Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和SimpleDateFormat
。
目前位于Joda-Time的maintenance 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中添加内容提供了一个试验场。您可能会在这里找到一些有用的类,例如Interval
,YearWeek
,YearQuarter
和more。
答案 2 :(得分:0)
您是否正在使用LocalDate?我认为这是比较日期的好选择。从Java 8开始。
package sample;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class LocalDateTest {
public static void main(String[] args) {
//of(year, month, day)
LocalDate date1 = LocalDate.of(2018, 11, 11);
LocalDate date2 = LocalDate.of(2018, 11, 14);
long daysBetween = ChronoUnit.DAYS.between(date1, date2);
System.out.println(daysBetween);
}
}
LocalDate没有任何公共构造函数,您可以通过静态工厂方法创建一个对象。 通过使用枚举ChronoUnit,您将获得一个长值,表示从一个日期到第二个日期的天,周或年。如果你想计算星期之间的时间,只需用WEEKS代替DAYS。
现在比较日期很简单,如果值是负数,则第一个日期超过第二个日期。
LocalDate的文档:https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html