# Problem mit erster Kalenderwoche



## TomAdam (12. Nov 2012)

Moin,

ich bin auf folgendes Problem gestossen: Wenn ich für den 31.12.2012 die Kalenderwoche ermitteln möchte, liefert mir der GregorianCalendar trotz gesetzter TimeZone und Locale statt ""01.2013" fälschlich "01.2012" als Ausgabe zurück. Wie komme ich auf den korrekten Wert bzw. was mache ich flscha?


```
Calendar calendar = GregorianCalendar.getInstance(
        		TimeZone.getTimeZone( "Europe/Berlin" ), 
        		Locale.GERMANY);        
        calendar.setMinimalDaysInFirstWeek(4);
        SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy");        
        try
    	{			
        	calendar.setTime(df.parse("31.12.2012"));
        }
        catch (Exception ignore) {}
        
        df.applyPattern("ww.yyyy");
        System.out.println("Woche/Jahr: " + df.format(calendar.getTime()));
```

Grüsse


Tom


----------



## hüteüberhüte (12. Nov 2012)

> ```
> calendar.setMinimalDaysInFirstWeek(4);
> ```



Liegts daran? (4-Tage-Woche?)


----------



## bERt0r (12. Nov 2012)

Wie kommst du darauf dass der 31.12.2012 in der ersten KW des Jahres 2013 liegen soll? Btw: 
	
	
	
	





```
catch (Exception ignore) {}
```
 Sowas is auch immer ganz toll wenn man irgend einen Fehler hat und den dann sucht....


----------



## TomAdam (12. Nov 2012)

hüteüberhüte hat gesagt.:


> Liegts daran? (4-Tage-Woche?)



Nein, die erste Woche des Jahres ist nach DIN/ISO die Woche, in die mindestens vier Tage des neuen Jahres fallen, dieser Wert wird damit gesetzt bzw. sollte damit eigentlich gesetzt werden.
Wenn man die Zeile auskommentiert, ändert das aber nichts am falschen Ergebnis.




bERt0r hat gesagt.:


> Wie kommst du darauf dass der 31.12.2012 in der ersten KW des Jahres 2013 liegen soll?



Ein Blick auf den neuen Wandkalendar verrät mir das.



bERt0r hat gesagt.:


> Btw:
> 
> 
> 
> ...



Im Beispielcode tritt keine Exception auf. In der Anwendung würde ich allfällige Exceptions natürlich handeln.


Tom


----------



## SlaterB (12. Nov 2012)

ab Java 1.7 scheint es in SimpleDateFormat gerade Y statt y neu zu geben
SimpleDateFormat (Java Platform SE 7 )
kann ich persönlich nicht testen, yyyy selber kann offensichtlich nur das normale richtige Jahr sein

erschaunlicherweise in Calendar keinerlei Angebot, sofern ich das überblicke, 
da zweifle ich dann dass SimpleDateFormat mehr kann, aber was soll Y dort als 'Week year' sonst sein?
nach
java - Getting wrong data when using SimpleDateFormat.parse() - Stack Overflow
sieht es auch funktionierend aus

im Zweifel selber zusammenbauen (+1 ..) oder vielleicht bei Alternativen wie Joda Time vorbei schauen

noch ein Link
java - SimpleDateFormat Week Calculations - Stack Overflow


----------



## D4rkscr43m (12. Nov 2012)

yyyy gibt IMMER das Jahr aus, welches vom Calendar angegeben ist. Das Problem mit dem Ausgeben der Woche kannst du lösen, indem du auf den Donnerstag der Woche springst.

Aus dem 31.12.12 wird dann der 03.01.13 und wenn du von dem das Calendar-Objekt mit dem Format ww.yyyy ausgibst, bekommst du das richtige Ergebnis.

[EDIT]Muss natürlich der Donnerstag sein. Denn wenn der Donnerstag einer Woche im alten Jahr liegt, gehört die Woche zum alten Jahr und wenn der Donnerstag der Woche im neuen Jahr liegt, gehört die Woche zum neuen Jahr.[/EDIT]


----------



## TomAdam (12. Nov 2012)

D4rkscr43m hat gesagt.:


> Das Problem mit dem Ausgeben der Woche kannst du lösen, indem du auf den Donnerstag der Woche springst.



Danke, aber das löst nicht mein Problem, für ein bestimmtes Datum wie den 31.12.2012 oder den 30.12.2013 die richtige Kalenderwoche zu bestimmen. Das Problem scheint im übrigen nur bei Jahren aufzutreten, die 52 Wochen haben, bei Jahren mit 53 Wochen klappt es problemlos.


Tom


----------



## SlaterB (12. Nov 2012)

> Das Problem scheint im übrigen nur bei Jahren aufzutreten, die 52 Wochen haben, bei Jahren mit 53 Wochen klappt es problemlos.

einfach so klingt der Satz etwas unintelligent, da kann man ruhig weiterdenken 
bei 53 Wochen in einem Jahr ist der Definiton nach eine 53. im Jahr angebrochen,
nach der begrenzten Anzahl Tage im Jahr wird diese 53. garantiert bis ins nächste Jahr laufen,
das 'Problem', dass die erste Woche des nächsten Jahres noch ins alte reinreicht, kann es nicht geben

also sieht die natürliche Situation günstig aus, deshalb kommt Java nicht in Verlegenheit, immer noch das Problem zu haben,
wobei es dann übrigens für den Jahresanfang ungünstig aussieht:
für 01.01.2012, nach einem 53er-Jahr 2011, gibt dein Programm '52.2012' aus, auch nicht günstig

ich erlaube mir dieses halbe Offtopic, weil im Thema auch nicht mehr viel zu sagen ist,
hast du YYYY probiert, oder kein Java 1.7?
wenn du mit Calendar die Zahlen einzeln holen würdest, könntest du ja bisschen rechnen:
'wenn Dezember und Woche < 40, dann wohl Jahr+1'

edit:
ok, das Beispiel 2011 gewählt zu haben ist vor mir nicht grad intelligent, da gab es gar keine 53. Woche,
zumal auch Ausgabe '52.2012', der Rest dürfte aber noch stimmen, 2009 etwa


----------



## TomAdam (13. Nov 2012)

SlaterB hat gesagt.:


> einfach so klingt der Satz etwas unintelligent, da kann man ruhig weiterdenken
> bei 53 Wochen in einem Jahr ist der Definiton nach eine 53. im Jahr angebrochen,
> nach der begrenzten Anzahl Tage im Jahr wird diese 53. garantiert bis ins nächste Jahr laufen,
> das 'Problem', dass die erste Woche des nächsten Jahres noch ins alte reinreicht, kann es nicht geben
> ...



Ja richtig wäre in diesem Fall 52.2011 ansonsten verstehe ich nur Bahnhof. 



SlaterB hat gesagt.:


> ich erlaube mir dieses halbe Offtopic, weil im Thema auch nicht mehr viel zu sagen ist,
> hast du YYYY probiert, oder kein Java 1.7?



Java 7 ist definitiv keine Option, max. steht Java 6 zur Verfügung.



SlaterB hat gesagt.:


> wenn du mit Calendar die Zahlen einzeln holen würdest, könntest du ja bisschen rechnen:
> 'wenn Dezember und Woche < 40, dann wohl Jahr+1'



Äh, Dezember UND Woche < 40 ergibt irgendwie immer false. 
Na ja, da werde ich mir wohl selbst einen workaround einfallen lassen müssen. Ich dachte, das liesse sich einfach mit den vorhandenen Bordmitteln lösen.


Tom


----------



## SlaterB (13. Nov 2012)

> Äh, Dezember UND Woche < 40 ergibt irgendwie immer false. 

31.12.2012 -> Woche 1 und Dezember -> also zum Jahr 2012 +1 -> "01.2013" statt "01.2012", das wolltest du doch


----------



## D4rkscr43m (13. Nov 2012)

```
SimpleDateFormat df = new SimpleDateFormat("ww.Y");
```
 funktioniert bei mir zumindest auch mit eingestelltem Java 1.5.

Sonst würde ich immernoch dazu raten das Calendarobjekt auf das Datum des Donnerstags zu setzen.


----------



## mla.rue (13. Nov 2012)

```
public static void identifyWeekOfYear() {
     int iWoche;
     Calendar cal = Calendar.getInstance();
     cal.set(2012, 11, 31);
	
     iWoche = cal.get(Calendar.WEEK_OF_YEAR);
     System.out.println(iWoche);
}
```

Ausgabe: 1

Wo genau liegt da das Problem? Die 'richtigen' Werkzeuge wählen.


----------



## SlaterB (13. Nov 2012)

die Ausgabe 1 funktioniert auch bei SimpleDateFormat im ersten Post, genauer lesen

fraglich ist das Jahr, gewünscht ist 2013 statt 2012,
gewisse Wege sind aber bereits gezeigt


----------



## D4rkscr43m (13. Nov 2012)

Hättest du dir den Thread durchgelesen würdest du merken, dass das Problem nicht die Woche sondern das Jahr ist.
[EDIT]Ups, zu spät [/EDIT]


----------



## mla.rue (14. Nov 2012)

bzzz ersetzt man 2012 durch 2013 ist die Ausgabe immernoch 1, also immernoch richtig

der letzte Beitrag vom TO wirkte auf mich nicht so, als wäre das Problem erledigt
nur weil hier mehrere Wege "angezeigt" wurden heisst doch nicht, dass ich nicht auch einen Weg vorgeben kann?
Die Wege von Slater und Darkscream wirken auf mich wie Workarounds... wenn dann oder Datum auf Do setzen. Daher meine Aussage "richtige Werkzeuge"... wozu der Umweg über SimpleDateFormat wenns mit Calendar schneller, einfacher und vor allem richtig geht? Ich kann einen Nagel auch mit einem Schuh ein'hämmern', praktikabel ist anders.

Naja meine Meinung :/


----------



## D4rkscr43m (14. Nov 2012)

mla.rue hat gesagt.:


> Ich kann einen Nagel auch mit einem Schuh ein'hämmern', praktikabel ist anders.



Du solltest den Nagel aber schon richtig herum halten, tust du aber nicht.


----------



## SlaterB (14. Nov 2012)

was genau ist denn deine Aussage, deine Meinung?
letztlich kann man immer auf SimpleDateFormat verzichten, jede beliebige Darstellung mit Calendar-Abfragen zusammenbauen,
aber das ist ja wohl nicht logisch, dann gäbe es SimpleDateFormat nicht..

das Ziel ist "01.2003" für 31.12.2012, 
wenn es mit SimpleDateFormat möglich wäre, ab Java 1.7 anscheinend "ww.YYYY",  dann ein idealer sauberer Schritt, 
alles andere mit Calendar.get() oder Datumwechsel vergleichsweise Gefrickel, aber eben nötig

(edit: ui, schon wieder mit D4rkscr43m gleichzeitig  )


----------



## TomAdam (14. Nov 2012)

D4rkscr43m hat gesagt.:


> Sonst würde ich immernoch dazu raten das Calendarobjekt auf das Datum des Donnerstags zu setzen.



Es muss aber mit jedem beliebigen Startdatum richtig funktionieren. Ich habe mir jetzt folgende Lösung erarbeitet. Der Code gibt in einer Schleife die KW für die nächsten 250 Wochen ab einem beliebigen Startdatum heraus.

```
public static void main(String[] args)
	{
		Calendar cal = (GregorianCalendar) Calendar.getInstance(TimeZone.getTimeZone( "Europe/Berlin" ), Locale.GERMANY);         
		SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy"); 
		
		try
        {           
            cal.setTime(df.parse("01.01.2012")); // Hier das Startdatum setzen
        }
        catch (Exception ignore) {}		
		
		// Vergleichskalender für das Vorjahr
        Calendar comp = Calendar.getInstance(Locale.GERMANY);        

        for(int weeks = 0; weeks < 250; weeks++) // Beispiel: nächste 250 Wochen
        {  	
        	comp.set(Calendar.YEAR, (cal.get(Calendar.YEAR) - 1));
        	
        	// Fall 1: Jahr mit 52 Wochen, 1. KW beginnt im Dezember
        	if((cal.get(Calendar.MONTH) == Calendar.DECEMBER && cal.get(Calendar.WEEK_OF_YEAR) == 1) && cal.getActualMaximum(Calendar.WEEK_OF_YEAR) == 52)
        	{
        		System.out.println("(1)Woche/Jahr: " + "01." + (cal.get(Calendar.YEAR) + 1));        		
        	}  
        	else
        	{
        		// Fall 2: Jahr mit 53 Wochen, 1. KW beginnt im Januar
        		if(cal.get(Calendar.MONTH) == Calendar.JANUARY 
        				&& cal.get(Calendar.WEEK_OF_YEAR) == 53 
        			 	&& cal.getActualMaximum(Calendar.WEEK_OF_YEAR) == 52 
        			 	&& comp.getActualMaximum(Calendar.WEEK_OF_YEAR) == 53)
        		{
        			System.out.println("(2)Woche/Jahr: " + "53." + (cal.get(Calendar.YEAR) - 1));
        		}        		
        		else
        		{
        			// Fall 3: Jahr mit 52 Wochen, 52. KW geht in den Januar
        			if(cal.get(Calendar.MONTH) == Calendar.JANUARY 
            				&& cal.get(Calendar.WEEK_OF_YEAR) == 52 
            			 	&& cal.getActualMaximum(Calendar.WEEK_OF_YEAR) == 52
            			 	&& comp.getActualMaximum(Calendar.WEEK_OF_YEAR) == 52)
            		{
        				System.out.println("(3)Woche/Jahr: " + "52." + (cal.get(Calendar.YEAR) - 1)); 
            		}
            		
                	else // Fall 4: Der Normalfall
                	{	                		
                		System.out.println("(4)Woche/Jahr: " + new SimpleDateFormat("ww.yyyy").format(cal.getTime()));            			
                	}
        		}        		
        	}    	
        	cal.add(Calendar.WEEK_OF_YEAR, 1);        	
        }
   }
```

Falls jemandem noch etwas auffällt bin ich für Hinweise dankbar.


Tom


----------



## bone2 (14. Nov 2012)

Du hast einfach einen Denkfehler beim ursprünglichen Jahr
yyyy gibt dir das Jahr des Datums aus, das gerade im Calendar steht. unabhängig davon was du sonst noch wissen willst.

ww gibt dir die woche aus, unabhängig vom jahr. die werte haben keine verbindung.

also funktionierte schon im ursprünglichen code alles, so wie es gedacht ist


wenn die woche < 10 ist und das datum im dezember liegt, einfach das jahr +1 ausgeben

Hinweis: dein code trägt die Kirche ums Dorf, hier eine vernünftige lösung

```
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone( "Europe/Berlin" ), Locale.GERMANY);
        SimpleDateFormat df = new SimpleDateFormat("dd.MM.yyyy");

        try
        {
            cal.setTime(df.parse("01.01.2012")); // Hier das Startdatum setzen
        }
        catch (Exception e) {
            System.out.println(e);
        }

        for(int weeks = 0; weeks < 250; weeks++) // Beispiel: nächste 250 Wochen
        {
            int week = cal.get(Calendar.WEEK_OF_YEAR);
            int year = cal.get(Calendar.YEAR);
            int month = cal.get(Calendar.MONTH);

            year +=  month == Calendar.JANUARY && week > 50 ? -1 : month == Calendar.DECEMBER && week == 1 ? 1 : 0;
            System.out.println(String.format("Woche/Jahr: %02d.%d", Integer.valueOf(week),Integer.valueOf(year)));

            cal.add(Calendar.WEEK_OF_YEAR, 1);
        }
```


----------



## D4rkscr43m (14. Nov 2012)

SlaterB hat gesagt.:


> das Ziel ist "01.2003" für 31.12.2012,
> wenn es mit SimpleDateFormat möglich wäre, ab Java 1.7 anscheinend "ww.YYYY",  dann ein idealer sauberer Schritt



Und ich meine, dass ein einzelnes "Y" schon reicht und auch schon vor Java 1.7 funktioniert.

compilr bestätigt mich darin auch.

```
java.util.Calendar c = new java.util.GregorianCalendar(2012, 11, 31);
java.text.SimpleDateFormat s = new java.text.SimpleDateFormat("w.Y");
System.out.println(s.format(c.getTime()));
```
führt auch da zur Ausgabe von 
	
	
	
	





```
1.2013
```


----------



## TomAdam (14. Nov 2012)

D4rkscr43m hat gesagt.:


> Und ich meine, dass ein einzelnes "Y" schon reicht und auch schon vor Java 1.7 funktioniert.



Nein, funktioniert nicht in Java 1.5 und 6



> Exception in thread "main" java.lang.IllegalArgumentException: Illegal pattern character 'Y'
> at java.text.SimpleDateFormat.compile(Unknown Source)
> ...




Tom


----------



## D4rkscr43m (14. Nov 2012)

Dann trotzdem danke für das Feedback


----------



## TomAdam (14. Nov 2012)

bone2 hat gesagt.:


> Hinweis: dein code trägt die Kirche ums Dorf, hier eine vernünftige lösung



Danke, da habe ich wohl etwas zu umständlich gedacht, das ist natürlich viel schlanker. Das Java soetwas nicht von sich aus hingekommt...


Tom


----------



## bone2 (14. Nov 2012)

Der SimpleDateFormat bietet ja wirklich schon an was der TE will... interessant
edit: oh das ist neu
java 6 SimpleDateFormat (Java Platform SE 6)

das arbeiten mit dates is bisher völlig an mir vorbei gegangen


----------



## snoboy (4. Jan 2013)

Hallo zusammen

Auf der Suche nach einer Lösung für mein Problem, bin ich auf diesen Thread gestossen.

Aus einer Datenbank bekomme ich Jahr und Woche (yyyyww).
Mit dem folgenden Code wird dieser Wert umformatiert:

**********Code aus einem Birt Report**********
dfParser = new Packages.java.text.SimpleDateFormat("yyyyww");
df = new Packages.java.text.SimpleDateFormat("ww-yyyy");
myDate = dfParser.parse(row["val_num"]);
formattedDate = df.format(myDate);
****************************************

Das Ergebnis seht Ihr unten. Irgendwie hängen Woche und Jahr schon zusammen.
Ich verwende auch Java 1.6.

val_num   formattedWeek
201247    47-2012
201248    48-2012
201249    49-2012
201250    50-2012
201251    51-2012
201252    52-2012
201301    01-2012

Es hat den Anschein, ob das Jahr in der KW 53/2012 ist, die Woche jedoch schon in KW 01/2013.

Hat jemand eine Erklärung? Ev. Bug im SimpleDateFormat?

Danke und Gruss
Piero


----------



## SlaterB (4. Jan 2013)

dein Programm ist unnötig kompliziert mit Erwähnung der Datenbank + Birt und unnötig unvollständig,
wahrscheinlich meinst du folgendes 100% klares, von jedermann ausführbares vollständiges Programm:

```
public class Test2
{
    public static void main(String[] args) throws Exception
    {
        String st = "201301";
        SimpleDateFormat dfParser = new SimpleDateFormat("yyyyww");
        SimpleDateFormat df = new SimpleDateFormat("ww-yyyy");
        Date myDate = dfParser.parse(st);
        System.out.println(myDate);
        System.out.println(df.format(myDate));
    }
}
```
Ausgabe:

```
Mon Dec 31 00:00:00 CET 2012
01-2012
```

das entspricht weitgehend den vorherigen Problemen, es ist eindeutig ein Datum aus dem Jahr 2012, aber Kalenderwoche 1 aus dem nächsten Jahr,
das Jahr 2012 HAT nunmal keine 53 Wochen
Alle Kalenderwochen 2012, kw kalender 2012 - kalenderwoche.net

würde man '01-2012' wieder parsen, käme man an den Anfang des Jahres 2012, weil nicht erkennbar ist dass die Kalenderwoche des nächsten Jahres gemeint ist,
das ist sicherlich nicht schön, aber was sollte die Alternative sein?
das SimpleDateFormat kann für den Montag der 1. Woche 2013, Silverster vor 4 Tagen, 31.12.2012, doch nicht das Jahr 2013 behaupten, eindeutig ist 2012 richtig,

vielleicht wäre eine generelle Erweiterung nötig, 'gib Kalenderwoche + Kalenderwoche-Jahr' = 01-2013


----------



## snoboy (11. Jan 2013)

Hallo SlaterB

Wollte mich noch bedanken. Sorry, wenn ich etwas zu wenig präzis war.

Mit Java 1.7 bietet das SimpleDateFormat das Symbol "Y". Hier passen dann Woche und Jahr zusammen.
Übrigens bietet auch ein Package von der IBM diese Möglichkeit (Packages.com.ibm.icu.text).

Viele Grüsse
Piero


----------



## SlaterB (11. Jan 2013)

ach ja, das große Y, kürzlich auch schonmal gelesen und vorgeschlagen
(spätes edit: war ja in diesem Thema, auf Seite 1..)


----------

