Как добавить рабочие дни в текущую дату на Java?

Как добавить рабочие дни в текущую дату на Java?

public Calendar addBusinessDate(Calendar cal, int days) { // // code goes over here // } 

Заметка:

Он также должен учитывать выходные.

Вы можете захотеть использовать ObjectLab Kit, чтобы сделать тяжелую работу для вас.

Предполагая, что требование состоит в том, чтобы просто вернуть следующий рабочий день, когда вычисленная дата приходится на нерабочий день:

 package bizdays.example; import java.util.HashSet; import net.objectlab.kit.datecalc.common.DateCalculator; import net.objectlab.kit.datecalc.common.DefaultHolidayCalendar; import net.objectlab.kit.datecalc.common.HolidayHandlerType; import net.objectlab.kit.datecalc.joda.LocalDateKitCalculatorsFactory; import static org.junit.Assert.assertThat; import org.junit.Before; import org.junit.Test; import static org.hamcrest.Matchers.equalTo; import org.joda.time.LocalDate; public class BizDayTest { private DateCalculator dateCalculator; private final LocalDate startDate = new LocalDate(2009, 12, 23); @Before public void setUp() { HashSet holidays = new HashSet(); holidays.add(new LocalDate(2009, 12, 25)); // Friday DefaultHolidayCalendar holidayCalendar = new DefaultHolidayCalendar(holidays); LocalDateKitCalculatorsFactory.getDefaultInstance() .registerHolidays("example", holidayCalendar); dateCalculator = LocalDateKitCalculatorsFactory.getDefaultInstance() .getDateCalculator("example", HolidayHandlerType.FORWARD); dateCalculator.setStartDate(startDate); } @Test public void should_not_change_calendar_start_date_even_after_moving() { assertThat( dateCalculator.moveByBusinessDays(6).getStartDate(), equalTo(startDate)); } @Test public void moveByBusinessDays_will_return_24_dec_2009_as_next_business_day() { assertThat( dateCalculator.moveByBusinessDays(1).getCurrentBusinessDate(), equalTo(new LocalDate(2009, 12, 24))); } @Test public void moveByBusinessDays_will_return_28_dec_2009_as_two_business_days_later() { assertThat( dateCalculator.moveByBusinessDays(2).getCurrentBusinessDate(), equalTo(new LocalDate(2009, 12, 28))); } @Test public void moveByDays_will_also_return_28_dec_2009_as_two_business_days_later() { assertThat( dateCalculator.moveByDays(2).getCurrentBusinessDate(), equalTo(new LocalDate(2009, 12, 28))); } @Test public void moveByBusinessDays_will_exclude_25_26_and_27_dec_when_computing_business_days() { assertThat( dateCalculator.moveByBusinessDays(5).getCurrentBusinessDate(), equalTo(new LocalDate(2009, 12, 31))); } @Test public void moveByDays_will_include_25_26_and_27_dec_when_computing_business_days() { assertThat( dateCalculator.moveByDays(5).getCurrentBusinessDate(), equalTo(new LocalDate(2009, 12, 28))); } } 

В библиотеке по умолчанию работает неделя с понедельника по пятницу, но вы можете изменить настройки по умолчанию, поставив пользовательскую настройку WorkWeek в DateQalculator setWorkingWeek () .

Как показано в последних двух примерах, moveByDays () включает выходные дни при перемещении дней, тогда как moveByBusinessDays () исключает выходные дни.

Библиотека также позволяет вам использовать java.util.Calendar вместо LocalDate от Joda Time . В этом примере используется библиотека Joda Time, потому что это предпочтительная библиотека, используемая при обработке дат в Java.

Использование:

 public Calendar addBusinessDate(Calendar cal, int numBusinessDays) { int numNonBusinessDays = 0; for(int i = 0; i < numBusinessDays; i++) { cal.add(Calendar.DATE, 1); /* It's a Canadian/American custom to get the Monday (sometimes Friday) off when a holiday falls on a weekend. */ for(int j = 0; j < holidays; j++) { //holidays is list of dates if(cal.getTime() == (Date)holidays.get(j)) { numNonBusinessDays++; } } if(cal.get(Calendar.DAY_OF_WEEK) == 1 || cal.get(Calendar.DAY_OF_WEEK) == 7) { numNonBusinessDays++; } } if(numNonBusinessDays > 0) { cal.add(Calendar.DATE, numNonBusinessDays); } return cal; } 

Вам нужно будет заполнить список дат для обработки праздников. Есть такие общие, как Новый год, но День благодарения отличается от Канады и США, например. Также помните, что праздники могут выпасть на выходные, поэтому выходные станут 3-дневными выходными.

Справка:

  • Календарь
  • Значения константы в календаре

PS: Нет необходимости возвращать экземпляр календаря, если вы обновляете значение, как в примере. Но это действительно, если вы хотите создать отдельный экземпляр календаря, используйте:

 public Calendar addBusinessDate(Calendar cal, int numBusinessDays) { Calendar cal2 = Calendar.getInstance(); cal2.setTime(cal.getTime()); int numNonBusinessDays = 0; for(int i = 0; i < numBusinessDays; i++) { cal2.add(Calendar.DATE, 1); /* It's a Canadian/American custom to get the Monday (sometimes Friday) off when a holiday falls on a weekend. */ for(int j = 0; j < holidays; j++) { //holidays is list of dates if(cal2.getTime() == (Date)holidays.get(j)) { numNonBusinessDays++; } } if(cal2.get(Calendar.DAY_OF_WEEK) == 1 || cal2.get(Calendar.DAY_OF_WEEK) == 7) { numNonBusinessDays++; } } if(numNonBusinessDays > 0) { cal2.add(Calendar.DATE, numNonBusinessDays); } return cal2; } 

Вот модифицированная версия, чтобы найти расчет даты.

 public Calendar algorithm2(int businessDays){ Calendar cal2 = Calendar.getInstance(); Calendar cal = Calendar.getInstance(); int totalDays= businessDays/5*7; int remainder = businessDays % 5; cal2.add(cal2.DATE, totalDays); switch(cal.get(Calendar.DAY_OF_WEEK)){ case 1: break; case 2: break; case 3: if(remainder >3) cal2.add(cal2.DATE,2); break; case 4: if(remainder >2) cal2.add(cal2.DATE,2); break; case 5: if(remainder >1) cal2.add(cal2.DATE,2); break; case 6: if(remainder >1) cal2.add(cal2.DATE,2); break; case 7: if(remainder >1) cal2.add(cal2.DATE,1); break; } cal2.add(cal2.DATE, remainder); return cal2; } 
 public static Date addBusinessDays(Date date, int days) { DateTime result = new DateTime(date); result = isWeekEnd(result) ? getPreviousBusinessDate(result) : result; for (int i = 0; i < days; i++) { if (isWeekEnd(result)) { i--; } result = result.plusDays(1); } return result.toDate(); } private static boolean isWeekEnd(DateTime dateTime) { int dayOfWeek = dateTime.getDayOfWeek(); return dayOfWeek == DateTimeConstants.SATURDAY || dayOfWeek == DateTimeConstants.SUNDAY; } private static DateTime getPreviousBusinessDate(DateTime result) { while (isWeekEnd(result)) { result = result.minusDays(1); } return result; } 

// поддерживает отрицательные числа.

 private Calendar addBusinessDay(final Calendar cal, final Integer numBusinessDays) { if (cal == null || numBusinessDays == null || numBusinessDays.intValue() == 0) { return cal; } final int numDays = Math.abs(numBusinessDays.intValue()); final int dateAddition = numBusinessDays.intValue() < 0 ? -1 : 1;//if numBusinessDays is negative int businessDayCount = 0; while (businessDayCount < numDays) { cal.add(Calendar.DATE, dateAddition); //check weekend if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) { continue;//adds another day } //check holiday if (isHoliday(cal))//implement isHoliday yourself { continue;//adds another day } businessDayCount++; } return cal; } 

Будет ли это работать? Конечно, это не обработка праздников.

public static Дата addBusinessDays (Дата baseDate, int numberOfDays) {

  if(baseDate == null){ baseDate = new Date(); } Calendar baseDateCal = Calendar.getInstance(); baseDateCal.setTime(baseDate); for(int i = 0; i < numberOfDays; i++){ baseDateCal.add(Calendar.DATE,1); if(baseDateCal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY){ baseDateCal.add(Calendar.DATE,2); } } return baseDateCal.getTime(); } 

ТЛ; др

Идти вперед.

 myLocalDate.with( org.threeten.extra.Temporals.nextWorkingDay() ) 

Возrotation назад.

 myLocalDate.with( org.threeten.extra.Temporals.previousWorkingDay() ) 

Использование java.time

В Вопросе и других ответах используются неприятные старые classы времени и времени, теперь устаревшие, вытесненные classами java.time.

Также см. Мой ответ на аналогичный вопрос.

TemporalAdjuster

В java.time интерфейс TemporalAdjuster предоставляет classы для управления значениями даты и времени. Используя неизменяемые объекты , создается новый экземпляр со значениями, основанными на оригинале.

nextWorkingDay

Проект ThreeTen-Extra расширяет java.time с дополнительной функциональностью. nextWorkingDay входит регулятор nextWorkingDay который пропускает дни субботы и воскресенья. Таким образом, мы можем циклически, увеличивая дату один день за раз, и пропускаем любые выходные дни.

Класс LocalDate представляет значение даты только без времени и без часового пояса.

 LocalDate start = LocalDate.now( ZoneId.of( "America/Montreal" ) ) ; int businessDaysToAdd = 13 ; // … ensure that: ( businessDaysToAdd >= 0 ) int daysLeft = businessDaysToAdd ; LocalDate localDate = start ; while ( daysLeft > 0 ) { localDate = localDate.with( Temporals.nextWorkingDay() ); daysLeft = ( daysLeft - 1 ) ; // Decrement as we go. } return localDate ; 

каникулы

Праздники – совсем другое дело. Очевидно, нет простого решения. Вы должны либо предоставить список своих почетных праздников, либо получить список, с которым вы согласны.

Когда у вас есть такой список, я предлагаю написать собственную реализацию TemporalAdjuster похожую на nextWorkingDay .


О java.time

Рамка java.time встроена в Java 8 и более поздние версии . Эти classы вытесняют неприятные старые устаревшие classы времени, такие как java.util.Date , Calendar и SimpleDateFormat .

Проект Joda-Time , теперь в режиме обслуживания , советует перейти на classы java.time .

Чтобы узнать больше, ознакомьтесь с учебным пособием Oracle . И поиск Stack Overflow для многих примеров и объяснений. Спецификация – JSR 310 .

Где можно получить classы java.time?

  • Java SE 8 и SE 9 и более поздние версии
    • Встроенный.
    • Часть стандартного Java API с интегрированной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и SE 7
    • Большая часть функциональных возможностей java.time включена обратно в Java 6 и 7 в ThreeTen-Backport .
  • Android
    • Проект ThreeTenABP адаптирует ThreeTen-Backport (упомянутый выше) специально для Android.
    • См. Раздел Как использовать ThreeTenABP ….

Проект ThreeTen-Extra расширяет java.time с дополнительными classами. Этот проект является доказательством возможных будущих дополнений к java.time. Здесь вы можете найти полезные classы, такие как Interval , YearWeek , YearQuarter и другие .

Этот алгоритм вычисляет следующую дату работы для данной даты (рабочие дни с понедельника по пятницу в моей стране) , вы можете адаптировать ее для повторения количества дней, которое нужно добавить.

 public Calendar nextBusinessDate(Calendar cal) { List holidays = ******** // Here get list of holidays from DB or some other service... GregorianCalendar calCp = new GregorianCalendar(); calCp.setTime(cal.getTime()); calCp.add(Calendar.DAY_OF_MONTH, 1); boolean isSaturday = (calCp.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY); boolean isSunday = (calCp.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY); boolean isHoliday = holidays.contains(calCp); while (isSaturday || isSunday || isHoliday) { if (isSaturday) { calCp.add(Calendar.DAY_OF_MONTH, +2); // is saturday, make it monday } else { if (isSunday) { calCp.add(Calendar.DAY_OF_MONTH, +1); // is sunday, make it monday } else { if (isHoliday) { calCp.add(Calendar.DAY_OF_MONTH, +1); // is holiday, make it next day } } } calCp = new GregorianCalendar(); calCp.setTime(cal.getTime()); isSaturday = (calCp.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY); isSunday = (calCp.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY); isHoliday = holidays.contains(calCp); } // end while return calCp; } 

O (1), которая работает и поддерживает различные шаблоны выходных дней и отрицательные дни:

 import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Map; public class DateUtil { //Weekend patterns public static final int WEEKEND_SAT_SUN = 0; public static final int WEEKEND_FRI_SAT = 1; public static final int WEEKEND_THU_FRI = 2; public static final int WEEKEND_FRI_SUN = 3; public static final int WEEKEND_FRI = 4; public static final int WEEKEND_SAT = 5; public static final int WEEKEND_SUN = 6; //Weekend pattern by country //@see https://en.wikipedia.org/wiki/Workweek_and_weekend public static Map weekendPatternByCountry = new HashMap<>(); static { weekendPatternByCountry.put("CO",WEEKEND_SUN); //Colombia weekendPatternByCountry.put("GQ",WEEKEND_SUN); //Equatorial Guinea weekendPatternByCountry.put("IN",WEEKEND_SUN); //India weekendPatternByCountry.put("MX",WEEKEND_SUN); //Mexico weekendPatternByCountry.put("KP",WEEKEND_SUN); //North Korea weekendPatternByCountry.put("UG",WEEKEND_SUN); //Uganda weekendPatternByCountry.put("BN",WEEKEND_FRI_SUN); //Brunei Darussalam weekendPatternByCountry.put("DJ",WEEKEND_FRI); //Djibouti weekendPatternByCountry.put("IR",WEEKEND_FRI); //Iran weekendPatternByCountry.put("AF",WEEKEND_THU_FRI); //Afghanistan weekendPatternByCountry.put("NP",WEEKEND_SAT); //Nepal weekendPatternByCountry.put("DZ",WEEKEND_FRI_SAT); //Algeria weekendPatternByCountry.put("BH",WEEKEND_FRI_SAT); //Bahrain weekendPatternByCountry.put("BD",WEEKEND_FRI_SAT); //Bangladesh weekendPatternByCountry.put("EG",WEEKEND_FRI_SAT); //Egypt weekendPatternByCountry.put("IQ",WEEKEND_FRI_SAT); //Iraq weekendPatternByCountry.put("IL",WEEKEND_FRI_SAT); //Israel weekendPatternByCountry.put("JO",WEEKEND_FRI_SAT); //Jordan weekendPatternByCountry.put("KW",WEEKEND_FRI_SAT); //Kuwait weekendPatternByCountry.put("LY",WEEKEND_FRI_SAT); //Libya weekendPatternByCountry.put("MV",WEEKEND_FRI_SAT); //Maldives weekendPatternByCountry.put("MR",WEEKEND_FRI_SAT); //Mauritania weekendPatternByCountry.put("MY",WEEKEND_FRI_SAT); //Malaysia weekendPatternByCountry.put("OM",WEEKEND_FRI_SAT); //Oman weekendPatternByCountry.put("PS",WEEKEND_FRI_SAT); //Palestine weekendPatternByCountry.put("QA",WEEKEND_FRI_SAT); //Qatar weekendPatternByCountry.put("SA",WEEKEND_FRI_SAT); //Saudi Arabia weekendPatternByCountry.put("SD",WEEKEND_FRI_SAT); //Sudan weekendPatternByCountry.put("SY",WEEKEND_FRI_SAT); //Syria weekendPatternByCountry.put("AE",WEEKEND_FRI_SAT); //United Arab Emirates weekendPatternByCountry.put("YE",WEEKEND_FRI_SAT); //Yemen } //Adjustment vectors - precomputed adjustment static int[][][] adjVector = new int[][][]{ {//WEEKEND_SAT_SUN //Positive number of days {1,0,-1,-2,-3,1,1}, {0,0}, {0,0,0,0,0,2,1}, //Negative number of days {-1,3,2,1,0,-1,-1}, {0,0}, {-1,1,1,1,1,1,0} }, {//WEEKEND_FRI_SAT //Positive number of days {0,-1,-2,-3,1,1,1}, {0,0}, {0,0,0,0,2,1,0}, //Negative number of days {3,2,1,0,-1,-1,-1}, {0,0}, {1,1,1,1,1,0,-1} }, {//WEEKEND_THU_FRI //Positive number of days {-1,-2,-3,1,1,1,0}, {0,0}, {0,0,0,2,1,0,0}, //Negative number of days {2,1,0,-1,-1,-1,3}, {0,0}, {1,1,1,1,0,-1,1} }, {//WEEKEND_FRI_SUN //Positive number of days {0,-1,-2,-3,-4,-4,0}, {1,0}, {0,0,0,0,0,-1,1}, //Negative number of days {4,3,2,1,0,0,4}, {0,-1}, {1,1,1,1,1,0,2} }, {//WEEKEND_FRI //Positive number of days {-1,-2,-3,-4,1,1,0}, {0}, {0,0,0,0,1,0,0}, //Negative number of days {3,2,1,0,-1,-1,4}, {0}, {1,1,1,1,1,0,1} }, {//WEEKEND_SAT //Positive number of days {0,-1,-2,-3,-4,1,1}, {0}, {0,0,0,0,0,1,0}, //Negative number of days {4,3,2,1,0,-1,-1}, {0}, {1,1,1,1,1,1,0} }, {//WEEKEND_SUN //Positive number of days {1,0,-1,-2,-3,-4,1}, {0}, {0,0,0,0,0,0,1}, //Negative number of days {-1,4,3,2,1,0,-1}, {0}, {0,1,1,1,1,1,1} } }; //O(1) algorithm to add business days. public static Date addBusinessDays(Date day, int days,int weekendPattern){ Calendar ret = Calendar.getInstance(); if(day != null) { ret.setTime(day); } if(days != 0) { int startDayofWeek = ret.get(Calendar.DAY_OF_WEEK)-1; //Zero based to use the vectors bellow. int idx = days > 0 ? 0 : 3; int howManyWeekendDays = 0; int[][] adjV = adjVector[weekendPattern]; int numWeekendDaysInOneWeek = adjV[idx+1].length; for(int i = 0; i < numWeekendDaysInOneWeek;i++){ int adjustmentA = adjV[idx][startDayofWeek]; //pattern shift int adjustmentB = adjV[idx+1][i]; //day shift howManyWeekendDays += (days-adjustmentA-adjustmentB)/(7-numWeekendDaysInOneWeek); } int adjustmentC = adjV[idx+2][startDayofWeek]; //f(0) adjustment howManyWeekendDays += adjustmentC; ret.add(Calendar.DATE,days + howManyWeekendDays); //TODO: Extend to support holidays using recursion // int numHolidays = getNumHolidaysInInterval(day,ret.getTime()); // if(numHolidays > 0) return addBusinessDays(ret.getTime,numHolidays); } return ret.getTime(); } public static Date addBusinessDays(Date day, int days,String country){ Integer weekpat = weekendPatternByCountry.get(country); return weekpat != null ? addBusinessDays(day,days,weekpat) : addBusinessDays(day,days,WEEKEND_SAT_SUN); } } 

Это метод, который я придумал:

  private Date addLaborDays(Integer days, Date date){ Collection holidaysList = getHolidays(); Calendar cal = Calendar.getInstance(); cal.setTime(date); cal.add(Calendar.DATE, 1); Date dateTemp = cal.getTime(); if(days == 1) return dateTemp; if(holidaysList.contains(dateTemp) || DateUtil.isWeekend(dateTemp)){ return addLaborDays(days, dateTemp); } else { return addLaborDays(days-1, dateTemp); } } 

Метод getHolidays() запрашивает таблицу пользовательских праздничных дней, а метод DateUtil.isWeekend(dateTemp) возвращает true, если dateTemp – суббота или воскресенье.

 /* To Calculate 10 business days ahead of today's date */ public class DueDate { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub DueDate d = new DueDate(); String dueDate = d.getDueDate(10); System.out.println("due Date " + dueDate); } public String getDueDate(int bday){ Calendar cal = new GregorianCalendar(); SimpleDateFormat fdate = new SimpleDateFormat("MM/dd/yyyy"); while(bday > 0){ cal.add(Calendar.DAY_OF_MONTH, 1); if(noWeekendsorHolidays(cal)){ bday--; } } return fdate.format(cal.getTime()); } public boolean noWeekendsorHolidays(Calendar cal){ int day = cal.get(Calendar.DAY_OF_WEEK); if(day == 1 || day == 7){ return false; } return true; } } 

Это работает для меня коротко и просто:

 public static Date getBusinessDay(final Date date, final int businessDaysFromDate) { final int max = 60; if (date == null) { return getBusinessDay(new Date(), businessDaysFromDate); } else if (date != null && (businessDaysFromDate < 0 || businessDaysFromDate > max)) { return getBusinessDay(date, 0); } else { final Calendar baseDateCal = Calendar.getInstance(); baseDateCal.setTime(date); for (int i = 1; i <= businessDaysFromDate; i++) { baseDateCal.add(Calendar.DATE, 1); while (baseDateCal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY || baseDateCal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) { baseDateCal.add(Calendar.DATE, 1); } } return baseDateCal.getTime(); } 

}

Добавление двух рабочих дней к текущей дате:

  Date today = new Date(); Calendar cal1 = Calendar.getInstance(); cal1.setTime(today); switch(cal1.get(Calendar.DAY_OF_WEEK)){ case 1: cal1.add(Calendar.DATE, 2); break; case 2: cal1.add(Calendar.DATE, 2); break; case 3: cal1.add(Calendar.DATE, 2); break; case 4: cal1.add(Calendar.DATE, 2); break; case 5: cal1.add(Calendar.DATE, 4); break; case 6: cal1.add(Calendar.DATE, 4); break; case 7: cal1.add(Calendar.DATE, 3); break; } // You may also set the time to meet your purpose: cal1.set(Calendar.HOUR_OF_DAY, 23); cal1.set(Calendar.MINUTE, 59); cal1.set(Calendar.SECOND, 59); cal1.set(Calendar.MILLISECOND, 00); Date twoWeekdaysAhead = cal1.getTime(); 
  • Какие общие алгоритмы используются для rand ()?
  • Как работает Google «Вы имели в виду?» Алгоритм работы?
  • Эффективное квантование цвета gif / изображения?
  • Обработка изображений: улучшение алгоритма для распознавания «Coca-Cola Can»
  • C #: Поиск алгоритма / библиотеки сжатия PNG
  • Маркировка связанных компонентов
  • Плавный спектр для создания Мандельброта
  • Как я могу рассчитать возраст человека в год, месяц, дни?
  • Наиболее эффективный способ случайного выбора набора различных целых чисел
  • Наименьшее общее число для 3 или более номеров
  • Обмен двумя переменными без использования временной переменной
  • Давайте будем гением компьютера.