Reputation: 7605
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). 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:
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
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:
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?
Thanks!
UPDATE: based on previous SO question here, I modified my previous code and now it works:
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;
}
Upvotes: 2
Views: 252
Reputation: 29693
Method DateTime::getMillis
returns milliseconds independent of zone. This value is a constant.
Once created DateTime
instance will return the same millis in any time zone.
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.
So this value is also zone independent.
But printing DateTime
with DateTimeFormatter
is zone dependent. 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
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
Upvotes: 3