# Berechnung der Arbeitstage in einem Zeitraum



## Sherry (16. Okt 2014)

Hallo,

ich habe mir zur Aufgabe gemacht, die Arbeitstage zwischen zwei Daten zu ermitteln. Da gelten in meiner Klasse der Samstag, Heiligabend und Silvester nicht als Arbeitstage.

```
package com.example.workingDays;

import org.joda.time.Days;
import org.joda.time.LocalDate;

/**
 * 
 * The parameters startDate and endDate are strings. calculateDays calculates the number
 * of project days in Germany between the two dates.
 */
public class WorkingDays {

	/**
	 * @param startDate, endDate
	 */
	public int calculateDays(String startDate, String endDate) {
		DateDisassembler d = new DateDisassembler();
		LocalDate date1 = new LocalDate(d.disassemble(startDate)[2], d.disassemble(startDate)[1], d.disassemble(startDate)[0]);
    	LocalDate date2 = new LocalDate(d.disassemble(endDate)[2], d.disassemble(endDate)[1], d.disassemble(endDate)[0]);
    	/*
    	 * Calculates the weekend days
    	 */
    	int weekend = 0;
    	int count = 0;
    	Eastern easterHolidays = new Eastern();
    	for (LocalDate date = date1; date.isBefore(date2); date = date.plusDays(1)) {
    		if (date.getDayOfWeek() == 6 || date.getDayOfWeek() == 7) {
    			weekend++;
    		}
    		count++;
    	}
    	System.out.println(count);
    	/*
    	 * Calculates the German holidays
    	 */
    	int holidays = 0;
    	for (LocalDate date = date1; date.isBefore(date2); date = date.plusDays(1)) {
    		int year = date.getYear();
    		// New Year's Day
    		if (date.getMonthOfYear() == 1 && date.getDayOfMonth() == 1 && !(date.getDayOfWeek() == 6 || date.getDayOfWeek() == 7)) {
    			holidays++;
			}
    		// Epiphany
    		if (date.getMonthOfYear() == 1 && date.getDayOfMonth() == 6 && !(date.getDayOfWeek() == 6 || date.getDayOfWeek() == 7)) {
    			holidays++;
			}
    		// Good Friday
    		if (date.toString().equals(easterHolidays.calculate(year, 1))) {
    			holidays++;
			}
    		// Easter Monday
    		if (date.toString().equals(easterHolidays.calculate(year, 2))) {
    			holidays++;
			}
    		// Ascension Day
    		if (date.toString().equals(easterHolidays.calculate(year, 3))) {
    			holidays++;
			}
    		// Whit Monday
    		if (date.toString().equals(easterHolidays.calculate(year, 4))) {
    			holidays++;
			}
    		// Corpus Christi
    		if (date.toString().equals(easterHolidays.calculate(year, 5))) {
    			holidays++;
			}
    		// Labor Day
    		if (date.getMonthOfYear() == 5 && date.getDayOfMonth() == 1 && !(date.getDayOfWeek() == 6 || date.getDayOfWeek() == 7)) {
    			holidays++;
			}
    		// German Unity Day
    		if (date.getMonthOfYear() == 10 && date.getDayOfMonth() == 3 && !(date.getDayOfWeek() == 6 || date.getDayOfWeek() == 7)) {
				holidays++;
			}
    		// All Saints
    		if (date.getMonthOfYear() == 11 && date.getDayOfMonth() == 1 && !(date.getDayOfWeek() == 6 || date.getDayOfWeek() == 7)) {
				holidays++;
			}
    		// Christmas Day
    		if (date.getMonthOfYear() == 12 && date.getDayOfMonth() == 24 && !(date.getDayOfWeek() == 6 || date.getDayOfWeek() == 7)) {
				holidays++;
			}
    		if (date.getMonthOfYear() == 12 && date.getDayOfMonth() == 25 && !(date.getDayOfWeek() == 6 || date.getDayOfWeek() == 7)) {
				holidays++;
			}
    		if (date.getMonthOfYear() == 12 && date.getDayOfMonth() == 26 && !(date.getDayOfWeek() == 6 || date.getDayOfWeek() == 7)) {
				holidays++;
			}
    		// New Year's Eve
    		if (date.getMonthOfYear() == 12 && date.getDayOfMonth() == 31 && !(date.getDayOfWeek() == 6 || date.getDayOfWeek() == 7)) {
				holidays++;
			}
    	}
    	Days days = Days.daysBetween(date1, date2);
    	int diffDays = 1+days.getDays();
    	System.out.println("Differenz:    " + diffDays);
    	System.out.println("Wochenenden : " + weekend);
    	System.out.println("Feiertage   : " + holidays);
		return diffDays - weekend - holidays;
		
	}

}
```

DateDisassembler macht aus "12.5.2014" 12, 5 und 2014 zur Weiterverarbeitung.


```
/**
 * Eastern.java
 */
package com.example.workingDays;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;


public class Eastern {
	private String eastern;

	/**
	 * @param year, index
	 * The parameter year is given as a integer and must be greater than 1593.
	 * The parameter index is a integer for Good Friday (1), Easter Monday (2),
	 * Ascension (3), Whit Monday (4) and Corpus Christi (5).
	 * Return value is a string with the date of the selected holiday.
	 */
	public String calculate(int year, int index) {
		int y = year;
		int g = y % 19;
	    int c = y / 100;
	    int h = (c - c / 4 - (8 * c + 13) / 25 + 19 * g + 15) % 30;
	    int i = h - (h / 28) * (1 - (29 / (h + 1)) * ((21 - g) / 11));
	    int j = (y +y / 4 + i + 2 - c + c / 4) % 7;
	    int l = i - j;
	    int monat = 3 + (l + 40) / 44;
	    int day = l + 28 - 31 * (monat / 4);
	    int difference = 0;
	    switch (index) {
		case 1:
			difference = -2;
			break;
		case 2:
			difference = 1;
			break;
		case 3:
			difference = 39;
			break;
		case 4:
			difference = 50;
			break;
		case 5:
			difference = 60;
			break;
		}
	    DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
	    Calendar easternSunday = new GregorianCalendar();
	    easternSunday.set(y, monat-1, day);
	    easternSunday.add(Calendar.DAY_OF_MONTH, difference);
	    eastern = dateFormat.format(easternSunday.getTime());
		return eastern;
	}
}
```


```
package com.example.WorkingDays;

public class MainTest {

	public static void main(String[] args) {
		WorkingDays d = new WorkingDays();
		System.out.println("Anzahl der Arbeitstage: " + d.calculateDays("1.10.2014", "31.10.2014"));
	}

}
```

Ich suche gerade eine Abweichung der Anzahl der Arbeitstage, die ich mir im Code nicht erklären kann.
Führe ich die Klassen für 1.10.2014 bis 31.10.2014 aus, erhalte ich 22 Tage, was auch stimmt.
Für 1.11.2014 bis 30.11.2014 erhalte ich 21 Tage, korrekt sind aber nur 20 Tage. Über mehrere Monate schleichen sich so Differenzen ein.
Ich finde allerdings nicht den Fehler in meinem Denkansatz. Vielleicht seht ihr ihn und könnt mir weiterhelfen.
Grüße und besten Dank
Sherry


----------



## Joose (16. Okt 2014)

Sherry hat gesagt.:


> ........
> Ich suche gerade eine Abweichung der Anzahl der Arbeitstage, die ich mir im Code nicht erklären kann.
> ........
> Ich finde allerdings nicht den Fehler in meinem Denkansatz. Vielleicht seht ihr ihn und könnt mir weiterhelfen.



Kleiner Tipp um deinen Fehler vielleicht leichter zu finden (ohne das ich mir den Code genau angeschaut habe).
In der Methode "WorkingDays.calculateDays(...)" hast du eine Schleife um die Ferien und Feiertage zu zählen, füge bei jedem Fall eine passende Konsolen-/Logausgabe ein.
Damit kannst du leichter nachvollziehen welche Feiertage/Ferien dein Code gefunden hat.


----------



## jgh (16. Okt 2014)

das hast du beachtet?
A month is represented by an integer from 0 to 11;


----------



## Joose (16. Okt 2014)

@jgh
Es wird JodaTime benutzt, außer bei der Klasse Eastern (aber dort wird korrekt das Monat vermindert)


----------



## d.fuhri (16. Okt 2014)

Hallo 

Der letzte Tag wird nicht auf Weekend verglichen. 
Es ist nur date < date2 und nicht date <= date2.


```
for (LocalDate date = date1; date.isBefore(date2); date = date.plusDays(1))
```
Gruss


----------



## jgh (16. Okt 2014)

> @jgh
> Es wird JodaTime benutzt, außer bei der Klasse Eastern (aber dort wird korrekt das Monat vermindert)



Ok, sorry und thx


----------



## Sherry (16. Okt 2014)

Erstmal besten Dank Joose für den Tipp mit der Schleifenreduzierung und Deine PM.

Und das hier sehe ich jetzt auch:


d.fuhri hat gesagt.:


> Hallo
> 
> Der letzte Tag wird nicht auf Weekend verglichen.
> Es ist nur date < date2 und nicht date <= date2.
> ...


Das ist jetzt die Frage ob JodaTime neben isBefore() auch ein isBeforeAndEqual() anbietet, oder wie ich die zusätzliche Abfrage einbaue.

Grüße

Sherry


----------



## Sherry (16. Okt 2014)

Mit dieser Erweiterung hier

```
for (LocalDate date = date1; date.isBefore(date2) || date.isEqual(date2); date = date.plusDays(1)) {
```
klappt es jetzt auf kurze Zeiträume.
Dennoch der Zeitrraum 01.10.2014 bis 01.10.2015 liefert bei mir 254 Tage, richtig wären aber 249 Tage. Da bin ich noch am Suchen.

Grüße

Sherry


----------



## Sherry (16. Okt 2014)

Ahh, ich seh's: Die beweglichen Feiertage aus der Eastern-Klasse werden verschluckt.


----------



## Sherry (17. Okt 2014)

Das Thema hier gilt für mich als gelöst.
In Eastern.java muss lediglich

```
DateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy");
```
gegen

```
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
```
ausgetauscht werden.


----------

