# Zeiträume unterteilen, JodaTime



## Spewer (16. Okt 2012)

Hallo liebe Leute,

ich bin auf ein Problem gestoßen bei der Programmierung von einem kleinen Programm. 
Hoffe, dass Ihr vllt ein paar Tipps für mich habt.

Das Problem ist, dass ich nicht weiß, wie ich einen Zeitraum in mehrere Zeiträume unterteile.
Ziel ist es einen Zeitraum, in Wochen zu unterteilen. (Bsp.: Zeitraum: 1.6 - 31.8, müssten 13 Wochen sein).
Aber hier erst mein Vorgehen. Für sämtliche zeitlichen Berechnungen wollte ich eig. JodaTime benutzen. Bin aber für andere Vorschläge offen.

1) 2 "DateTime"s bestimmen (firstLogin, lastLogout)
2) mit Hilfe von Duration den Zeitraum ermitteln 
3) Ermittlung der Anzahl der Tage in diesem Zeitraum
4) Tage dividiert durch 7 = Anzahl der Wochen

Soweit so gut, leider weiß ich jetzt nicht weiter. Wie kann ich einzelne Zeiträume erzeugen, die jeweils eine Woche lang sind. Wahrscheinlich muss man das ganze ja in Arrays speichern.


```
int sessionsLength = 0;
	int days = 0;
	long tmpDays = 0;

	users = data.getUsers();
	sessions = data.getSessions();

	sessionsLength = sessions.size();
	DateTime firstLogin = sessions.get(sessionsLength - 1).getLogin();
	DateTime lastLogout = sessions.get(0).getLogout();

	Duration d = new Duration(firstLogin, lastLogout);
	tmpDays = d.getStandardDays();

	days = (int) tmpDays;
	
	totalWeeks = days / 7;
```

Ein kleiner Ausschnitt aus dem gesamten Projekt, der die Schritte 1-4 zeigt.

Für Tipps und Tricks wäre ich sehr verbunden.

Grüße
Spewer


----------



## faetzminator (16. Okt 2012)

Stimmt das Resultat in [c]totalWeeks[/c] nicht?


----------



## Spewer (16. Okt 2012)

Ich wusste bis dato garnicht, dass es soetwas gibt. 
Wie verwendet man denn "totalWeeks" richtig bei einer Duration ?
"getWeeks" bei einer Period hat leider nicht das gewünschte Ergebnis gebracht.


----------



## faetzminator (16. Okt 2012)

Ich verstehe deine Frage nicht. [c]getStandardDays()[/c] liefert gem. API:


> Gets the length of this duration in days assuming that there are the standard number of milliseconds in a day.


Nicht berücksichtigt sind da lediglich Schaltsekunden o.ä., das ist allerdings vernachlässigbar. Sicher dass in den beiden [c]DateTime[/c] korrekte Daten drin sind?


----------



## Spewer (16. Okt 2012)

Der ganze Teil mit "getStandardDays" funktioniert ja soweit auch. Ich bekomme ja die Anzahl der Wochen raus mit dem Code von oben.

Nur wie ich weiter mache weiß ich nicht.
Sinnvollerweise erzeuge ich ein Array, wo ich die Daten der einzelnen Wochen reinspeicher.
Nur bei der praktischen Umsetzung scheitere ich


----------



## jgh (16. Okt 2012)

also hier mal eine schnell Möglichkeit das mit den StandardKlassen des SDK´s zu lösen.


```
public static void main(String[] args) {

		Calendar c1 = new GregorianCalendar();
		Calendar c2 = new GregorianCalendar();
		c1.set(Calendar.MONTH, 5);// zu beachten, dass die Monatszahl mit 0
									// beginnt für Janunar bspw
		c1.set(Calendar.DAY_OF_MONTH, 1);
		c2.set(Calendar.MONTH, 7);
		c2.set(Calendar.DAY_OF_MONTH, 31);
		setCalendarToBeginOfDays(c1);
		setCalendarToBeginOfDays(c2);
		long diff = c2.getTimeInMillis() - c1.getTimeInMillis();

		int days = (int) (diff / 1000l / 60l / 60l / 24l);
		int week = (int) (diff / 1000l / 60l / 60l / 24l / 7);

		Date[] dateArray = new Date[week * 2];
		for (int i = 0; i < dateArray.length; i++) {
			dateArray[i] = c1.getTime();
			c1.add(Calendar.DAY_OF_YEAR, 7);
			i++;
			dateArray[i] = c1.getTime();
		}
		for (int i = 0; i < dateArray.length; i = i + 2) {
			System.out.println(dateArray[i] + " - " + dateArray[i + 1]);

		}
		System.out.println("Days=" + days + " weeks=" + week);

	}

	public static void setCalendarToBeginOfDays(Calendar c) {
		c.set(Calendar.MILLISECOND, 0);
		c.set(Calendar.SECOND, 0);
		c.set(Calendar.MINUTE, 0);
		c.set(Calendar.HOUR_OF_DAY, 0);
	}
```


----------



## Spewer (16. Okt 2012)

Vielen Dank. Das war sehr hilfreich !
Muss mal schauen, dass ich dann das Projekt umstelle und JodaTime "verbanne"


----------



## jgh (16. Okt 2012)

es gibt ja einige/viele hier, die auf JODA schwören...gibt sicherlich einige Bereiche, wo Joda bequemer und einfacher zu gebrauchen ist...aber grundsätzlich kann man imho das alles auch  (manchmal zugegebenermaßen umständlich) mit den Standardklassen erreichen.


----------



## Spewer (16. Okt 2012)

Gibt es die Möglichkeit mit der Standardklasse eine Abfrage zu machen so wie: 
	
	
	
	





```
is between
```
 ?

Also 
	
	
	
	





```
if (Date A.is between(dateArray[i]))
```


----------



## faetzminator (16. Okt 2012)

Davon ausgegangen, dass die jeweilige Datumsklasse [c]Comparable[/c] ist kannst du das relativ elegant lösen:

```
if (someDate.compareTo(date1) > 0 && someDate.compareTo(date2) < 0) { ... }
```


----------



## Spewer (16. Okt 2012)

okay, klingt logisch.
Danke euch Beiden vielmals!


----------



## Spewer (16. Okt 2012)

Hab doch noch eine Frage.
Wenn man das so coded : 
	
	
	
	





```
for (int i = 0; i < dateArray.length; i++) {
            dateArray[i] = c1.getTime();
            c1.add(Calendar.DAY_OF_YEAR, 7);
            i++;
            dateArray[i] = c1.getTime();
        }
```

dann erzeugt man ja ein eindimensionales Array mit folgendem Inhalt: 





> datum 1
> datum 2
> datum 3
> .
> ...



Wäre es auch möglich ein Array der Form: 
	
	
	
	





```
dateArray[week][]
```
 zu erzeugen, was dann so gefüllt wird:


> datum 1 - datum 2
> datum 2 - datum 3
> datum 3 - datum 4
> .
> ...



Stehe da gerade irgendwie auf dem Schlauch.


----------



## jgh (16. Okt 2012)

klar kannst du das ....entweder ein 2 -dim Date Array, oder du baust dir eine Klasse bspw. MyWeek...die rudimentär so oder ähnlich aussieht...


```
Date[][] dateArray = new Date[week][2];
		MyWeek[] myWeekArray = new MyWeek[dateArray.length];

	class MyWeek {
		Date startWeek;
		Date endWeek;
	}
```


----------



## Spewer (17. Okt 2012)

Jetzt hat sich leider ein weiteres Problem ergeben...
Ich möchte nun keine Einteilung mehr in Wochen sondern in Monaten.

Das heißt, bei einem Zeitraum vom zb.: 15.1 - 29.3 soll das DateArray so aussehen: [15.01 , 01.02 , 01.03]

Mir ist nur nicht wirklich klar, wie ich das mit den Standardklassen machen kann.

Ich kann eventuell mit 
	
	
	
	





```
calender1.get(Calendar.DAY_OF_MONTH);
```
 den Tag bestimmen aber leider weiß ich nicht wirklich weiter.
Eine Schleife, die immer einen Tag addiert und sobald 
	
	
	
	





```
calender1.get(Calendar.DAY_OF_MONTH); = 1
```
  ist,  im Array einen Eintrag mehr ?

Oder gibt es wohl eine einfache, bessere Art und Weise.
Hoffe, dass das überhaupt verständlich ist 

*Edit*: Habe es jetzt so gelöst, jedenfalls glaube ich, dass es so richtig funktioniert.

```
int dif = c2.get(Calendar.MONTH) - c1.get(Calendar.MONTH);
	
	dateArray = new Date[dif * 2];
	for (int i = 0; i < dateArray.length; i++)
	{
	    dateArray[i] = c1.getTime();
	    c1.roll(Calendar.MONTH, 1);
	    i++;
	    dateArray[i] = c1.getTime();
	}
```

Edit Edit : Die Lösung oben funktioniert leider nur wenn das erste Datum zb. der 01.06 ist. wenns der 03.06 ist, geht die logik nicht mehr auf


----------



## jgh (17. Okt 2012)

ungetestet, Bedingung ist das c1 das ältere Datum gegenüber c2 hält...und wirklich schön ist es auch nicht...mal sehen, evtl. heute abend etwas sinnvolleres...



```
Calendar c1 = new GregorianCalendar();
		Calendar c2 = new GregorianCalendar();
		c1.set(Calendar.MONTH, 1);
		c1.set(Calendar.DAY_OF_MONTH, 15);
		c2.set(Calendar.MONTH, 9);
		c2.set(Calendar.DAY_OF_MONTH, 14);

		int monatsArrayGroesse = (c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR))
				* 12 + (c2.get(Calendar.MONTH) - c1.get(Calendar.MONTH) + 1);

		Date[] dateArray = new Date[monatsArrayGroesse];
		dateArray[0] = c1.getTime();
		for (int i = 1; i < dateArray.length; i++) {
			while (c1.get(Calendar.DAY_OF_MONTH) != 1) {
				c1.add(Calendar.DAY_OF_MONTH, 1);
			}
			dateArray[i] = c1.getTime();
			c1.add(Calendar.MONTH, 1);

		}
		System.out.println(Arrays.toString(dateArray));
```


----------



## Spewer (17. Okt 2012)

Danke, hast mir sehr viel weitergeholfen.
Habe den Code ein wenig optimiert und jetzt funktioniert es sehr gut


----------



## jgh (17. Okt 2012)

dann zeig dochmal deine Optimierungen pls


----------



## Spewer (17. Okt 2012)

```
c1.setTime(firstLogin);
	c2.setTime(lastLogout);

	month = (c2.get(Calendar.YEAR) - c1.get(Calendar.YEAR)) * 12
		+ (c2.get(Calendar.MONTH) - c1.get(Calendar.MONTH) + 1);

	dateArray = new Date[month];

	if (c1.get(Calendar.DAY_OF_MONTH) != 1)
	{
	    dateArray[0] = c1.getTime();

	    for (int i = 1; i < dateArray.length; i++)
	    {
		while (c1.get(Calendar.DAY_OF_MONTH) != 1)
		{
		    c1.add(Calendar.DAY_OF_MONTH, 1);
		}
		dateArray[i] = c1.getTime();
		c1.add(Calendar.MONTH, 1);
	    }
	}
	else
	{
	    for (int i = 0; i < dateArray.length; i++)
	    {
		while (c1.get(Calendar.DAY_OF_MONTH) != 1)
		{
		    c1.add(Calendar.DAY_OF_MONTH, 1);
		}
		dateArray[i] = c1.getTime();
		c1.add(Calendar.MONTH, 1);
	    }
	}
```

Schaut jetzt im Projekt so aus.
Eigentlich habe ich nur den 
	
	
	
	





```
if - else
```
 Part reingebaut, damit sichergestellt wird, dass er nicht zweimal das selbe Datum ins Array schreibt, wenn der Zeitraum am 1. des Monats anfängt.


----------



## Spewer (18. Okt 2012)

Nach den ganzen Berechnungen von oben, stehe ich nun vor dem Problem nicht einfach auszuwählen ob Zeitraum = Wochen oder Monate, sondern nun will ich es umsetzen, dass ich ein beliebiges Intervall eingebe.
Beispiel: 
Zeitraum: 1.6 - 1.9 
Intervall = 2

Zuerst habe ich mir überlegt, sollte ich die Differenz der beiden Daten ausrechnen

```
long diff = c2.getTimeInMillis() - c1.getTimeInMillis();
```
Danach sollte die Differenz durch die Anzahl an Intervallen dividiert werden. Das Ergebnis ist ja dann die Zeit (in Millis) von einem Interval

```
long oneInterval= diff / intervals;
```

Nun erstelle ich wieder mein DateArray mit der Länge von den Intervallen

```
dateArray = new Date[intervals];
```

nur weiß ich leider nicht weiter... habe einiges versucht nur das Problem ist, dass wenn Intervall = ausgewählt wird, sollen im Array 3 Werte stehen [1.6; 15.7; 1.9]. Habe folgendes ausprobiert aber das geht nicht wirklich.

```
if (oneInterval <= Integer.MAX_VALUE)
	{
	    dateArray = new Date[intervals + 1];

	    for (int i = 0; i < dateArray.length; i++)
	    {
		dateArray[i] = c1.getTime();
		c1.add(Calendar.MILLISECOND, (int) oneInterval);
	    }
	}
	else
	{
	    int oneIntervalMinutes = (int) (diff / 1000l / 60l);

	    dateArray = new Date[intervals + 1];

	    for (int i = 0; i < dateArray.length; i++)
	    {
		dateArray[i] = c1.getTime();
		c1.add(Calendar.MINUTE, oneIntervalMinutes);
	    }
	}
```

Hat da nochmal jemand einen Tipp für mich ?


----------



## jgh (18. Okt 2012)

das ist nicht logisch...wo soll denn bei 2 Intervallen im o.g. Zeitraum die Logik herkommen, dass der 15.7 die Intervalle unterteilen soll?
immer inc. der genannten Tage:
1.6. -30.6 = 30 Tage
1.7 - 31.7 = 31 Tage
1.8 - 30.8 = 30 Tage
+1.9 =           1 Tag
Summe = 92 Tage / 2 Intervalle = 46 Tage/intervall => 1.6 + 30 Tage = 1.07 

1.7+16 Tage = 17.07 als Intervallgrenze


----------



## Spewer (18. Okt 2012)

Hehe, ja das ist mir auch 10 Min nach meinem Post aufgefallen. Musste die Logik etwas ändern.
Hier der fertige Code soweit, damit klappt es gut:


```
long diff = c2.getTimeInMillis() - c1.getTimeInMillis();
	long oneInterval = diff / intervals;
		
	int minutes = (int) (oneInterval / 1000l / 60l );
	
	
	dateArray = new Date[intervals + 1];
	
	dateArray[0] = c1.getTime();
	dateArray[dateArray.length - 1] = c2.getTime();
	
	for (int i = 1; i < dateArray.length - 1; i++)
	{
	    c1.add(Calendar.MINUTE, minutes);
	    dateArray[i] = c1.getTime();
	}
```


----------

