简体   繁体   English

比较DateTime对象和JODA时的奇怪行为

[英]Strange behaviour when comparing DateTime objects with JODA

Let me depict my scenario: 让我描述一下我的情况:

I have a running app in a server that is located in Dallas, Texas (I think it internally uses EDT timezone). 我在德克萨斯州达拉斯的服务器中有一个正在运行的应用程序(我认为它内部使用EDT时区)。 In this server I need to get the time server, convert it to Europe/Madrid timezone and then check if the obtained date is within a Date Interval. 在此服务器中,我需要获取时间服务器,将其转换为欧洲/马德里时区,然后检查获取的日期是否在日期间隔内。

The weird thing is that I'm getting a response that suggests that the current server time once it is converted to Europe/Madrid timezone in BEFORE the lower date interval, which is very weird. 奇怪的是,我得到的响应表明,当前服务器时间一旦在较低的日期间隔之前转换为欧洲/马德里时区,就会非常奇怪。

Here is how I'm doing this, getting the server time and convert it to Europe/Madrid timezone: 这是我这样做的方法,获取服务器时间并将其转换为欧洲/马德里时区:

DateTimeZone timeZoneMadrid = DateTimeZone.forID( "Europe/Madrid" );
DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm");
DateTime nowServer = new DateTime();
log.debug("Current server time is " + nowServer.toString(formatter));
DateTime nowServerSpanishTimeZone = nowServer.withZone(timeZoneMadrid);
log.debug("Current server time converted to Madrid Zone is " +  nowServerSpanishTimeZone.toString(formatter));

Output: 输出:

Current server is 2014-10-06 06:12
Current server time converted to Madrid Zone is 2014-10-06 12:12

Now, I create the DateTime for the interval, start and end, based on the converted DateTime: 现在,我根据转换后的DateTime为间隔(开始和结束)创建DateTime:

int year = serverTimeConverted.getYear();
int month = serverTimeConverted.getMonthOfYear();
int day = serverTimeConverted.getDayOfMonth();
this.setStartDate(new DateTime(year, month, day, 8, 0, 0, 0));
this.setEndDate(new DateTime(year, month, day, 21, 0, 0, 0));

As you can see, my interval goes from 08:00:00 to 21:00:00 如您所见,我的间隔从08:00:00到21:00:00

Then I check if the server time converted is within the date range, this is very verbose because I added a lot of checking and output because of the strange behaviour...: 然后我检查转换的服务器时间是否在日期范围内,这非常冗长,因为由于奇怪的行为,我添加了很多检查和输出...:

private boolean withinTimeRange(DateTime now, DateTime start, DateTime end){

    DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYYMMdd-HH:mm");
    String currentDate = now.toString(formatter);
    long nowTimeStamp = now.getMillis() / 1000;
    long startTimeStamp = start.getMillis() / 1000;
    long endTimeStamp = end.getMillis() / 1000;
    log.debug("Checking if date " + currentDate + " is in the interval dates " + start.toString(formatter) + " and " + end.toString(formatter));
    log.debug("Checking if UNIX timestamp " + nowTimeStamp + " is in the interval dates " + startTimeStamp + " and " + endTimeStamp);
    if (!now.isBefore(start)){
        log.debug("Current time " + currentDate + " is not before " + start.toString(formatter));
        if (!now.isAfter(end)){
            log.debug("Current time " + currentDate + " is not after " + end.toString(formatter));
            return true;
        }
        else{
            log.debug("Current time " + currentDate + " is after " + end.toString(formatter));
            return false;
        }
    }
    else{
        log.debug("Current time " + currentDate + " is before " + start.toString(formatter));
        return false;
    }
}

Just call the method with the time server converted and the start and end dates and, for the previous output, where server time converted is 2014-10-06 12:12, I get this output from previous method: 只需调用转换了服务器时间以及开始日期和结束日期的方法,对于先前的输出(转换的服务器时间为2014-10-06 12:12),我可以从先前的方法中获得以下输出:

Checking if date 20141006-12:12 is in the interval dates 20141006-08:00 and 20141006-21:00
Checking if UNIX timestamp 1412590332 is in the interval dates 1412596800 and 1412643600
Current time 20141006-12:12 is before 20141006-08:00
Current timeserver converted to Madrid TimeZone is not within time range, skipping iteration

As you can see the timestamp from the server time converted is before the start datetime.....how is this possible? 如您所见,从服务器时间转换的时间戳记在开始日期时间之前.....这怎么可能?

I think I'm doing something wrong when creating the DateTime start and end, I've tried creating them with .withTimeZone("Europe/Madrid"), but then I get even strangest behaviour...any clues? 我想我在创建DateTime开始和结束时做错了什么,我尝试使用.withTimeZone(“ Europe / Madrid”)创建它们,但是随后我什至得到了最奇怪的行为……任何线索?

Thanks! 谢谢!

UPDATE: based on previous SO question here , I modified my previous code and now it works: 更新:基于此处的先前SO问题,我修改了先前的代码,现在可以正常工作:

DateTime now = new DateTime();
LocalDate today = now.toLocalDate();
LocalDate tomorrow = today.plusDays(1);
DateTimeZone timeZoneMadrid = DateTimeZone.forID( "Europe/Madrid" );
DateTime start = today.toDateTimeAtStartOfDay(timeZoneMadrid);
DateTime end = tomorrow.toDateTimeAtStartOfDay(timeZoneMadrid);
start = start.plusHours(8);
end = end.minusHours(4);
Interval interval = new Interval(start, end);
DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm");
String currentDate = now.toString(formatter);
if (interval.contains(now)){
    return true;
}
else{
    return false;
}

Method DateTime::getMillis returns milliseconds independent of zone. DateTime::getMillis方法返回独立于区域的毫秒数。 This value is a constant. 该值是一个常数。
Once created DateTime instance will return the same millis in any time zone. 一旦创建, DateTime实例将在任何时区返回相同的毫秒。

final DateTime now = DateTime.now();
now.withZone(texas).getMillis() == now.withZone(madrid).getMillis(); // true

DateTime::isAfter and DateTime::isBefore methods compares millis returned by DateTime::getMillis method. DateTime::isAfterDateTime::isBefore方法比较DateTime::getMillis方法返回的DateTime::isBefore
So this value is also zone independent. 因此,该值也与区域无关。

But printing DateTime with DateTimeFormatter is zone dependent. 但是使用DateTimeFormatter打印DateTime取决于区域。 It will print different hours/minutes in in different time zones. 它将在不同的时区中打印不同的小时/分钟

So, if you want compare dates zone independently, then your result is correct. 因此,如果要独立比较日期区域,则结果是正确的。

Example: 例:
- Precondition: -前提:

  DateTimeZone usZone = DateTimeZone.forID("US/Eastern");
  DateTimeZone spZone = DateTimeZone.forID("Europe/Madrid");
  DateTimeZone.setDefault(usZone);

Your code works in next way: 您的代码以下面的方式工作:

DateTime serverDate = new DateTime(2014, 10, 6, 6, 12);     // US zone 
DateTime dateInMadrid = serverDate.withZone(spZone); // zone is Madrid, but .getMillis() will return the same value
DateTime startDate = new DateTime(2014, 10, 6, 8, 0); // US zone
// startDate = startDate.withZone(spZone) - this will not change the result
DateTime endDate = new DateTime(2014, 10, 6, 21, 0);  // US zone
// endDate = endDate.withZone(spZone) - this will also not change the result
System.out.println(dateInMadrid .isAfter(startDate) && dateInMadrid .isBefore(endDate)); 
// false - it is correct. because all dates were created in US zone  

Correct way: you should create start and end dates in Madrid zone 正确方法:您应该在马德里区域中创建startend日期

DateTime serverDate = new DateTime(2014, 10, 6, 6, 12);   
DateTime startDateMadrid = new DateTime(2014, 10, 6, 8, 0, spZone); // Madrid zone is used in constructor!
DateTime endDateMadrid = new DateTime(2014, 10, 6, 21, 0, spZone); // Madrid zone is used in constructor!  
System.out.println(serverDate.isAfter(startDateMadrid) && serverDate.isBefore(endDateMadrid));  
// true

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM