Мне нужно найти количество дней между двумя датами : одна из отчета, а другая - текущая дата. Мой фрагмент:
int age=calculateDifference(agingDate, today);
Вот calculateDifference
это частный метод, agingDate
и today
являются Date
объектами, просто для уточнения. Я читал две статьи с форума Java, Thread 1 / Thread 2 .
Он отлично работает в автономной программе, хотя, когда я включаю это в свою логику для чтения из отчета, я получаю необычную разницу в значениях.
Почему это происходит и как это исправить?
РЕДАКТИРОВАТЬ :
Я получаю большее количество дней по сравнению с фактическим количеством дней.
public static int calculateDifference(Date a, Date b)
{
int tempDifference = 0;
int difference = 0;
Calendar earlier = Calendar.getInstance();
Calendar later = Calendar.getInstance();
if (a.compareTo(b) < 0)
{
earlier.setTime(a);
later.setTime(b);
}
else
{
earlier.setTime(b);
later.setTime(a);
}
while (earlier.get(Calendar.YEAR) != later.get(Calendar.YEAR))
{
tempDifference = 365 * (later.get(Calendar.YEAR) - earlier.get(Calendar.YEAR));
difference += tempDifference;
earlier.add(Calendar.DAY_OF_YEAR, tempDifference);
}
if (earlier.get(Calendar.DAY_OF_YEAR) != later.get(Calendar.DAY_OF_YEAR))
{
tempDifference = later.get(Calendar.DAY_OF_YEAR) - earlier.get(Calendar.DAY_OF_YEAR);
difference += tempDifference;
earlier.add(Calendar.DAY_OF_YEAR, tempDifference);
}
return difference;
}
Заметка :
К сожалению, ни один из ответов не помог мне решить проблему. Я решил эту проблему с помощью библиотеки Joda-time .
java.util.Date
,java.util.Calendar
иjava.text.SimpleDateFormat
теперь наследие , вытесняется java.time классов. См. Учебник Oracle . Точно так же проект Joda-Time сейчас находится в режиме обслуживания , и команда советует перейти на классы java.time.Ответы:
Я бы посоветовал вам использовать отличную библиотеку Joda Time вместо испорченных java.util.Date и друзей. Вы могли бы просто написать
import java.util.Date; import org.joda.time.DateTime; import org.joda.time.Days; Date past = new Date(110, 5, 20); // June 20th, 2010 Date today = new Date(110, 6, 24); // July 24th int days = Days.daysBetween(new DateTime(past), new DateTime(today)).getDays(); // => 34
источник
Возможно, я уже слишком поздно, чтобы присоединиться к игре, но какого черта, да? :)
Как вы думаете, это проблема с потоками? Например, как вы используете результат этого метода? ИЛИ ЖЕ
Можем ли мы изменить ваш код, чтобы сделать что-то более простое, например:
Calendar calendar1 = Calendar.getInstance(); Calendar calendar2 = Calendar.getInstance(); calendar1.set(<your earlier date>); calendar2.set(<your current date>); long milliseconds1 = calendar1.getTimeInMillis(); long milliseconds2 = calendar2.getTimeInMillis(); long diff = milliseconds2 - milliseconds1; long diffSeconds = diff / 1000; long diffMinutes = diff / (60 * 1000); long diffHours = diff / (60 * 60 * 1000); long diffDays = diff / (24 * 60 * 60 * 1000); System.out.println("\nThe Date Different Example"); System.out.println("Time in milliseconds: " + diff + " milliseconds."); System.out.println("Time in seconds: " + diffSeconds + " seconds."); System.out.println("Time in minutes: " + diffMinutes + " minutes."); System.out.println("Time in hours: " + diffHours + " hours."); System.out.println("Time in days: " + diffDays + " days."); }
источник
Параметр diff / (24 * etc) не учитывает часовой пояс, поэтому, если в вашем часовом поясе по умолчанию указано летнее время, расчет может не выполняться.
Эта ссылка имеет небольшую симпатичную реализацию.
Вот источник указанной выше ссылки на случай, если ссылка не работает:
/** Using Calendar - THE CORRECT WAY**/ public static long daysBetween(Calendar startDate, Calendar endDate) { //assert: startDate must be before endDate Calendar date = (Calendar) startDate.clone(); long daysBetween = 0; while (date.before(endDate)) { date.add(Calendar.DAY_OF_MONTH, 1); daysBetween++; } return daysBetween; }
и
/** Using Calendar - THE CORRECT (& Faster) WAY**/ public static long daysBetween(final Calendar startDate, final Calendar endDate) { //assert: startDate must be before endDate int MILLIS_IN_DAY = 1000 * 60 * 60 * 24; long endInstant = endDate.getTimeInMillis(); int presumedDays = (int) ((endInstant - startDate.getTimeInMillis()) / MILLIS_IN_DAY); Calendar cursor = (Calendar) startDate.clone(); cursor.add(Calendar.DAY_OF_YEAR, presumedDays); long instant = cursor.getTimeInMillis(); if (instant == endInstant) return presumedDays; final int step = instant < endInstant ? 1 : -1; do { cursor.add(Calendar.DAY_OF_MONTH, step); presumedDays += step; } while (cursor.getTimeInMillis() != endInstant); return presumedDays; }
источник
while
должен быть финальный .while (cursor.getTimeInMillis() <= endInstant);
В противном случае вы получите бесконечный цикл, если осталось меньше суток.java.time
В Java 8 и новее используйте фреймворк java.time ( Учебник ).
Duration
Duration
Класс представляет собой промежуток времени , как несколько секунд плюс дробной секунду. Он может считать дни, часы, минуты и секунды.ZonedDateTime now = ZonedDateTime.now(); ZonedDateTime oldDate = now.minusDays(1).minusMinutes(10); Duration duration = Duration.between(oldDate, now); System.out.println(duration.toDays());
ChronoUnit
Если все, что вам нужно, это количество дней, вы также можете использовать перечисление . Обратите внимание, что методы вычисления возвращают, а не .
ChronoUnit
long
int
long days = ChronoUnit.DAYS.between( then, now );
источник
import java.util.Calendar; import java.util.Date; public class Main { public static long calculateDays(String startDate, String endDate) { Date sDate = new Date(startDate); Date eDate = new Date(endDate); Calendar cal3 = Calendar.getInstance(); cal3.setTime(sDate); Calendar cal4 = Calendar.getInstance(); cal4.setTime(eDate); return daysBetween(cal3, cal4); } public static void main(String[] args) { System.out.println(calculateDays("2012/03/31", "2012/06/17")); } /** Using Calendar - THE CORRECT WAY**/ public static long daysBetween(Calendar startDate, Calendar endDate) { Calendar date = (Calendar) startDate.clone(); long daysBetween = 0; while (date.before(endDate)) { date.add(Calendar.DAY_OF_MONTH, 1); daysBetween++; } return daysBetween; } }
источник
Это зависит от того, что вы определяете как разницу. Сравнивать две даты в полночь можно.
long day1 = ...; // in milliseconds. long day2 = ...; // in milliseconds. long days = (day2 - day1) / 86400000;
источник
Решение с использованием разницы между миллисекундами и правильным округлением дат летнего времени:
public static long daysDiff(Date from, Date to) { return daysDiff(from.getTime(), to.getTime()); } public static long daysDiff(long from, long to) { return Math.round( (to - from) / 86400000D ); // 1000 * 60 * 60 * 24 }
Одно замечание: конечно, даты должны быть в каком-то часовом поясе.
Важный код:
Math.round( (to - from) / 86400000D )
Если вы не хотите округлять, вы можете использовать даты в формате UTC,
источник
Иллюстрация проблемы: (Мой код вычисляет дельту в неделях, но та же проблема касается дельты в днях)
Вот очень разумно выглядящая реализация:
public static final long MILLIS_PER_WEEK = 7L * 24L * 60L * 60L * 1000L; static public int getDeltaInWeeks(Date latterDate, Date earlierDate) { long deltaInMillis = latterDate.getTime() - earlierDate.getTime(); int deltaInWeeks = (int)(deltaInMillis / MILLIS_PER_WEEK); return deltaInWeeks; }
Но этот тест не удастся:
public void testGetDeltaInWeeks() { delta = AggregatedData.getDeltaInWeeks(dateMar09, dateFeb23); assertEquals("weeks between Feb23 and Mar09", 2, delta); }
Причина:
но любой, кто смотрит в календарь, согласится, что ответ - 2.
источник
Я использую эту функцию:
DATEDIFF("31/01/2016", "01/03/2016") // me return 30 days
моя функция:
import java.util.Date; public long DATEDIFF(String date1, String date2) { long MILLISECS_PER_DAY = 24 * 60 * 60 * 1000; long days = 0l; SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy"); // "dd/MM/yyyy HH:mm:ss"); Date dateIni = null; Date dateFin = null; try { dateIni = (Date) format.parse(date1); dateFin = (Date) format.parse(date2); days = (dateFin.getTime() - dateIni.getTime())/MILLISECS_PER_DAY; } catch (Exception e) { e.printStackTrace(); } return days; }
источник
Посмотрите на методы getFragmentInDays в этом классе apache commons-lang
DateUtils
.источник
Основываясь на ответе @ Mad_Troll, я разработал этот метод.
Я проверил около 30 тестовых примеров против него, это единственный метод, который правильно обрабатывает субдневные фрагменты.
Пример: если вы пройдете сейчас и сейчас + 1 миллисекунду, это будет тот же день. Ведение
1-1-13 23:59:59.098
в1-1-13 23:59:59.099
возвраты 0 дней, правильно; выделение других методов, размещенных здесь, не будет делать это правильно.Стоит отметить, что его не волнует, каким образом вы их вставляете. Если ваша дата окончания раньше даты начала, она будет отсчитываться в обратном порядке.
/** * This is not quick but if only doing a few days backwards/forwards then it is very accurate. * * @param startDate from * @param endDate to * @return day count between the two dates, this can be negative if startDate is after endDate */ public static long daysBetween(@NotNull final Calendar startDate, @NotNull final Calendar endDate) { //Forwards or backwards? final boolean forward = startDate.before(endDate); // Which direction are we going final int multiplier = forward ? 1 : -1; // The date we are going to move. final Calendar date = (Calendar) startDate.clone(); // Result long daysBetween = 0; // Start at millis (then bump up until we go back a day) int fieldAccuracy = 4; int field; int dayBefore, dayAfter; while (forward && date.before(endDate) || !forward && endDate.before(date)) { // We start moving slowly if no change then we decrease accuracy. switch (fieldAccuracy) { case 4: field = Calendar.MILLISECOND; break; case 3: field = Calendar.SECOND; break; case 2: field = Calendar.MINUTE; break; case 1: field = Calendar.HOUR_OF_DAY; break; default: case 0: field = Calendar.DAY_OF_MONTH; break; } // Get the day before we move the time, Change, then get the day after. dayBefore = date.get(Calendar.DAY_OF_MONTH); date.add(field, multiplier); dayAfter = date.get(Calendar.DAY_OF_MONTH); // This shifts lining up the dates, one field at a time. if (dayBefore == dayAfter && date.get(field) == endDate.get(field)) fieldAccuracy--; // If day has changed after moving at any accuracy level we bump the day counter. if (dayBefore != dayAfter) { daysBetween += multiplier; } } return daysBetween; }
Вы можете удалить
@NotNull
аннотации, они используются Intellij для анализа кода на лету.источник
Вы говорите, что он «отлично работает в отдельной программе», но вы получаете «необычные значения разницы», когда «включаете это в мою логику для чтения из отчета». Это говорит о том, что в вашем отчете есть некоторые значения, для которых он не работает правильно, а ваша автономная программа не имеет этих значений. Вместо отдельной программы я предлагаю тестовый пример. Напишите тестовый пример как отдельную программу, создав подкласс от класса TestCase JUnit. Теперь вы можете запустить очень конкретный пример, зная, какое значение вы ожидаете (и не давайте его сегодня в качестве тестового значения, потому что сегодня со временем меняются). Если вы введете значения, которые использовали в автономной программе, ваши тесты, вероятно, пройдут. Это здорово - вы хотите, чтобы эти кейсы продолжали работать. Теперь добавьте значение из вашего отчета, которое не т работать правильно. Ваш новый тест, вероятно, не удастся. Выясните, почему он не работает, исправьте это и получите зеленый цвет (все тесты пройдены). Запустите свой отчет. Посмотрите, что все еще сломано; написать тест; пусть это пройдет. Довольно скоро вы обнаружите, что ваш отчет работает.
источник
Сотня строк кода для этой базовой функции ???
Просто простой способ:
protected static int calculateDayDifference(Date dateAfter, Date dateBefore){ return (int)(dateAfter.getTime()-dateBefore.getTime())/(1000 * 60 * 60 * 24); // MILLIS_IN_DAY = 1000 * 60 * 60 * 24; }
источник
public static int getDifferenceIndays(long timestamp1, long timestamp2) { final int SECONDS = 60; final int MINUTES = 60; final int HOURS = 24; final int MILLIES = 1000; long temp; if (timestamp1 < timestamp2) { temp = timestamp1; timestamp1 = timestamp2; timestamp2 = temp; } Calendar startDate = Calendar.getInstance(TimeZone.getDefault()); Calendar endDate = Calendar.getInstance(TimeZone.getDefault()); endDate.setTimeInMillis(timestamp1); startDate.setTimeInMillis(timestamp2); if ((timestamp1 - timestamp2) < 1 * HOURS * MINUTES * SECONDS * MILLIES) { int day1 = endDate.get(Calendar.DAY_OF_MONTH); int day2 = startDate.get(Calendar.DAY_OF_MONTH); if (day1 == day2) { return 0; } else { return 1; } } int diffDays = 0; startDate.add(Calendar.DAY_OF_MONTH, diffDays); while (startDate.before(endDate)) { startDate.add(Calendar.DAY_OF_MONTH, 1); diffDays++; } return diffDays; }
источник
ThreeTen-Extra
Ответ Виталия Федоренко правильно, описывая , как выполнить этот расчет в современном стиле с java.time классами (
Duration
&ChronoUnit
) , встроенные в Java 8 , а затем (и бэк-портированы на Java 6 и 7 и для Android ).Days
Если вы обычно используете в своем коде несколько дней, вы можете заменить простые целые числа использованием класса. Этот
Days
класс можно найти в проекте ThreeTen-Extra , расширении java.time и испытательном полигоне для возможных будущих дополнений к java.time.Days
Класс предоставляет способ типобезопасного представления несколько дней в вашем приложении. Класс включает удобные константы дляZERO
иONE
.Учитывая старые устаревшие
java.util.Date
объекты в Вопросе, сначала преобразуйте их в современныеjava.time.Instant
объекты. В старые классы времени и даты добавлены новые методы для облегчения преобразования в java.time, напримерjava.util.Date::toInstant
.Instant start = utilDateStart.toInstant(); // Inclusive. Instant stop = utilDateStop.toInstant(); // Exclusive.
Передайте оба
Instant
объекта в фабричный метод дляorg.threeten.extra.Days
.В текущей реализации (2016-06) это вызов оболочки
java.time.temporal.ChronoUnit.DAYS.between
,ChronoUnit
подробности читайте в документации по классу. Чтобы было ясно: все прописные буквыDAYS
находятся в перечислении,ChronoUnit
а начальная крышкаDays
- это класс от ThreeTen-Extra.Вы можете передавать эти
Days
объекты в свой собственный код. Вы можете сериализовать строку в стандартном формате ISO 8601 , вызвавtoString
. Этот форматPnD
используетP
для обозначения начала иD
означает «дни» с количеством дней между ними. И классы java.time, и ThreeTen-Extra по умолчанию используют эти стандартные форматы при создании и анализе строк, представляющих значения даты и времени.Days days = Days.parse( "P3D" );
источник
Этот код вычисляет дни между двумя строками даты:
static final long MILLI_SECONDS_IN_A_DAY = 1000 * 60 * 60 * 24; static final String DATE_FORMAT = "dd-MM-yyyy"; public long daysBetween(String fromDateStr, String toDateStr) throws ParseException { SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT); Date fromDate; Date toDate; fromDate = format.parse(fromDateStr); toDate = format.parse(toDateStr); return (toDate.getTime() - fromDate.getTime()) / MILLI_SECONDS_IN_A_DAY; }
источник
Если вы ищете решение, которое возвращает правильное число или дни между, например,
11/30/2014 23:59
и12/01/2014 00:01
здесь решением с использованием Joda Time.private int getDayDifference(long past, long current) { DateTime currentDate = new DateTime(current); DateTime pastDate = new DateTime(past); return currentDate.getDayOfYear() - pastDate.getDayOfYear(); }
Эта реализация вернется
1
в виде разницы в днях. Большинство размещенных здесь решений рассчитывают разницу в миллисекундах между двумя датами. Это означает, что0
он будет возвращен, потому что разница между этими двумя датами составляет всего 2 минуты.источник
Вам следует использовать библиотеку Joda Time, потому что Java Util Date иногда возвращает неправильные значения.
Joda против Java Util Date
Например, дни между вчерашним днем (дд-мм-гггг, 12-07-2016) и первым днем года в 1957 году (дд-мм-гггг, 01-01-1957):
public class Main { public static void main(String[] args) { SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy"); Date date = null; try { date = format.parse("12-07-2016"); } catch (ParseException e) { e.printStackTrace(); } //Try with Joda - prints 21742 System.out.println("This is correct: " + getDaysBetweenDatesWithJodaFromYear1957(date)); //Try with Java util - prints 21741 System.out.println("This is not correct: " + getDaysBetweenDatesWithJavaUtilFromYear1957(date)); } private static int getDaysBetweenDatesWithJodaFromYear1957(Date date) { DateTime jodaDateTime = new DateTime(date); DateTimeFormatter formatter = DateTimeFormat.forPattern("dd-MM-yyyy"); DateTime y1957 = formatter.parseDateTime("01-01-1957"); return Days.daysBetween(y1957 , jodaDateTime).getDays(); } private static long getDaysBetweenDatesWithJavaUtilFromYear1957(Date date) { SimpleDateFormat format = new SimpleDateFormat("dd-MM-yyyy"); Date y1957 = null; try { y1957 = format.parse("01-01-1957"); } catch (ParseException e) { e.printStackTrace(); } return TimeUnit.DAYS.convert(date.getTime() - y1957.getTime(), TimeUnit.MILLISECONDS); }
Поэтому я действительно советую вам использовать библиотеку Joda Time.
источник
Я так и сделал. это просто :)
Date d1 = jDateChooserFrom.getDate(); Date d2 = jDateChooserTo.getDate(); Calendar day1 = Calendar.getInstance(); day1.setTime(d1); Calendar day2 = Calendar.getInstance(); day2.setTime(d2); int from = day1.get(Calendar.DAY_OF_YEAR); int to = day2.get(Calendar.DAY_OF_YEAR); int difference = to-from;
источник