Entwickler-Ecke

C# - Die Sprache - Jahrestage


ThomAlex - Do 22.04.10 20:36
Titel: Jahrestage
Hallo,

ich habe ein kleines Programm geschrieben, dass die Eingabe von Jahr, Monat und Tag mit einem Algorithmus verarbeitet, der mir ausspuckt, welcher Tag im Jahr das ist. Miteinbezogen sind Schaltjahre, diese haben 366 Tage und um die grogorianische Schaltregel mal einfachheitshalber außen vor zu lassen, ist jedes vierte Jahr ein Schaltjahr (also das Jahr geteilt durch 4 darf keinen Rest aufweisen). Es klappt, nur ich möchte versuchen den Code von der Menge soweit zu kürzen, wie es nur geht, habt ihr Ideen, wie ich den verkürzen kann? Hier der Code:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
int result, userday, usermonth, useryear;
int[] monthdays = new int[12];

private void button1_Click(object sender, EventArgs e)
{
       userday = 0;
       usermonth = 0;
       useryear = 0;

       //Day
       if (int.Parse(txtDays.Text) > 0 && int.Parse(txtDays.Text) <= 31)
            userday = int.Parse(txtDays.Text);
       else
       {
            MessageBox.Show("Ungültige Eingabe für den Tag!");
            txtDays.Text = "";
            return;
       }

       //Month
            
       if (int.Parse(txtMonth.Text) <= 12 && int.Parse(txtMonth.Text) >= 1)
            usermonth = int.Parse(txtMonth.Text);
       else
       {
            MessageBox.Show("Ungültige Eingabe für den Monat!");
            txtMonth.Text = "";
            return;
       }
       //Year
            
       try { useryear = int.Parse(txtYear.Text); }
       catch
       {
            MessageBox.Show("Ungültige Eingabe!");
            txtYear.Text = "";
            return;
       }

       result = 0;

       for (int i = 0; i < 12; i++)
       {
            if (i == 0 || i == 2 || i == 4 || i == 6 || i == 7 || i == 9 || i == 11)
                monthdays[i] = 31;
            else if (i == 1 && useryear % 4 == 0)
                monthdays[i] = 29;
            else if (i == 1 && useryear % 4 != 0)
                monthdays[i] = 28;
            else
                monthdays[i] = 30;
        }
        for (int i = 0; i < usermonth - 1; i++)
            result += monthdays[i];
        result += userday;

        lblAusgabe.Text = result + ". Tag im Jahr " + useryear;
        lblAusgabe.Visible = true;
}

Danke fürs Gedanken machen


Moderiert von user profile iconKha: Topic aus WinForms verschoben am Do 22.04.2010 um 21:20


Ralf Jansen - Do 22.04.10 20:55

Laß das ganze doch das Framework selber rechnen. Ist kompakter und das Schaltjahr Handling ist auch geschenkt.


C#-Quelltext
1:
result = new DateTime(useryear, usermonth, userday).Subtract(new DateTime(useryear - 11231)).Days;                    


JüTho - Do 22.04.10 21:03

Ich empfehle DayOfYear. Jürgen


ThomAlex - Do 22.04.10 21:17

Ja danke für die Methoden, allerdings gehts mir um eine Optimierung meines Codes. Sinn der Sache ist nicht fertigen Code zu benutzen, sondern ihn selber in Kurzform zu programmieren. Kann jemand meinen Code kürzen? Danke


Kha - Do 22.04.10 21:30

user profile iconThomAlex hat folgendes geschrieben Zum zitierten Posting springen:
Es klappt, nur ich möchte versuchen den Code von der Menge soweit zu kürzen, wie es nur geht, habt ihr Ideen, wie ich den verkürzen kann?
Der Code ist von der Logik schon ziemlich direkt, da lässt sich wenig rütteln. Aber zwei Anmerkungen: Warum sind die Variablen außerhalb der Methode deklariert? Die meisten 0 Initialisierungen kannst du dir auch sparen. Und wozu erst monthdays füllen und dann direkt zusammenrechnen? Die zwei Schritte könntest du gleichzeitig ausführen und dir so das Array sparen. Oder du ersetzt die Schleife durch Folgendes, imo ein wenig hübscher:

C#-Quelltext
1:
int[] monthDays = { 31, userYear % 4 == 0 ? 29 : 283130, ... };                    

Und wenn du LINQ magst, kannst du dann mit

C#-Quelltext
1:
int result = monthDays.Take(userMonth - 1).Sum() + userDay;                    

weitermachen.

/edit: Und noch eine Idee: Das Einlesen der drei Datumsteile in eine Methode bool Validate(TextBox box, string name, int min, int max, out int value) auslagern.


Ralf Jansen - Do 22.04.10 21:32

Zitat:
Sinn der Sache ist nicht fertigen Code zu benutzen, sondern ihn selber in Kurzform zu programmieren. Kann jemand meinen Code kürzen


Der Ausspruch ist jetzt aber reichlich Paradox :gruebel:


danielf - Do 22.04.10 21:35

Okay, dann mache ich mich mal an den Code :)

Zu aller erst könntest du ein NumericUpDown verwenden für die Datum eingabe. Dann brauchst du das Parsen nicht.
Oder eine MaskedTextBoxed, dann kannst du ungültige Eingaben abfangen.

Wenn es aber eine Textbox sein "muss" dann denke ich, dass dir TryParse weiter hilft:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
private void button1_Click(object sender, EventArgs e)
{
   int userday, usermonth, useryear;

   if (!int.TryParse(textDays.Text, out userday) || userday > 31 || userday < 0)
   {
       throw new Exception("Ungültige Tag eingabe");
   }
   if (!int.TryParse(textMonth.Text, out usermonth) || usermonth > 12 || usermonth < 1)
   {
       throw new Exception("Ungültige Monat eingabe");
   }
   if (!int.TryParse(textYear.Text, out useryear))
   {
       throw new Exception("Ungültige Jahr eingabe");
   }

   int[] monthdays = new int[12];
   int sumOfDays;
   for (int i = 0; i < 12; i++)
   {
      switch(i)
      {
         case 0:
         case 2:
         case 4:
         case 6:
         case 7:
         case 9:      
         case 11:
            monthdays[i]= 31;
            break;
         case 1:
            monthdays[i]= useryear % 4 ? 28 : 29;
            break;
         default:
            monthdays[i]= 30;
      }
      sumOfDays += monthdays[i];
   }
   
   lblAusgabe.Text = string.Format("Das Jahr {0} hat {1} Tage.", useryear, sumOfDays);
}


Ich denke das ist selbsterklärend :)

Wenn du fragen hast .. schieß los

Gruß


ThomAlex - Fr 23.04.10 00:07

Vielen Dank, aus allem hab ich etwas genommen.


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
private void button1_Click(object sender, EventArgs e)
{
       //Lesen
       int userday, usermonth, useryear;
       if (!InitializeData(out userday, out usermonth, out useryear))
           return;

       //Verarbeiten
       int[] monthdays = { 31, useryear % 4 == 0 ? 28 : 2931303130313130313031 };
       int sumOfDays = 0;
       for (int i = 0; i < usermonth - 1; i++)
           sumOfDays += monthdays[i];
       sumOfDays += userday;

       //Schreiben
       lblAusgabe.Text = "Der " + userday.ToString() + "." + usermonth.ToString() + " ist der " + sumOfDays.ToString() + ". Tag im Jahr " + useryear.ToString();
       lblAusgabe.Visible = true;
}
private bool InitializeData(out int userday, out int usermonth, out int useryear)
{
       bool Converted = true;
       if (!int.TryParse(txtDays.Text, out userday) || userday < 1 || userday > 31)
       {
           MessageBox.Show("Ungültiger Tag!");
           txtDays.Text = "";
           Converted = false;
       }
       if (!int.TryParse(txtMonth.Text, out usermonth) || usermonth < 1 || usermonth > 12)
       {
           MessageBox.Show("Ungültiger Monat!");
           txtMonth.Text = "";
           Converted = false;
       }
       if (!int.TryParse(txtYear.Text, out useryear))
       {
           MessageBox.Show("Ungültiges Jahr!");
           txtYear.Text = "";
           Converted = false;
       }
       if (!Converted)
           lblAusgabe.Text = "";
       return Converted;
}


Nemag - Fr 23.04.10 07:35

Servus

zum Code an sich will ich jetzt mal nichts sagen, nur zur Schaltjahrberechnung (hab mir jetzt nicht alles durch gelesen - vielleicht hat es ja auch schon jemand geschrieben)

Schaltjahre sind alle Jahre die restlos durch 4 geteilt werden können ohne die, die durch 100 teilbar aber nicht durch 400 teilbar sind.

quasi 1900 war keins, 2000 war eins und 2100 wird wieder keins.

aber das nur am Rande.


ThomAlex - Mo 26.04.10 18:51

@Nemag:
Zitat:

Schaltjahre sind alle Jahre die restlos durch 4 geteilt werden können ohne die, die durch 100 teilbar aber nicht durch 400 teilbar sind.


C#-Quelltext
1:
int[] monthdays = { 31, useryear % 4 == 0 ? 28 : 2931303130313130313031 };                    

Im zweiten Element, dem Februar, ist deine Anmerkung längst erfüllt worden.


JüTho - Mo 26.04.10 19:29

user profile iconThomAlex hat folgendes geschrieben Zum zitierten Posting springen:

C#-Quelltext
1:
int[] monthdays = { 31, useryear % 4 == 0 ? 28 : 2931303130313130313031 };                    

Im zweiten Element, dem Februar, ist deine Anmerkung längst erfüllt worden.

Wie bitte?
* Bei useryear = 1900 ist mod4 gleich 0, dann also 28 Tage. Korrekt.
* Bei useryear = 1901 ist mod4 gleich 1, dann also 29 Tage. Falsch.
* Bei useryear = 1902 ist mod4 gleich 2, dann also 29 Tage. Falsch.
* Bei useryear = 1903 ist mod4 gleich 3, dann also 29 Tage. Falsch.
* Bei useryear = 1904 ist mod4 gleich 0, dann also 28 Tage. Falsch.

Du müsstest also zumindest 28 und 29 vertauschen. Aber auch dann fehlen die Bedingungen mod 100 und mod 400.

Jürgen


ThomAlex - Mi 28.04.10 22:37

Wenn mans genau nimmt schon, aber die Gregorianische Regel gilt nur bis 1582 und diese wollte ich weglassen und simpel einfach die julianische Regel, die nur besagt Ein Jahr ist ein Schaltjahr, wenn die Division durch 4 keinen Rest ergibt, weiter nichts, nehmen.


Nemag - Do 29.04.10 09:47

user profile iconThomAlex hat folgendes geschrieben Zum zitierten Posting springen:
Wenn mans genau nimmt schon, aber die Gregorianische Regel gilt nur bis 1582 und diese wollte ich weglassen und simpel einfach die julianische Regel, die nur besagt Ein Jahr ist ein Schaltjahr, wenn die Division durch 4 keinen Rest ergibt, weiter nichts, nehmen.


Also wenn man es schon genau nimmt gilt die Gregorianische Regel ab 1582 und nicht bis. Übrigens gibt es dafür diverse Normen ISO 8601 (die deutsche dazu weiß ich spontan nicht und war jetzt zu faul zu googln).

Ich hoffe du hast den von Jürgen beschriebenen Fehler beim Zuweisungoperator wenigstens getauscht ;-)


JüTho - Do 29.04.10 17:18

user profile iconNemag hat folgendes geschrieben Zum zitierten Posting springen:
Normen ISO 8601 (die deutsche dazu weiß ich spontan nicht

Ganz einfach: EN 28601 (und europäische Normen sind auch deutsche Normen). Jürgen