Uhrzeit richtig verwenden



  • Hallo liebe Community,

    zuerst natürlich an alle ein gutes neues Jahr 2016 :).

    Ich weiß nicht ob ich hier richtig bin, jedoch treibt mich die Verzweiflung in den Wahnsinn, obwohl ich bereits 30-40 Artikel über die DateTime gelesen habe bekomme ich eine Zeitberechnung nicht hin.

    Mein Problem:

    Ich habe insgesamt 4 Comboboxen:

    cb_beginn_stunde
    cb_beginn_minute
    cb_ende_stunde
    cb_ende_minute

    So soll man also eine Startuhrzeit sowie eine Enduhrzeit auswählen können um die Differenz zu berechnen (Arbeitszeitberechnung).

    1. Schritt war einen kompletten String von beginn und ende zu machen

    string beginn = cb_beginn_stunde.Text + ":" + cb_ende_minute.Text;
    string ende = cb_ende_stunde.Text + ":" + cb_ende_minute.Text;
    

    Problem : wie bekomme ich meine Strings nun in die DateTime Klasse sodass ich lediglich die Uhrzeit (ohne Datum) habe um mit .Ticks (was in der MSDN wieder mit long steht) zu arbeiten. Ich weiß nicht, vlt habe ich einen völlig falschen Ansatz jedoch bin ich noch ein sehr blutiger Anfänger.

    Ich bitte daher um Vorschläge wie man das Problem bewerkstelligen kann.

    Danke euch 🙂



  • Es gibt einen DateTime Konstruktor, der Jahr, Monat usw. (was dich nicht interessiert) und Stunde, Minute, Sekunde als int bekommt. Musst also den Text in einen Integer konvertieren (Int32.Parse, Convert.ToInt32 oder wie auch immer) und den richtigen Konstruktor aufrufen. Bei Jahr, Monat usw. übergibst du die aktuellen Werte.



  • Danke, für die schnelle Hilfe :).

    leider gibt er mir noch immer eine Exeption raus :(.

    So sieht nun mein Code aus:

    DateTime anfang = new DateTime(1, 1, 2001, Convert.ToInt32(cb_beginn_stunde.Text), Convert.ToInt32(cb_beginn_minute.Text), 0);
                DateTime ende = new DateTime(1, 1, 2001, Convert.ToInt32(cb_ende_stunde.Text), Convert.ToInt32(cb_ende_minute.Text), 0);
    
                TimeSpan  ergebnis = anfang - ende;
                Console.WriteLine("Ergebnis: {0:hh\\:mm}",ergebnis );
    

    Ich befürchte auch, wenn ich sagen wir mal um 22:00 zum Arbeiten anfange und um 3:00 Feierabend habe Probleme mit den Dummywerten bekomme (nur ne Vermutung).



  • Muss ich jetzt wirklich nachfragen, welche Exception und an welcher Stelle?



  • also in meinem Code meckert er bei Zeile 40, das ist die deffinition von DateTime.

    Um ehrlich zu sein habe ich seit gestern immer den gleichen Absturz, außer wenn ich die oberen CodeZeilen auskommentiere :(.

    System.FormatException: Input string was not in a correct format.
    at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
    at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
    at System.Convert.ToInt32(String value)
    at Hopfengarten.frm_haupt.cmd_speichern_Click(Object sender, EventArgs e) in C:\Users\master\Documents\Hopfengarten\Hopfengarten\Hopfengarten\Form1.cs:line 40

    edit:

    quasi so ist alles ok (liegt also an der Zeitberechnung)

    //DateTime anfang = new DateTime(1, 1, 2001, Convert.ToInt32(cb_beginn_stunde.Text), Convert.ToInt32(cb_beginn_minute.Text), 0);
                //DateTime ende = new DateTime(1, 1, 2001, Convert.ToInt32(cb_ende_stunde.Text), Convert.ToInt32(cb_ende_minute.Text), 0);
    
                //TimeSpan ergebnis = anfang - ende;
                //Console.WriteLine("Ergebnis: {0:hh\\:mm}", ergebnis);
    


  • System.FormatException: Input string was not in a correct format.

    Und was heißt das wohl? Musst halt genau schauen, was du genau konvertierst, ob das auch eine gültige Zahl ist (auch auf Leerzeichen usw. achten).



  • Mechanics schrieb:

    System.FormatException: Input string was not in a correct format.

    Und was heißt das wohl? Musst halt genau schauen, was du genau konvertierst, ob das auch eine gültige Zahl ist (auch auf Leerzeichen usw. achten).

    Oh Mann! Ja, ich hatte in meiner cb_beginn_minute ein Leerzeichen mit drinnen.
    Sorry, nun geht es ^^. Vielen vielen Dank, ich will nicht wissen wieviel Varianten davor schon funktioniert hätten ohne den Fehler 🙄

    edit//
    für vlt andere Hilfesuchenden:

    natürlich habe ich auch noch mein Datum umdrehen müssen sprich in:

    DateTime anfang = new DateTime(2001,01,01, Convert.ToInt32(cb_beginn_stunde.Text), Convert.ToInt32(cb_beginn_minute.Text), 0);
    DateTime ende = new DateTime(2001,01,01, Convert.ToInt32(cb_ende_stunde.Text), Convert.ToInt32(cb_ende_minute.Text), 0);
    


  • Wie ich mir vorhin in punkto 22:00 Uhr Arbeitsbeginn und 3:00 Uhr Feierabend schon dachte, habe ich folgende Lösung, welche 1A funktioniert. Allerdings wollte ich nun fragen ob es keine schönere Variante gibt bzw. wie Ihr Profis das macht ;).

    Wenn wir nun mal von einer Variablen Arbeitszeit ausgehen (z.B. nach 4h 15 min Pause und nach 6h 30 min)welche gleich abgezogen werden, ist das ein wenig umständlich.Vor allem wenn wir dann noch das Jugendrecht mit einbeziehen wollen.

    Ich meine die Uhrzeitberechnung kommt doch sicherlich oft vor und da haben sich schlauen Füchse bestimmt was einfallen lassen 😉

    //prüft ob anfangsStunde größer als endStunde
    Int32 anfangsStunde = Convert.ToInt32(cb_beginn_stunde.Text);
    Int32 endStunde = Convert.ToInt32(cb_ende_stunde.Text);
    int dummyTag = 1;
    
        if (anfangsStunde > endStunde)
        {
            dummyTag = 2;
        }
        else
        {
            dummyTag = 1;
        }
    
    DateTime anfang = new DateTime(2001, 01, 01 , Convert.ToInt32(cb_beginn_stunde.Text), Convert.ToInt32(cb_beginn_minute.Text), 0);
    DateTime ende = new DateTime(2001, 01, dummyTag , Convert.ToInt32(cb_ende_stunde.Text), Convert.ToInt32(cb_ende_minute.Text), 0);
    TimeSpan ergebnis = anfang - ende;
    MessageBox.Show(ergebnis.ToString("hh\\:mm"));
    

    Danke für Info´s bzw. Aufklärung



  • Ich seh jetzt den Zusammenhang zwischen AnfangsStunde > EndStunde und den Pausen und dem Jugendrecht nicht. Was willst du mit den Pausen usw. konkret berechnen?
    Und wo sollen die Pausen automatisch abgezogen werden? Geht es dir eben genau darum, dass du unter Einbeziehung bestimmter Regeln einen ausgerechneten "TimeSpan" zurückbekommst, der die reine Arbeitsdauer angibt?

    Also, erst einmal muss man dafür Logik und GUI besser trennen. In der Berechnung haben irgendwelche ComboBoxen nichts mehr zu suchen. Die Funktion zum Berechnen der Arbeitsdauer sollte fertig konstruierte DateTime Objekte bekommen. Das mit dem Dummy Tag finde ich soweit ok (aber nein, eigentlich kommen Uhrzeitberechnungen nicht so oft vor, kann mich nicht dran erinnern, sowas schon mal gemacht zu haben), ob man das in der eigentlichen Berechnung oder davor macht, kann man sich noch überlegen.

    Wie weit man das mit den Regeln treibt, ist Geschmackssache. Die Beispiele, die du genannt hast, kann man hartkodiert implementieren. Wenn man die Fälle genau kennt und weiß, dass die sich nicht so oft ändern. Oder man macht es konfigurierbar. Das andere Extrem wären "Business Rules Engines". Damit definiert man die Business Regeln extern, konfigurierbar, damit ein Endkunde das auch anpassen kann. Für einen konkreten Fall kann man das natürlich auch selber konfigurierbar machen, hab ich vorhin auch geschrieben, aber Rules Engines sind allgemeiner und für alles mögliche verwendbar.



  • @ Mechanics

    Erstmal vielen vielen Dank für deine Hilfsbereitschaft 👍

    Da ich gerade eine Umschulung zum Anwendungsentwickler mache (seit 5 Wochen Programmiere) und ein Projekt zum Lernen suchte habe ich meiner Chefin (Nebenjob als Kellner)versprochen ein Programm zu schreiben, was Ihr die Arbeit bei der Stundenberechnung abnimmt, denn vor meiner Zeit hat sie alles per Hand mit nem Taschenrechner ausgerechnet und es dann in Excel eingetippt 😃 .

    Nun soll also mein erstes Programm wo wirklich eingesetzt wird her 🙂

    Das Programm soll also die Arbeitszeit und den Lohn berechnen. Bei der Arbeitszeit ist zu berücksichtigen, ob der Mitarbeiter gegessen hat (wenn ja, zieht Sie 15 min) Arbeitszeit ab. Danach ist zu berücksichtigen wie lange man gearbeitet hat, da das Arbeitsrecht bei einer Arbeitszeit von 4 Stunden eine Pause von 15 Minuten und bei einer Arbeitszeit von 6 Stunden 30 Minuten vorsieht. Bei einem Jugendlichen (haben wir öfter mal) sieht das Gesetz nach 4 Stunden eine Pausezeit von 30 Minuten und nach 6 Stunden von 45 Minuten vor.

    Dank deiner Hilfe weiß ich ja nun wie ich mit Uhrzeiten rechnen kann und bekomme sicherlich auch eine Lösung hin (wobei es wahrscheinlich eher Vergewaltigung an C# wird 🙄 ). Mein Problem liegt derzeit noch vielmehr darin die Programmierung zu verstehen z.B. wie handhabe ich meine Funktionen was sollte man nicht machen und natürlich was gibt es eigentlich alles für Möglichkeiten (Programmieren nach 5 Wochen halt 😉 ).

    Ich werde dir morgen mal meine Lösung posten auch wenn du danach wahrscheinlich Augenkrebs hast 🙄 . Im Moment ist es für mich einfach nur wichtig verschiedene Dinge kennen zu lernen und mich damit zu befassen :).



  • samkirchner schrieb:

    bekomme sicherlich auch eine Lösung hin (wobei es wahrscheinlich eher Vergewaltigung an C# wird 🙄 ). Mein Problem liegt derzeit noch vielmehr darin die Programmierung zu verstehen z.B. wie handhabe ich meine Funktionen was sollte man nicht machen und natürlich was gibt es eigentlich alles für Möglichkeiten

    Das wird wahrscheinlich auch später eine zentrale Frage. So genau weiß das (ist natürlich etwas übertrieben) im Endeffekt auch keiner, und je nachdem, womit man sich gerade beschäftigt, können völlig unterschiedliche Lösungen rauskommen. Man kann solche Regelsysteme wie gesagt beliebig konkret oder abstrakt machen, und beides könnte man als Vergewaltigung ansehen 😉 Hat man ganz klare, überschaubare Anforderungen (wie in deinem Fall) und setzt ein kompliziertes dynamisches Framework ein, werden viele wahrscheinlich schreien, dass es viel zu kompliziert ist und keiner mehr was versteht. Aber wenn du jetzt etwas komplexere Anforderungen hast, sagen wir mal, auch so eine Lohnabrechnung für einen internationalen Konzern, der alles mögliche berücksichtigen muss, z.B. Regelungen in zig verschiedenen Ländern, schwarz bezahlte Söldner, Kinderarbeit usw., dann bietet sich wahrscheinlich eher ein kompliziertes, aber flexibles System an.



  • Warum arbeitest in den ComboBoxes umständlich mit strings? Die Stunden (0..23) und Minuten (0..59)
    können mit den Indizes gleichgesetzt werden, was die Sache sehr vereinfacht.
    Die Umwandlungen (in string) sind dann nur noch für die Ausgaben erforderlich.

    public partial class Form1 : Form
        {
            DateTime dt1, dt2;
            int      year, month, day, hour, minute;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                // Werte der comboBoxes = Indizes
                for(int i = 0; i < 24; i++)
                {
                    comboBox1.Items.Add(i);
                    comboBox3.Items.Add(i);
                }
                for (int i = 0; i < 60; i++)
                {
                    comboBox2.Items.Add(i);
                    comboBox4.Items.Add(i);
                }
                comboBox1.Text = comboBox1.Items[0].ToString();
                comboBox2.Text = comboBox1.Items[0].ToString();
                comboBox3.Text = comboBox1.Items[0].ToString();
                comboBox4.Text = comboBox1.Items[0].ToString();
                // Datum = heute 
                year   = DateTime.Now.Year;
                month  = DateTime.Now.Month;
                day    = DateTime.Now.Day;
                button1.Text = "Calc";
                label1.Text = "";
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                int cb1 = comboBox1.SelectedIndex;
                int cb2 = comboBox2.SelectedIndex;
                int cb3 = comboBox3.SelectedIndex;
                int cb4 = comboBox4.SelectedIndex;
                dt1 = new DateTime(year, month, day, cb1, cb2, 0, 0);
                dt2 = new DateTime(year, month, day, cb3, cb4, 0, 0);
                TimeSpan ts = dt2 - dt1;
                label1.Text = ts.Hours.ToString() + ":" + ts.Minutes.ToString();
             }
        }
    

    Dein gesamter Ansatz erscheint mir "Von hinten in das Knie geschossen" 😋



  • @berniebutt

    Wow nice der Ansatz :).

    Um ehrlich zu sein, habe ich die Items in den Einstellungen manuell eingegeben 😃 .

    Da sind wir mal wieder an dem Punkt das ich deine Version die Checkboxen per Code zu füllen noch net kannte :(. Ich glaube ich werde alles wieder umwurschteln, denn mein Code, welcher nun alles bis auf das Jugendrecht berücksichtigt schaut nun so aus :

    public void Zeitberechnung(Int32 beginn_Stunde, Int32 beginn_Minute, Int32 ende_Stunde, Int32 ende_Minute)
            {
                Int32[] alleZeiten = new Int32[] {beginn_Stunde , beginn_Minute , ende_Stunde , ende_Minute }; 
                try
                {
                    #region prüft ob AnfangsStunde größer Endstunde 
                    int dummyTag = 1;
                    TimeSpan ergebnis = new TimeSpan();
    
                    if (alleZeiten[0] > alleZeiten[1])
                    {
                        dummyTag = 2;
                    }
                    else
                    {
                        dummyTag = 1;
                    }
                    #endregion
                    DateTime anfang = new DateTime(2001, 01, 01, alleZeiten[0], alleZeiten[1], 0);
                    DateTime ende = new DateTime(2001, 01, dummyTag, alleZeiten[2], alleZeiten[3], 0);
                    ergebnis = anfang - ende;
    
                    #region pausezeiten
                    string abzugprüfen = ergebnis.ToString("hh");
                    if (int.Parse(abzugprüfen)>= 6)
                    { 
                       Zeitabzug (30,alleZeiten);
                       DateTime über_6Stunden = new DateTime(2001,01,dummyTag, alleZeiten[2],alleZeiten [3],0 );
                       ergebnis = anfang - über_6Stunden; 
                    }
                    else if (int.Parse(abzugprüfen) >= 4)
                    {
                        Zeitabzug(15, alleZeiten);
                        DateTime über_4Stunden = new DateTime(2001, 01, dummyTag, alleZeiten[2], alleZeiten[3], 0);
                        ergebnis = anfang - über_4Stunden;
                    }
    
                    #endregion
    
                    #region prüft ob gegessen
                    if (check_gegessen.Checked)
                    {
                        Zeitabzug(15, alleZeiten);
    
                        DateTime mit_essen = new DateTime(2001, 01, dummyTag, alleZeiten[2], alleZeiten[3], 0);
                        ergebnis = anfang - mit_essen;
                    }
                    #endregion
    
                    lbl_arbeitszeit_kontrolle.Text = ergebnis.ToString("hh\\:mm");
                }
                catch
                { 
    
                }
            }
    
            public Int32[] Zeitabzug(Int32 abzug, Int32[] alleZeiten)
            {
    
                if (alleZeiten[3] < abzug)
                {
                    abzug = System.Math.Abs(alleZeiten[3] - abzug);
                    alleZeiten[2] -= 1;
                    alleZeiten[3] = 60 - abzug;
                    MessageBox.Show("Neue Endzeit: " + alleZeiten[2].ToString() + ":" + alleZeiten[3].ToString());
                }
                else
                {
                    alleZeiten[3] -= abzug;
                    MessageBox.Show("Neue Endzeit: " + alleZeiten[2].ToString() + ":" + alleZeiten[3].ToString());
                }
                return  alleZeiten;
            }
    

    Lustig ist, dass durch deinen Vorschlag ein Eingabefehler weniger entstehen kann, welcher bei mir mit dem Methodenaufruf

    Zeitberechnung(Convert.ToInt32(cb_beginn_stunde.Text),
                               Convert.ToInt32(cb_beginn_minute.Text),
                               Convert.ToInt32(cb_ende_stunde.Text),
                               Convert.ToInt32(cb_ende_minute.Text));
    

    noch existiert, da meine cb zu Beginn noch "Stunde wählen" stehen hat (daher auch das try/catch). Wie man hier sehen kann, wandel ich permanent um.

    Danke für diese tolle Lösung, werde ich gleich in meinen lernordner stecken 🙂
    👍 👍 👍



  • Du solltest vor allem darauf achten, die Berechnungen von der GUI zu trennen. Ist bei den paar Zeilen Code ist noch nicht so wichtig, aber man sollte möglichst früh damit anfangen. Also die eigentliche Funktion zum Berechnen darf nicht auf irgendwelche GUI Controls wie ComboBox oder Checkbox zugreifen, die muss alles was sie braucht als Parameter reinbekommen. Dann könntest du später z.B. eine Weboberfläche drüberklatschen und müsstest an der Berechnungsfunktion überhaupt nichts ändern, nur am Frontend.

    Und gleich mal die Anmerkung, möglichst keine deutschen Bezeichner zu verwenden. Es gibt paar Leute, die es nicht stört, aber die allermeisten verwenden immer englische Bezeichner.


Log in to reply