我已经整理了一个方法,该方法应该检查给定日期是否在某个下限和上限之内。
不应该考虑时间,只考虑日期。这似乎是一项非常简单的任务,但在调试时我会遇到一些奇怪的行为。
我尝试过从输入日期中删除时间值的不同方法。 (inDate
。)但是他们似乎都给了我同样的意外行为,即将inLeft
日期放在inLeft
之前,从而使函数结果为假。
正如您从屏幕截图中看到的inLeft
和inLeft
相等(如果我们忽略了时间),为什么int leftLimit = DateTimeComparator.getDateOnlyInstance().compare(inLeft, inDate);
会导致1而不是0?
我的结论是我做错了但找不到什么。如果这是非常明显的话,请原谅我。
这是我的代码:
protected boolean checkDateInRange(Date inDate, Date inLeft, Date inRight) {
System.out.println("inDate = " + inDate);
System.out.println("inLeft = " + inLeft);
System.out.println("inRight = " + inRight);
int leftLimit = DateTimeComparator.getDateOnlyInstance().compare(inLeft, inDate);
int rightLimit = DateTimeComparator.getDateOnlyInstance().compare(inDate, inRight);
System.out.println("leftLimit = " + leftLimit);
System.out.println("rightLimit = " + rightLimit);
if (leftLimit > 0 || rightLimit > 0) {
return false;
}
return true;
}
I/System.out: inDate = Mon Sep 26 00:00:00 GMT+02:00 2016
I/System.out: inLeft = Mon Sep 26 20:14:13 GMT+02:00 2016
I/System.out: inRight = Mon Sep 26 00:00:00 GMT+02:00 2016
I/System.out: leftLimit = 1
I/System.out: rightLimit = 0
问题是leftLimit == 1,而不是0,inDate和inLeft没有时间是相同的。但leftLimit仍然是1。
修改(最终解决方案): 根据sumandas'和Roberts的解决方案,我写了一个新的方法,给了我预期的行为。
新代码:
protected boolean checkDateInRange(Date inDate, Date inLeft, Date inRight) {
SimpleDateFormat simpleDateFormatter = new SimpleDateFormat("yyyy-MM-dd");
String dateString = simpleDateFormatter.format(inDate);
String leftString = simpleDateFormatter.format(inLeft);
String rightString = simpleDateFormatter.format(inRight);
if (leftString.compareTo(dateString) > 0 || dateString.compareTo(rightString) > 0)
return false;
return true;
}
我仍然不明白为什么我的初始解决方案不起作用。
答案 0 :(得分:0)
试试这个:
String date1 = "2014/09/12"
String date2 = "2016/09/12"
SimpleDateFormat simpleDateFormatter = new SimpleDateFormat("yyyy-MM-dd");
Date inDate = simpleDateFormatter.parse(date1);
Date inLeft = simpleDateFormatter.parse(date2);
Date rightDate = simpleDateFormatter.parse(date2);
将这些传递给下面的函数并进行比较:
protected boolean checkDateInRange(Date inDate, Date inLeft, Date inRight) {
if (inDate.before(inLeft) || inDate.after(inRight)) {
// Do something
}
}
我的两分钱,我之前尝试使用Joda Time而且由于太多而无法切换到simpledateformat,但是joda时间在ISO日期格式中有很多帮助。
为什么建议的解决方案无法运作: 如果您阅读documentation,则说LHS< RHS返回-ve 否则返回+ ve
现在以您的示例为例,getDateOnlyInstance仅返回
的日期LHS = Sep 26 2016 = RHS and returns a 1. // Hope this helps.
答案 1 :(得分:0)
根据评论,我假设您正在使用joda-time API(我使用版本2.7 进行此测试)。
为了解释为什么你的第一次尝试不起作用,我已经做了一个测试。首先,我为您的测试输入创建了等效的DateTime
对象:
// equivalent date/times in GMT+02:00
DateTime in = new DateTime(2016, 9, 26, 0, 0, 0, 0, DateTimeZone.forOffsetHours(2));
DateTime left = new DateTime(2016, 9, 26, 20, 14, 13, 0, DateTimeZone.forOffsetHours(2));
DateTime right = new DateTime(2016, 9, 26, 0, 0, 0, 0, DateTimeZone.forOffsetHours(2));
然后我打电话给你的方法:
// using toDate to convert org.joda.time.DateTime to java.util.Date
checkDateInRangeWrong(in.toDate(), left.toDate(), right.toDate());
我得到的输出:
inDate = Sun Sep 25 19:00:00 BRT 2016
inLeft = Mon Sep 26 15:14:13 BRT 2016
inRight = Sun Sep 25 19:00:00 BRT 2016
请注意inDate
天 25 (而不是 26 ),时间 19 (而不是 00 )。另请注意,时区为 BRT (而不是 GMT + 02:00 )。
这是因为在使用DateTimeComparator.compare()
个实例调用java.util.Date
时,它会使用默认时区来转换对象。
由于我的默认时区(java.util.TimeZone.getDefault()
)是" America / Sao_Paulo" (或 BRT - 巴西标准时间),所以日期/时间26/09 at 00:00 GMT+02:00
已转换为25/09 at 19:00 in BRT
。
因此,代码实际上是将leftDate
(26/09)与inDate
(25/09)进行比较,这就是leftLimit
为1的原因。
根据您创建变量inDate
,leftDate
和rightDate
的方式,白天可能会有变化(因此代码可能仅在某些部分有效)这一天,例如)。在夏令时期间(当小时向前或向后移动1小时)也可能存在差异,这也可能导致当天的转变。
您的新代码(使用SimpleDateFormat
)对我来说也不起作用(它有同样的问题,因为SimpleDateFormat
也使用默认时区) - 如果出现同样的错误我使用Date
创建了java.util.Calendar
个对象,而不是使用DateTime.toDate()
。
所以,为了解决这个问题,我使用了org.joda.time.LocalDate
类(没有时间字段的日期),因为我只需要比较日期(日/月/年)并忽略时间(小时/分钟/秒)。我使用了接收时区的构造函数,所以我不依赖于系统的默认值,我可以肯定我总是在同一时区工作。
protected boolean checkDateInRange(Date inDate, Date inLeft, Date inRight) {
// convert inputs to LocalDate, using the specified timezone
LocalDate left = new LocalDate(inLeft, DateTimeZone.forOffsetHours(2));
LocalDate right = new LocalDate(inRight, DateTimeZone.forOffsetHours(2));
LocalDate date = new LocalDate(inDate, DateTimeZone.forOffsetHours(2));
System.out.println("inDate = " + date);
System.out.println("inLeft = " + left);
System.out.println("inRight = " + right);
int leftLimit = left.compareTo(date);
int rightLimit = date.compareTo(right);
System.out.println("leftLimit = " + leftLimit);
System.out.println("rightLimit = " + rightLimit);
if (leftLimit > 0 || rightLimit > 0) {
return false;
}
return true;
}
现在打电话:
checkDateInRange(in.toDate(), left.toDate(), right.toDate());
产生输出:
inDate = 2016-10-26
inLeft = 2016-10-26
inRight = 2016-10-26
leftLimit = 0
rightLimit = 0
true
备注:强>
当您使用joda-time时,您可以创建一个接收DateTime
对象(甚至更好,LocalDate
)的方法,而不是使用旧错误-prone java.util.Date
API。更改为LocalDate
更好,因为它明确表示该方法不需要时间字段:
protected boolean checkDateInRange(LocalDate inDate, LocalDate inLeft, LocalDate inRight) {
System.out.println("inDate = " + inDate);
System.out.println("inLeft = " + inLeft);
System.out.println("inRight = " + inRight);
int leftLimit = inLeft.compareTo(inDate);
int rightLimit = inDate.compareTo(inRight);
System.out.println("leftLimit = " + leftLimit);
System.out.println("rightLimit = " + rightLimit);
if (leftLimit > 0 || rightLimit > 0) {
return false;
}
return true;
}
// in, left and right are DateTime instances
checkDateInRange(in.toLocalDate(), left.toLocalDate(), right.toLocalDate());
我假设DateTimeZone.forOffsetHours(2)
是您所有输入的时区。如果情况并非如此,我建议相应地处理每个案例并在进行任何比较之前提取LocalDate
(使用上述构造函数LocalDate(dateObject, DateTimeZone)
。