2014-02-03 7 views
2

Я пытаюсь вычислить разницу между двумя днями в количестве дней. По какой-то причине сравнивая 01-03-2013 и 01-04-2013 дает результат 30, как это делает сравнение 01-03-2013 и 31-03-2013Java TimeUnit.MILLISECONDS.toDays() дает неправильный результат

Calendar cal = Calendar.getInstance(); 
cal.clear(); 

cal.set(2013, Calendar.MARCH, 1); 
Date start = cal.getTime(); 

cal.set(2013, Calendar.APRIL, 1); 
Date end = cal.getTime(); 

long days = TimeUnit.MILLISECONDS.toDays(end.getTime() - start.getTime()); 
System.out.println("!!! Amount of days : " + String.valueOf(days)); 

>> 30 

cal.set(2013, Calendar.MARCH, 1); 
start = cal.getTime(); 

cal.set(2013, Calendar.MARCH, 31); 
end = cal.getTime(); 

days = TimeUnit.MILLISECONDS.toDays(end.getTime() - start.getTime()); 
System.out.println("!!! Amount of days : " + String.valueOf(days)); 

>> 30 

Почему это?

+1

ли декретные либо начать или остановить во время первого из этих периодов? –

+2

Вы действительно заинтересованы в первопричине этой проблемы или просто хотите найти надежный способ рассчитать разницу в днях между двумя датами? –

+0

Я не уверен в вашем вопросе ... http: //ideone.com/n7ERlr .. Проверьте этот результат IDEone. –

ответ

5

Вы получите эти результаты, если дневной свет начнется в вашем часовом поясе 31 марта.

С 1 марта по 1 апреля у вас есть 30 24-часовых дней и один 23-часовой день из-за начала летнего сбережения. Если вы разделите общее количество миллисекунд на 24 x 60 x 60 x 1000, вы получите 30 плюс 23/24. Это получает округляется до 30.

+0

FYI ... Летнее время (США) 2013 г. началось в 2:00 утра по Воскресенье, 10 марта (так говорит Google). –

+0

Справа. Это объясняет ваш результат. ОП явно не в США. –

+0

Этот [список изменений DST] (http://www.timeanddate.com/time/dst/2013a.html) признает, что он не является исчерпывающим, но интересно отмечает, что 31 марта является особенно популярной датой переключения без каких-либо записей 1 апреля. –

0

я выполнил тот же код в моей системе это дает мне выход, как:

!!! Amount of days : 31 

пожалуйста, проверьте ваш код.

+0

Да, это зависит от часового пояса, и когда наступает летнее время. OP должен иметь 23-часовой день в своем часовом поясе, когда началось летнее сбережение. Преобразование в дни делит на 24 x 60 x 60, а 23 часа округляется до нуля. Вы, очевидно, находитесь в другом часовом поясе от ОП. –

+1

И я действительно должен превратить этот комментарий в свой ответ! –

0

Когда я запускаю эту версию кода здесь в США западного побережья времени зоны:

java.util.Calendar cal = java.util.Calendar.getInstance(); 
cal.clear(); 

cal.set(2013, java.util.Calendar.MARCH, 1); 
java.util.Date start = cal.getTime(); 

cal.set(2013, java.util.Calendar.APRIL, 1); 
java.util.Date end = cal.getTime(); 

long days = java.util.concurrent.TimeUnit.MILLISECONDS.toDays(end.getTime() - start.getTime()); 
System.out.println("!!! Amount of days : " + String.valueOf(days)); 

cal.set(2013, java.util.Calendar.MARCH, 1); 
start = cal.getTime(); 

cal.set(2013, java.util.Calendar.MARCH, 31); 
end = cal.getTime(); 

days = java.util.concurrent.TimeUnit.MILLISECONDS.toDays(end.getTime() - start.getTime()); 
System.out.println("!!! Amount of days : " + String.valueOf(days)); 

я получаю:

!!! Amount of days : 30 
!!! Amount of days : 29 

Для объяснения см комментария Дэвид Уоллес: this answer.

Переход на летнее время (Соединенные Штаты Америки) 2013 началась в 2:00 утра в воскресенье, 10 марта

1

Time Zone

correct answer by David Wallace объясняет, что Daylight Saving Time или другие аномалии влияет на результаты вашего кода. Опора на часовые пояса по умолчанию (или прямое игнорирование часовых поясов) приведет вас к таким неприятностям.

Сделать Span Inclusive-Exclusive

Кроме того, правильный способ определить промежуток времени, чтобы сделать начало включительно и заканчивая эксклюзивной. Так что, если вы хотите месяц марта, вам нужно перейти с первого момента первого дня до первого момента первого дня после Март (1 апреля).

Для подробного обсуждения этой идеи см. Мои другие ответы, такие как this one и this one.

Вот схема моего подняли из других ответов:

Timeline showing (>= start of day 1) and (< start of day 8)

Joda времени

Классы java.util.Date/Calendar в комплекте с Java, как известно, хлопотное. Избежать их. Используйте Joda-Time или Java 8, новый пакет java.time. * (Вдохновленный Joda-Time).

Библиотека Joda-Time 2.3 предоставляет классы, посвященные периодам времени: период, продолжительность и интервал. В этой библиотеке также есть некоторые полезные статические утилиты, такие как Days.daysBetween.

Объекты DateDime Joda-Time знают свои собственные time zone, в отличие от java.util.Date/Calendar, которые, похоже, имеют часовой пояс, но нет.

// Specify a timezone rather than rely on default. 
DateTimeZone timeZone = DateTimeZone.forID("Europe/Paris"); 

DateTime marchFirst = new DateTime(2013, DateTimeConstants.MARCH, 1, 0, 0, 0, timeZone); 
DateTime aprilFirst = new DateTime(2013, DateTimeConstants.APRIL, 1, 0, 0, 0, timeZone); 

int days = Days.daysBetween(marchFirst, aprilFirst).getDays(); 

самосвала утешать ...

System.out.println("marchFirst: " + marchFirst); 
System.out.println("aprilFirst: " + aprilFirst); // Note the change in time zone offset in the output. 
System.out.println("days: " + days); 

При запуске, обратите внимание:

  • Правильный ответ: 31
  • Разница во времени зоны смещения из-за Daylight Saving Time во Франции.
marchFirst: 2013-03-01T00:00:00.000+01:00 
aprilFirst: 2013-04-01T00:00:00.000+02:00 
days: 31 
Смежные вопросы