Überstundenberechnung in C# WinForms

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 13 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Überstundenberechnung in C# WinForms

    Moin zusammen,

    ich versuche ein Programm in C# WinForm .NET 4.7.2 zu entwickeln, das basierend auf einer Excel-Tabelle namens "Meine Zeiten" Überstunden und die Anzahl der Tage, die ich durch Überstunden gewonnen habe, berechnet. Leider funktioniert es nicht wie erwartet. Ich habe versucht, meinen Code umzuschreiben, aber ich erhalte eine Fehlermeldung, dass die Zeichenfolge nicht als gültiges DateTime erkannt wird. Das kann aber eigentlich nicht sein, da ich einen Screenshot der Tabelle habe und die Zeiten im Format hh:mm:ss angegeben sind.

    Das Programm soll die Daten aus Spalte A und B nehmen, das Datum vergleichen und am Ende anzeigen, wie viele Überstunden insgesamt für diesen Monat vorhanden sind und zusätzlich die Anzahl der Urlaubstage.

    Ich habe die Stelle im Code markiert, an der ich die Fehlermeldung erhalte. Vielen Dank für eure Unterstützung.

    Viele Grüße,

    komp. Quellcode:

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Globalization;
    7. using System.IO;
    8. using System.Linq;
    9. using System.Text;
    10. using System.Threading.Tasks;
    11. using System.Windows.Forms;
    12. using Excel = Microsoft.Office.Interop.Excel;
    13. using Application = Microsoft.Office.Interop.Excel.Application;
    14. using DocumentFormat.OpenXml.Packaging;
    15. using DocumentFormat.OpenXml.Spreadsheet;
    16. using ExcelDataReader;
    17. namespace LogSaver
    18. {
    19. public partial class Form3 : Form
    20. {
    21. private string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Meine Zeiten", "Meine Zeiten.xlsx");
    22. public Form3()
    23. {
    24. InitializeComponent();
    25. LoadData();
    26. }
    27. private void LoadData()
    28. {
    29. List<TimeRecord> timeRecords = new List<TimeRecord>();
    30. using (SpreadsheetDocument doc = SpreadsheetDocument.Open(filePath, false))
    31. {
    32. WorksheetPart worksheetPart = doc.WorkbookPart.WorksheetParts.First();
    33. CultureInfo provider = CultureInfo.InvariantCulture;
    34. foreach (Row row in worksheetPart.Worksheet.Descendants<Row>())
    35. {
    36. if (row.RowIndex > 1)
    37. {
    38. TimeRecord record = new TimeRecord();
    39. Cell startCell = row.Descendants<Cell>().ElementAt(0); // A column
    40. Cell endCell = row.Descendants<Cell>().ElementAt(1); // B column
    41. Cell dateCell = row.Descendants<Cell>().ElementAt(2); // C column
    42. string startCellVal = startCell.CellValue.Text;
    43. string endCellVal = endCell.CellValue.Text;
    44. string dateCellVal = dateCell.CellValue.Text;
    45. record.StartTime = DateTime.ParseExact(startCellVal, "HH:mm:ss", provider); // Hier bekomme ich das Problem: System.FormatException: "Die Zeichenfolge wurde nicht als gültiges DateTime erkannt."[color=#FF0000][u][b][/b][/u][/color]
    46. record.EndTime = DateTime.ParseExact(endCellVal, "HH:mm:ss", provider);
    47. record.Date = DateTime.ParseExact(dateCellVal, "dd.MM.yyyy", provider);
    48. timeRecords.Add(record);
    49. }
    50. }
    51. }
    52. UpdateLabels(timeRecords);
    53. }
    54. private void UpdateLabels(List<TimeRecord> records)
    55. {
    56. double totalOvertime = 0;
    57. double currentMonthOvertime = 0;
    58. foreach (var record in records)
    59. {
    60. double dailyHours = (record.EndTime - record.StartTime).TotalHours;
    61. totalOvertime += dailyHours - 8;
    62. if (record.Date.Month == DateTime.Now.Month && record.Date.Year == DateTime.Now.Year)
    63. currentMonthOvertime += dailyHours - 8;
    64. }
    65. überstundenlbl.Text = $"Überstunden total: {totalOvertime} Stunden";
    66. überstundenaktuellmonatlbl.Text = $"Überstunden diesen Monat: {currentMonthOvertime} Stunden";
    67. double holidayDays = totalOvertime / 8;
    68. stundeninurlaubstagelbl.Text = $"Urlaubstage durch Überstunden: {holidayDays} Tage";
    69. }
    70. public class TimeRecord
    71. {
    72. public DateTime StartTime { get; set; }
    73. public DateTime EndTime { get; set; }
    74. public DateTime Date { get; set; }
    75. }
    76. private void Form3_Load(object sender, EventArgs e)
    77. {
    78. }
    79. }
    80. }


    Bild von der .xlsx Datei: https://www.webpagescreenshot.info/image-url/h50KEhEhR
    naja, in 99,5% der Fälle stimmt so eine Fehlermeldung.
    Also prüfe den Wert, der da formatiert werden soll. Nur ins Grid gucken reicht nicht, weil da sieht man Werte, die auch wieder anders formatiert sind.

    Es kann auch sein, dass der FormatString insgesamt für ParseExact nicht geeignet ist - kann man ja auch schnell prüfen.
    ich habe die Stellen hinzugefügt hier der Code:

    C#-Quellcode

    1. if (DateTime.TryParseExact(startCellVal, "HH:mm:ss", provider, DateTimeStyles.None, out startTime))
    2. {
    3. record.StartTime = startTime;
    4. }
    5. else
    6. {
    7. // Fehler bei der Konvertierung der Startzeit
    8. MessageBox.Show("Fehler bei der Konvertierung der Startzeit: " + startCellVal);
    9. }
    10. DateTime endTime;
    11. if (DateTime.TryParseExact(endCellVal, "HH:mm:ss", provider, DateTimeStyles.None, out endTime))
    12. {
    13. record.EndTime = endTime;
    14. }
    15. else
    16. {
    17. // Fehler bei der Konvertierung der Endzeit
    18. MessageBox.Show("Fehler bei der Konvertierung der Endzeit: " + endCellVal);
    19. }
    20. DateTime date;
    21. if (DateTime.TryParseExact(dateCellVal, "dd.MM.yyyy", provider, DateTimeStyles.None, out date))
    22. {
    23. record.Date = date;
    24. }
    25. else
    26. {
    27. // Fehler bei der Konvertierung des Datums
    28. MessageBox.Show("Fehler bei der Konvertierung des Datums: " + dateCellVal);
    29. }


    tatsächlich obwohl das bei der Tabelle also bei der Datei .xlsx korrekt formatiert ist (spricht Uhrzeit Spalte A, B und Datum Spalte C) konvertiert auf komischerweise in dezimal zahlen für Spalte A bekomme ich den Wert für 7 Uhr "0.29166666666666...9" für Spalte B "0.6666666666666...3" und für Spalte C "44861.. 2 ... 3 ...4" usw. Aber wieso ist das bei der Excel Tabelle denn so, die sind ja richtig konvertiert?
    @mehmetqan Poste mal den Inhalt der Variable startCellVal.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermanyich kann dir die Quellcode noch einmal posten:
    Spoiler anzeigen

    C#-Quellcode

    1. using System;
    2. using System.Collections.Generic;
    3. using System.ComponentModel;
    4. using System.Data;
    5. using System.Drawing;
    6. using System.Globalization;
    7. using System.IO;
    8. using System.Linq;
    9. using System.Text;
    10. using System.Threading.Tasks;
    11. using System.Windows.Forms;
    12. using Excel = Microsoft.Office.Interop.Excel;
    13. using Application = Microsoft.Office.Interop.Excel.Application;
    14. using DocumentFormat.OpenXml.Packaging;
    15. using DocumentFormat.OpenXml.Spreadsheet;
    16. using ExcelDataReader;
    17. namespace LogSaver
    18. {
    19. public partial class Form3 : Form
    20. {
    21. private string filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "Meine Zeiten", "Meine Zeiten.xlsx");
    22. public Form3()
    23. {
    24. InitializeComponent();
    25. LoadData();
    26. }
    27. private void LoadData()
    28. {
    29. List<TimeRecord> timeRecords = new List<TimeRecord>();
    30. using (SpreadsheetDocument doc = SpreadsheetDocument.Open(filePath, false))
    31. {
    32. WorksheetPart worksheetPart = doc.WorkbookPart.WorksheetParts.First();
    33. CultureInfo provider = CultureInfo.InvariantCulture;
    34. foreach (Row row in worksheetPart.Worksheet.Descendants<Row>())
    35. {
    36. if (row.RowIndex > 1)
    37. {
    38. TimeRecord record = new TimeRecord();
    39. Cell startCell = row.Descendants<Cell>().ElementAt(0); // A column
    40. Cell endCell = row.Descendants<Cell>().ElementAt(1); // B column
    41. Cell dateCell = row.Descendants<Cell>().ElementAt(2); // C column
    42. string startCellVal = startCell.CellValue.Text;
    43. string endCellVal = endCell.CellValue.Text;
    44. string dateCellVal = dateCell.CellValue.Text;
    45. record.StartTime = DateTime.ParseExact(startCellVal, "HH:mm:ss", provider); // Hier bekomme ich das Problem: System.FormatException: "Die Zeichenfolge wurde nicht als gültiges DateTime erkannt."[color=#FF0000][u][b][/b][/u][/color]
    46. record.EndTime = DateTime.ParseExact(endCellVal, "HH:mm:ss", provider);
    47. record.Date = DateTime.ParseExact(dateCellVal, "dd.MM.yyyy", provider);
    48. timeRecords.Add(record);
    49. }
    50. }
    51. }
    52. UpdateLabels(timeRecords);
    53. }
    54. private void UpdateLabels(List<TimeRecord> records)
    55. {
    56. double totalOvertime = 0;
    57. double currentMonthOvertime = 0;
    58. foreach (var record in records)
    59. {
    60. double dailyHours = (record.EndTime - record.StartTime).TotalHours;
    61. totalOvertime += dailyHours - 8;
    62. if (record.Date.Month == DateTime.Now.Month && record.Date.Year == DateTime.Now.Year)
    63. currentMonthOvertime += dailyHours - 8;
    64. }
    65. überstundenlbl.Text = $"Überstunden total: {totalOvertime} Stunden";
    66. überstundenaktuellmonatlbl.Text = $"Überstunden diesen Monat: {currentMonthOvertime} Stunden";
    67. double holidayDays = totalOvertime / 8;
    68. stundeninurlaubstagelbl.Text = $"Urlaubstage durch Überstunden: {holidayDays} Tage";
    69. }
    70. public class TimeRecord
    71. {
    72. public DateTime StartTime { get; set; }
    73. public DateTime EndTime { get; set; }
    74. public DateTime Date { get; set; }
    75. }
    76. private void Form3_Load(object sender, EventArgs e)
    77. {
    78. }
    79. }
    80. }


    Auch die Excel Tabelle: file2send.eu/de/download/D8Hv8…EFbrX9vbfhGvy7TP1JDtbuvWw
    0.59032407407... ist die Excel-Uhrzeitrepräsentation von 14:10:04
    In Excel wird die Uhrzeit als Bruchteil des Tages gespeichert.
    0.5 = 1/2 Tag = 12 Stunden = 12:00

    Stunden bekommst du mit val*24
    Minuten mit val*24*60
    Sekunden mit val*24*60*60
    usw.

    Wenn du mit nur mit Uhrzeit arbeitest kannst du auch mit
    DateTime.FromOADate
    konvertieren und nur den Zeitanteil verwenden.
    --
    If Not Program.isWorking Then Code.Debug Else Code.DoNotTouch
    --

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „petaod“ ()

    @mehmetqan Gehe da mal mit Debug-Methoden ran, Du brauchst keine MessageBox, nur einen Haltepunkt:
    Debuggen, Fehler finden und beseitigen
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @RodFromGermany ich bin da in Debug mode gewesen und es überspringt nichts, sondern macht alles nach Code-Rheinfolge, dennoch stopp er bei record.StartTime, nach string dateCellVal = dateCell.CellValue.Text;

    ist alles gut, jedoch bei FormatException " record.StartTime = DateTime.ParseExact(startCellVal, "HH:mm:ss", provider);" bekomme ich ein DateTime Problem "System.FormatException: "Die Zeichenfolge wurde nicht als gültiges DateTime erkannt.""

    sonst weiß ich nicht was du meinst der Thread habe ich verfolgt, jedoch großartig habe ich leider auch nichts verstanden...

    mehmetqan schrieb:

    Debug mode
    und Debuggen ist zweierlei.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    so, dann ist ja alles klar - wie ich sagte: meist wenn die Exception kommt liegt das daran, das schlicht stimmt, was die Exception sagt.
    "0.59032407407" ist kein Wert, der mit DateTime.ParseExact() ausgelesen werden könnte.

    Zum Thema Debuggen: Du scheinst den Haltepunkt nicht zu kennen, und einige andere Visualstudio-Features auch nicht.
    Alternativ zu RFGs Tut kannste dir auch mal mein Tut zum Thema Debuggen angucken: VisualStudio richtig nutzen (Google ist nicht deine Mami)
    Das ist v.a. ein Video, da siehst du, was unsereiner meint, wenner sagt: "Mach mal Haltepunkt hin und guck im Lokalfenster nach, was inne Variablen steht."
    Evtl. öfter angucken, das Vid hat keine min, da bretter ich recht hastig durch den Stoff.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    du liest sie doch schon aus, das funktioniert ja - zumindest die Rohdaten.
    Was bei dir scheitert ist die Konvertierung der Rohdaten in ordentliche Objekte.
    orddentliche Objekte haste ja auch schon - etwa TimeRecord sccheint über sinnvolle Properties zu verfügen.
    wie gesagt, bei der Konvertierung haperts - DateTime.ParseExact ist nicht geeignet, einen Wert im Excel-Zeitformat zu parsen.
    Zum Konvertieren eines Excel-Zeitwertes schrieb petaod dir ja, wie das geht.