我需要计算两个日期之间的工作日。 例如:我们在july4th假期(在美国)。 所以,如果我的日期日期1 = 07月03日期2 = 07月06日
没有工作日B / W这些日期应该是1,因为july4th是假期。
我有一个下面的方法来calclulate业务天,这只会计算本周结束,但没有节假日。 有没有什么办法计算假期也....请帮我在这。
public static int getWorkingDaysBetweenTwoDates(Date startDate, Date endDate) {
Calendar startCal;
Calendar endCal;
startCal = Calendar.getInstance();
startCal.setTime(startDate);
endCal = Calendar.getInstance();
endCal.setTime(endDate);
int workDays = 0;
//Return 0 if start and end are the same
if (startCal.getTimeInMillis() == endCal.getTimeInMillis()) {
return 0;
}
if (startCal.getTimeInMillis() > endCal.getTimeInMillis()) {
startCal.setTime(endDate);
endCal.setTime(startDate);
}
do {
startCal.add(Calendar.DAY_OF_MONTH, 1);
if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY
&& startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
++workDays;
}
} while (startCal.getTimeInMillis() < endCal.getTimeInMillis());
return workDays;
}
让我们假设你有一个包含所有的节假日列表,如你所提到的。
ArrayList<Integer> holidays = ...
只需添加一个条件,你if
在你的病情do-while
:
do {
startCal.add(Calendar.DAY_OF_MONTH, 1);
if (startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SATURDAY
&& startCal.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY
&& !holidays.contains((Integer) startCal.get(Calendar.DAY_OF_YEAR))) {
++workDays;
}
} while (startCal.getTimeInMillis() < endCal.getTimeInMillis());
为简单起见,我假定holiday
包含格式相同的日期Calendar.DAY_OF_YEAR
。
Nager.Date
您可以使用JSON API的Nager.Date项目。 它支持美国,加拿大和欧洲。 可用于每年的数据可以保存在自己的数据库中的信息。
例
//https://github.com/FasterXML/jackson-databind/
ObjectMapper mapper = new ObjectMapper();
MyValue value = mapper.readValue(new URL("http://date.nager.at/api/v1/get/US/2017"), PublicHoliday[].class);
PublicHoliday.class
public class PublicHoliday
{
public String date;
public String localName;
public String name;
public String countryCode;
public Boolean fixed;
public Boolean countyOfficialHoliday;
public Boolean countyAdministrationHoliday;
public Boolean global;
public String[] counties;
public int launchYear;
}
例如JSON数据检索。
[
{
"date": "2017-01-01",
"localName": "New Year's Day",
"name": "New Year's Day",
"countryCode": "US",
"fixed": true,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": true,
"counties": null,
"launchYear": null
},
{
"date": "2017-01-16",
"localName": "Martin Luther King, Jr. Day",
"name": "Martin Luther King, Jr. Day",
"countryCode": "US",
"fixed": true,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": true,
"counties": null,
"launchYear": null
},
{
"date": "2017-01-20",
"localName": "Inauguration Day",
"name": "Inauguration Day",
"countryCode": "US",
"fixed": true,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": false,
"counties": [
"US-DC",
"US-LA",
"US-MD",
"US-VA"
],
"launchYear": null
},
{
"date": "2017-02-20",
"localName": "Washington's Birthday",
"name": "Presidents' Day",
"countryCode": "US",
"fixed": true,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": true,
"counties": null,
"launchYear": null
},
{
"date": "2017-05-29",
"localName": "Memorial Day",
"name": "Memorial Day",
"countryCode": "US",
"fixed": true,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": true,
"counties": null,
"launchYear": null
},
{
"date": "2017-07-04",
"localName": "Independence Day",
"name": "Independence Day",
"countryCode": "US",
"fixed": true,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": true,
"counties": null,
"launchYear": null
},
{
"date": "2017-09-04",
"localName": "Labor Day",
"name": "Labor Day",
"countryCode": "US",
"fixed": true,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": true,
"counties": null,
"launchYear": null
},
{
"date": "2017-09-09",
"localName": "Columbus Day",
"name": "Columbus Day",
"countryCode": "US",
"fixed": true,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": false,
"counties": [
"US-AL",
"US-AZ",
"US-CO",
"US-CT",
"US-DC",
"US-GA",
"US-ID",
"US-IL",
"US-IN",
"US-IA",
"US-KS",
"US-KY",
"US-LA",
"US-ME",
"US-MD",
"US-MA",
"US-MS",
"US-MO",
"US-MT",
"US-NE",
"US-NH",
"US-NJ",
"US-NM",
"US-NY",
"US-NC",
"US-OH",
"US-OK",
"US-PA",
"US-RI",
"US-SC",
"US-TN",
"US-UT",
"US-VA",
"US-WV"
],
"launchYear": null
},
{
"date": "2017-11-10",
"localName": "Veterans Day",
"name": "Veterans Day",
"countryCode": "US",
"fixed": false,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": true,
"counties": null,
"launchYear": null
},
{
"date": "2017-12-23",
"localName": "Thanksgiving Day",
"name": "Thanksgiving Day",
"countryCode": "US",
"fixed": true,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": true,
"counties": null,
"launchYear": 1863
},
{
"date": "2017-12-25",
"localName": "Christmas Day",
"name": "Christmas Day",
"countryCode": "US",
"fixed": true,
"countyOfficialHoliday": true,
"countyAdministrationHoliday": true,
"global": true,
"counties": null,
"launchYear": null
}
]
由于接受的答案仍然使用过时的Calendar
类-这是一个使用新的Java日期和时间API我的两分钱。
你必须得到从什么地方休假的日期,没有标准的Java库,用于它。 这无论如何都会过于本地化,因为假期在很大程度上取决于你的国家和地区。 (除广为人知的节日,如圣诞节,复活节)。
你可以从一个假期API得到它们,例如。 在下面的代码,我硬编码它们作为一个List
的LocalDate
秒。
Java的9
LocalDate startDate = LocalDate.of(2012, 3, 7);
LocalDate endDate = LocalDate.of(2012, 6, 7);
// I've hardcoded the holidays as LocalDates and put them in a List
final List<LocalDate> holidays = Arrays.asList(
LocalDate.of(2018, 7, 4)
);
List<LocalDate> allDates =
// Java 9 provides a method to return a stream with dates from the
// startdate to the given end date. Note that the end date itself is
// NOT included.
startDate.datesUntil(endDate)
// Retain all business days. Use static imports from
// java.time.DayOfWeek.*
.filter(t -> Stream.of(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY)
.anyMatch(t.getDayOfWeek()::equals))
// Retain only dates not present in our holidays list
.filter(t -> !holidays.contains(t))
// Collect them into a List. If you only need to know the number of
// dates, you can also use .count()
.collect(Collectors.toList());
Java的8
该方法LocalDate.datesUntil
不是在Java中8,所以你必须获得以不同的方式在这两个日期之间的所有日期的流。 我们必须先算在使用之间的天总数ChronoUnit.DAYS.between
方法。
long numOfDaysBetween = ChronoUnit.DAYS.between(startDate, endDate);
然后,我们必须生成一个整数序列完全相同,只要开始和结束日期之间的天数,然后创建LocalDate
从中S,起始于开始日期。
IntStream.iterate(0, i -> i + 1)
.limit(numOfDaysBetween)
.mapToObj(startDate::plusDays)
现在我们有一个Stream<LocalDate>
,然后你可以使用Java代码9的剩余部分。
我发现,最快的方式是使用一些数学(从借款SO后):
public static int totalBusinessDaysBetween(LocalDate start, LocalDate end) {
Objects.requireNonNull(start, "Start date must not be null");
Objects.requireNonNull(end, "End date must not be null");
long daysBetweenWithoutWeekends = calculateNumberOfDaysBetweenMinusWeekends(start, end);
final Set<LocalDate> holidayForYearRange = getUSFederalHolidayForYearRange(start.getYear(), end.getYear());
for (LocalDate localDate : holidayForYearRange) {
if (localDate.isAfter(start) && localDate.isBefore(end)) {
daysBetweenWithoutWeekends--;
}
}
return (int) daysBetweenWithoutWeekends;
}
和:
private static long calculateNumberOfDaysBetweenMinusWeekends(LocalDate start, LocalDate end) {
final DayOfWeek startW = start.getDayOfWeek();
final DayOfWeek endW = end.getDayOfWeek();
final long days = ChronoUnit.DAYS.between(start, end);
final long daysWithoutWeekends = days - 2 * ((days + startW.getValue()) / 7);
//adjust for starting and ending on a Sunday:
return daysWithoutWeekends + (startW == DayOfWeek.SUNDAY ? 1 : 0) + (endW == DayOfWeek.SUNDAY ? 1 : 0);
}
我把东西更完整的一起在这里 。