Entwickler-Ecke

Basistechnologien - Arbeitszeiten zusammenaddieren


lapadula - Fr 29.06.18 15:47
Titel: Arbeitszeiten zusammenaddieren
Hallo, ich bräuchte einen Schubs in die richtige Richtung bei dem folgenden Problem.

Ich habe eine Liste mit Objekten. Das Object hat unter anderem die Eigenschaft vom Datentyp DateTime und eine Eigenschaft mit dem Datentyp Integer.

Es handelt sich dabei um alle Zeitstempel eines Mitarbeiters.

So sieht die Tabelle aus:

01.01.2018 08:00 - 0 Eingestempelt
01.01.2018 12:00 - 1 Ausgestempelt
01.01.2018 12:30 - 0
01.01.2018 17:00 - 1

02.01.2018 08:00 - 0
02.01.2018 12:30 - 1
02.01.2018 13:00 - 0
02.01.2018 17:00 - 1

Diese ganzen Zeiten habe ich wie gesagt in ner List und möchte nun ausrechnen wie viel Minuten insgesamt gearbeitet wurde.
Bei der oberen Tabelle wären es 4 Std + 4 Std 30 Min = 7,5 Std. (von 8 - 12, 30 Min Pause, von 12:30 bis 17 Uhr).

Dann kommen die Stempel vom 02.01. dazu usw.

Ich verstricke mich gerade hier mit Schleifen und Hilfslisten, wo mich mich frage ob das eleganter geht.


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:
 List<Stempel> listeEingestempelt = new List<Stempel>();
            List<Stempel> listAusgestempelt = new List<Stempel>();

            foreach (Stempel stempel in listAlleStempelVomBenutzer)
            {
                if (timeMotoStempel.INOUT == 0 || timeMotoStempel.INOUT == 1)
                {
                    if (stempel.INOUT == 0)
                    {
                        listeEingestempelt.Add(stempel);
                    }
                    else if (stempel.INOUT == 1)
                    {
                        listAusgestempelt.Add(stempel);
                    }
                }
            }

var GesamtMinuten = 0;
            var counter = 0;
            foreach (Stempel eingestempelt in listeEingestempelt)
            {
                TimeSpan span = listAusgestempelt[counter].WHEN.Subtract(eingestempelt.WHEN);
                var differenz = span.TotalMinutes;
                GesamtMinuten += differenz;
                counter += 1;
            }


INOUT ist hier der eingestempelt/ausgestempelt indikator (0 oder 1)
WHEN ist hier das Datum wann es geschehen ist.

So in etwa, nur das ich den Wechsel der Tage noch berücksichtigen muss.

Kann mir jemand helfen


Ralf Jansen - Fr 29.06.18 16:13

Korrigiere bitte dein Beispiel. Oder erkläre genauer was du sagen willst mit dem Beispiel.
Du sagst er hat zwischen 12:30-17:00 gearbeitet hat, nach deinem Beispiel sind beides aber Einstempel-Vorgänge.
Für mich hat der man von 12:30 bis 12:30 am nächsten Tag durchgearbeitet da er dazwischen nur eingestempelt hat.


lapadula - Fr 29.06.18 16:49

Sorry, hab’s korrigiert.


Delete - Fr 29.06.18 17:31

- Nachträglich durch die Entwickler-Ecke gelöscht -


Ralf Jansen - Fr 29.06.18 19:22

Eleganz ist so eine Sache. Es sollte etwas sein das du und deine Kollegen auch nachvollziehen können und die Korrektheit entsprechend testen könnt.
Elegant wäre eine Linq Lösung. Ob die aber auch nachvollziehbar/testbar/performant ist ist eine andere Sache.

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:
static void Main(string[] args)
{
    var testData = new List<Stempel>()
    {
        new Stempel { WHEN = new DateTime(201811,  8,  00), INOUT = 0 },
        new Stempel { WHEN = new DateTime(20181112,  00), INOUT = 1 },
        new Stempel { WHEN = new DateTime(20181112300), INOUT = 0 },
        new Stempel { WHEN = new DateTime(20181117,  00), INOUT = 1 },
        new Stempel { WHEN = new DateTime(201812,  8,  00), INOUT = 0 },
        new Stempel { WHEN = new DateTime(20181212300), INOUT = 1 },
        new Stempel { WHEN = new DateTime(20181213,  00), INOUT = 0 },
        new Stempel { WHEN = new DateTime(20181217,  00), INOUT = 1 },
    }.OrderBy(x => x.WHEN);

    var workingMinutes = testData
                            .Where(x => x.INOUT == 0)
                            .Select(x => testData.SkipWhile(y => y.WHEN <= x.WHEN).First(z => z.INOUT == 1).WHEN - x.WHEN)
                            .Sum(x=> x.TotalMinutes);
              
    Console.WriteLine(workingMinutes);    
}

public class Stempel
{
  public DateTime WHEN { get; set; }
  public int INOUT { get; set; }
}


Diese Linq Lösung hätte z.B. Probleme wenn die Liste nicht sortiert ist, oder die Liste mit einem einstempeln endet, oder wenn einstempeln-ausstempeln sich nicht sauber abwechseln, oder wenn einstempeln-ausstempeln zeitgleich stattfindet .....

Ein gute Lösung ist hier sicherlich nur möglich wenn man alle zu berücksichtigen Details kennt. Eine scheinbar elegante Lösung wird sonst schnell zu offensichtlichem Mist.


Narses - Fr 29.06.18 23:04

Moin!

Ich hab ich auch mal mit sowas rumgeschlagen, hier noch ein paar Tipps von mir dazu ;) vielleicht hilft´s was :nixweiss:cu
Narses


lapadula - Sa 30.06.18 13:58

Danke für die Antworten.

Also wir nutzen ein neues Zeiterfassungssysten, mit der dazugehöriger Software. Allerdings zeigt diese nicht wirklich die aktuellen Stunden an, bzw. rechnet das intransparen.

Deswegen soll ich es machen, indem ich auf die Datenbank zugreifen und selber nachrechne.