2014-10-06 47 views
2

datetime对象时,让我描述我的方案奇怪的行为。在这台服务器中,我需要获取时间服务器,将其转换为欧洲/马德里时区,然后检查获取的日期是否在日期间隔内。比较JODA

奇怪的是,我得到的回应表明,当前的服务器时间一旦转换为欧洲/马德里时区之前的较低日期间隔,这很奇怪。

这里是我正在做这个,获取服务器的时间并将其转换为欧洲/马德里时区:

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)); 

输出:

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

现在,我创建的日期时间为间隔,开始和结束,基于转换后的日期时间:

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)); 

正如您所看到的,我的间隔fr om 08:00:00至21:00:00

然后我检查服务器时间转换是否在日期范围内,这是非常详细的,因为我添加了很多检查和输出,因为奇怪的行为.. :

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; 
    } 
} 

只要打电话与转换的时间服务器的方法和开始和结束日期,并为以前的输出,其中服务器的时间转换为2014年10月6日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 

正如你可以看到服务器时间转换的时间戳是在开始日期时间之前.....这怎么可能?

我认为我在创建DateTime开始和结束时做错了什么,我尝试使用.withTimeZone(“Europe/Madrid”)创建它们,但后来我得到了最奇怪的行为......任何线索?

谢谢!

UPDATE:根据以往的SO质疑here,我修改了上面的代码,现在,它的工作原理:

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; 
} 

回答

3

方法DateTime::getMillis返回毫秒的独立区域。这个值是一个常数。
一旦创建DateTime实例将在任何时区返回相同的毫秒。

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

DateTime::isAfterDateTime::isBefore方法比较由DateTime::getMillis方法返回米利斯。
所以这个值也是区域独立的。

但是打印DateTimeDateTimeFormatter是区域相关的。它将在不同的时区打印不同的小时/分钟

所以,如果你想单独比较日期区域,那么你的结果是正确的。

例子:
- 前提条件:

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

你的代码在接下来的方式:

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 

正确方法:你应该在马德里区创建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 
+0

Hello Ilya,那么服务器时间的时间戳是在上面的间隔日期之前?根据你的建议,这是做到这一点的正确方法......那么为什么这种奇怪的行为呢?或者你的建议我不会将服务器时间转换为欧洲/马德里时区? – AlejandroVK 2014-10-07 13:48:32

+0

@AjjandroVK服务器时间是上部间隔日期*区域依赖性*,但较低*区域独立*。表达式'dt1.isBefore(dt2)'等于'd1.getMillis() Ilya 2014-10-07 18:34:47

+0

那么?老实说,我仍然不明白你的观点......你能提供一些实际的例子吗?我甚至尝试过使用JODA Interval类,它给出了相同的结果,错误 – AlejandroVK 2014-10-08 08:53:43