Java 查询两个日期之间的数据
我需要从在线服务器中托管的Mongodb数据中获取两个日期之间的数据。我尝试了这段代码,它在我的本地主机(本地数据和实时数据)中运行良好。但是当我在网上上传应用程序时,它在Live中无法正常工作 现场测试结果不准确。它在指定日期之前和之后获取一些记录。例如,我给出了2018年2月1日和2018年2月28日的日期,结果是2018年1月31日和2018年3月1日的记录 我认为问题在于日期存储在UTC时区(2018-02-15T23:33:30.000Z) 代码:Java 查询两个日期之间的数据,java,datetime,datetime-comparison,Java,Datetime,Datetime Comparison,我需要从在线服务器中托管的Mongodb数据中获取两个日期之间的数据。我尝试了这段代码,它在我的本地主机(本地数据和实时数据)中运行良好。但是当我在网上上传应用程序时,它在Live中无法正常工作 现场测试结果不准确。它在指定日期之前和之后获取一些记录。例如,我给出了2018年2月1日和2018年2月28日的日期,结果是2018年1月31日和2018年3月1日的记录 我认为问题在于日期存储在UTC时区(2018-02-15T23:33:30.000Z) 代码: java.util.Date,因此解
java.util.Date
,因此解析和格式化订单日期没有意义。格式化将其转换为字符串
,解析将其转换回日期
,这是毫无意义的,因为订单日期已经是日期
对象
您必须首先在格式化程序中设置时区(变量format
),然后解析from和to日期:它们将被设置为加尔各答时区的相应日期和时间-在这种情况下,它是有效的,因为您有字符串并希望将其转换为日期
然后使用额外的括号进行比较,以避免任何歧义(如注释中所指出的)。
将日期
设置为日历
是没有意义的,只是为了稍后再取回它,日历
实例在代码中没有任何用途
对getOrderDate
的调用不应该在for
循环中
完整代码如下所示:
SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
// from and to dates are from Kolkata's timezone, so the formatter must know that
format.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
// dates will be equivalent to this date and time in Kolkata, although
// the date itself doesn't store the timezone in it
Date fromDate = format.parse(from + " 00:00:00");
Date toDate = format.parse(to + " 23:59:59");
for(Order order : orders){
Date orderDate = order.getOrderDate();
// note the extra parenthesis, they make all the difference
if( (orderDate.after(fromDate) || orderDate.equals(fromDate)) &&
(orderDate.before(toDate) || orderDate.equals(toDate)) ) {
....
}
}
如果Java>=8,最好使用Java.time
API:
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd-MM-yyyy");
ZoneId zone = ZoneId.of("Asia/Kolkata");
ZonedDateTime fromDate = LocalDate
// parse "from" string
.parse(from, fmt)
// start of day at Kolkata timezone
.atStartOfDay(zone);
ZonedDateTime toDate = LocalDate
// parse "to" string
.parse(to, fmt)
// get start of next day
.plusDays(1).atStartOfDay(zone);
// convert the Date to ZonedDateTime
for (Order order : orders) {
ZonedDateTime orderDate = order.getOrderDate().toInstant().atZone(zone);
if ((orderDate.isAfter(fromDate) || orderDate.isEqual(fromDate)) && (orderDate.isBefore(toDate))) {
...
}
}
这是一个不同的代码,因为这个API引入了新的类型和概念,但它比以前的API有了很大的改进(Date
和Calendar
杂乱无章、有缺陷且过时)
花点时间研究一下这个API,它是完全值得的:如果问题的一部分是您的
。没有括号,它由三个部分条件组成,由|
(or)分隔,第一个是orderDate.after(fromDate)
,这就是为什么它接受3月份的日期。我想你的意思是在和&
之前和之后的每一半都用括号括起来。时区可能是该问题的另一个原因。您正在将order.getOrderDate()
放入日历中并再次取出,然后将其格式化为字符串并再次解析回日期。所有这些不都只是浪费吗?您使用的日期和时间类,date
、Calendar
和SimpleDateFormat
,早已过时,最后一个类尤其麻烦。更好地合作,更适合解决时区问题。我建议这样做。我尝试将订单日期从UTC转换为IST,因此我有了calendar对象。我认为orderDate
的声明应该放在这两个代码段的for
循环中?Java8版本很棒!我可能会让fromDate
和toDate
成为Instant
s,以避免为每个订单调用atZone
,但这只是一个小细节。绝对建议使用半开间隔(从包含到排除)。谢谢你的回答,向上投票。即使使用Java6或Java7,我仍然推荐后者。您只需要获取并将其添加到Java项目中。然后从Date
到Instant
的转换会有一点不同,仅此而已。@OleV.V。我相信ZonedDateTime
可以让代码更清楚地了解我们用来比较的日期-使用Instant
需要将思维转换为相应的本地时间,更难调试和维护,我想,你说得对,我更新了,谢谢!你说得有道理。我可能一直在考虑优化,但可能没有理由这样做。@xunts-非常感谢它与Java 8时间代码一起工作
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("dd-MM-yyyy");
ZoneId zone = ZoneId.of("Asia/Kolkata");
ZonedDateTime fromDate = LocalDate
// parse "from" string
.parse(from, fmt)
// start of day at Kolkata timezone
.atStartOfDay(zone);
ZonedDateTime toDate = LocalDate
// parse "to" string
.parse(to, fmt)
// get start of next day
.plusDays(1).atStartOfDay(zone);
// convert the Date to ZonedDateTime
for (Order order : orders) {
ZonedDateTime orderDate = order.getOrderDate().toInstant().atZone(zone);
if ((orderDate.isAfter(fromDate) || orderDate.isEqual(fromDate)) && (orderDate.isBefore(toDate))) {
...
}
}