Autor Beitrag
erfahrener Neuling
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 233
Erhaltene Danke: 19

Win 7, Win 10
C#, ASP-MVC (VS 2017 Community), MS SQL, Firebird SQL
BeitragVerfasst: Mi 23.03.16 11:09 
Hallo malwieder,

heute mal eine Sache, die mich gewundert hat.

Ich habe einen string aus einer DataTable, der mal ein Datum mit Uhrzeit war.

Nun wollte ich mit
ausblenden C#-Quelltext
1:
value = string.Format("{0:d}",value);					
die Uhrzeit entfernen, da hat sich aber nichts getan. Ich hab das jetzt erstmal mit
ausblenden C#-Quelltext
1:
value = value.Substring(0,10);					
gelöst, aber verwundert hat's mich schon.

Was konkret hab ich falsch gemacht?
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mi 23.03.16 11:19 
Du hast einen String, das was Du haben willst, braucht aber ein DateTime.

Du musst also erst in DateTime parsen und danch hilft dir diese Seite weiter: www.csharp-examples....ing-format-datetime/
Dort findest Du die verschiedenen Formate, die DateTime kann, schön aufgelistet mit Beispielen.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 23.03.16 11:39 
Wieso hast du überhaupt Datum-/Uhrzeit als string und nicht gleich als DateTime in der DataTable?

Auf fixe Zahlen (wie die 10 beim Substring) würde ich mich niemals verlassen...
erfahrener Neuling Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 233
Erhaltene Danke: 19

Win 7, Win 10
C#, ASP-MVC (VS 2017 Community), MS SQL, Firebird SQL
BeitragVerfasst: Mi 23.03.16 11:58 
Zitat:
Wieso hast du überhaupt Datum-/Uhrzeit als string und nicht gleich als DateTime in der DataTable?

Also in der table ist der Typ DateTime, aber das liegt an meinem skript, wie ich die table auslese.
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
StringBuilder rowContent = new StringBuilder();

foreach (DataRow row in table.Rows)
{
  foreach(DataColumn column in table.Columns)
  {
    string value = row[column].ToString();    //hier wusst ich nicht, wie ich anders an den Wert komme

    if (column.DataType == Type.GetType("System.DateTime"))
      value = value.Substring(0,10);

    rowContent.Append(value + "\t");
  }
        rowContent.AppendLine();


Wie würdet ihr das machen, wenn ihr die ganze Tabelle auslesen wollt, aber die Typen nicht verändern wollt?

Bzw: Wie mache ich aus einem string ein DateTime?
Wenn ich
ausblenden C#-Quelltext
1:
DateTime date = Convert.ToDateTime(value);					
schreibe, kommt die Meldung: Eine eingebettete Anweisung kann keine Deklaration und keine Anweisung mit Bezeichnung sein.

Zitat:
Auf fixe Zahlen (wie die 10 beim Substring) würde ich mich niemals verlassen...
Ja normalerweise schon, aber hier geht das ;)
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mi 23.03.16 12:25 
Zitat:
hier wusst ich nicht, wie ich anders an den Wert komme

Das geht so: var value = (DateTime)row[column];
Oder sicherer so:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
var value = row[column];

if (value is DateTime)
{
    var date = (DateTime)value;
    // todo ...
}
else
{
    // error ...
}

Zitat:
Type.GetType("System.DateTime"))

Besser so: typeof(DateTime)



Ich schreib nochmal mein obligatorisches Gemecker dazu:
Ich finde die DataTable nicht gut ^^
Wenn die genutzt wird, dann wird sie häufig genutzt um eine schlechte Software-Architektur zu umgehen oder aus Faulheit.
Es gibt keine Typisierung zur Compiletime, allgemein gibt es keine Sicherheit, die der Compiler verschaffen kann, in der Table kann ja alles sein und das kannst Du vorher nur umständlich prüfen.
Besser wäre eine Klasse mit den entsprechenden Properties und dann eine Auflistung mit diesem Typ, mit der gearbeitet wird.
Wenn die Daten von der Datenbank kommen, gibt es OR-Mapper (z.B. Entity Framework) und wenn nicht, kann man zumindest einen DataReader bekommen, dessen Daten man ziemlich leicht in ein IEnumerable<MyClass> konvertieren kann.


Zuletzt bearbeitet von Palladin007 am Mi 23.03.16 12:38, insgesamt 1-mal bearbeitet

Für diesen Beitrag haben gedankt: erfahrener Neuling
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 23.03.16 12:27 
ausblenden C#-Quelltext
1:
2:
if (row[column] is DateTime)
    value = ((DateTime)row[column]).ToString(meineLiebeFormatierZeichenfolge);


Das sieht nach generischem Code aus da solltest du auch (vorher) testen ob die Column nullable ist und/oder DBNull enthält sonst fliegt dir das um die Ohren.
Werte danch als strings weiterzubearbeiten finde ich suoptimal. Zum Beispiel wie ich eine Datum formatiert haben möchte ist eine ziemlich individuelle Sache.
So wie du das machst entscheidest du für den User wie das Datum auszusehen hat der womöglich aber ganz andere Präferenzen hat als du. Das würde ich so wie du maximal so machen wenn die Daten an eine definierten Schnittstelle gehen wo das so aussehen muß.

Edit: @Paladin007

Bei einer dynamischen Quelle (z.b. User definiertes Sql oder eine DataPump ...) wird dir ein Typisierung zur Design/Compilezeit nicht helfen. Dann muß man das so oder ähnlich machen. Und da er hier generisch über Columns und Rows iteriert gehe ich schwer davon aus das es keine klar definierte Datenquelle gibt.

Edit2:

Zitat:
ausblenden C#-Quelltext
1:
value = string.Format("{0:d}",value);					


Um das auch zu beantworten. Wenn value ein DateTime value wäre würde das gehen. Du gibst aber einen string rein und das System kann nicht wissen das dieser string ein Datum darstellen sollte. Schon gar nicht welche Formatierung die Quelle (also value) hat. Diee Formatierungsanweisung beziehen sich immer auf einen bestimmten Datentyp. Wenn du zum Beispiel im Formatstring angibst das du etwas mit n Nachkommastellen angezeigt bekommen willst geht das auch nur wenn du ein Fließkommazahl rein reichst. Ein string wird nicht formatiert sondern per string.Format nur ausgegeben nur für andere Datentypen kannst du Anweisungen mitgeben wie sie als string dargestellt werden sollen.


Zuletzt bearbeitet von Ralf Jansen am Mi 23.03.16 12:42, insgesamt 1-mal bearbeitet

Für diesen Beitrag haben gedankt: erfahrener Neuling
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mi 23.03.16 12:36 
Hallo Palladin007,

da bin ich wohl dran schuld, weil ich ihm in Inhalt einer Datenbank-​Abfrage in ein DataGridView packen zu dieser kurz und schnell umsetzbaren Lösung geraten habe.

Generell gebe ich dir recht, daß man bei größeren Projekten ein ORM benutzen sollte - aber nicht gleich einem Anfänger...

PS: Du hast einen kleinen Fehler in deinem letzten Code (erste Zeile) - es muß so aussehen:
ausblenden C#-Quelltext
1:
var value = row[column];					

(war sicherlich nur ein C&P-Fehler und kein Verständnisproblem, oder? ;-))
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mi 23.03.16 12:51 
@Th69:

Ja, Copy-Pasta-Fehler :D
Hab ich angepasst, danke ^^

Dennoch finde ich persönlich den DataReader besser.
Ich habe dafür auch immer irgendwo eine Extension-Methode rum fliegen, die ungefähr so aus sieht:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
public static IEnumerable<Person> CastToPeople(IDataReader dataReader)
{
    using (dataReader)
    {
        while (dataReader.NextResult())
        {
            yield return Person
            {
                Name = dataReader.GetString(0),
                BirthDate = dataReader.GetDateTime(1),
                // ...
            };
        }
    }
}


So hab ich keinen ORMapper, sondern einen DataReader, aber alles streng typisiert.


@Ralf Jansen:

Dynamisch ist schon doof, das gebe ich zu.
Allerdings würde ich dann trotzdem eine Klassen-Struktur aufbauen, die entsprechend flexibel die Daten aufnehmen kann.
Typisiert ist das dann immer noch nicht, aber ich bin flexibler in der weiteren Arbeit damit
erfahrener Neuling Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 233
Erhaltene Danke: 19

Win 7, Win 10
C#, ASP-MVC (VS 2017 Community), MS SQL, Firebird SQL
BeitragVerfasst: Mi 23.03.16 13:51 
Danke an alle für die wie immer schnelle und hilfreiche Hilfe ;)

@Ralf Jansen
Zitat:
Das sieht nach generischem Code aus da solltest du auch (vorher) testen ob die Column nullable ist und/oder DBNull enthält sonst fliegt dir das um die Ohren.
Werte danch als strings weiterzubearbeiten finde ich suoptimal. Zum Beispiel wie ich eine Datum formatiert haben möchte ist eine ziemlich individuelle Sache.
So wie du das machst entscheidest du für den User wie das Datum auszusehen hat der womöglich aber ganz andere Präferenzen hat als du. Das würde ich so wie du maximal so machen wenn die Daten an eine definierten Schnittstelle gehen wo das so aussehen muß.

Ja das mit dem Null stimmt schon, wird aber schon vorher geprüft.
Zur Erklärung:
Step 1: der Benutzer wählt eine Datenbank-Verbindung aus (diese konnte nur erstellt werden , wenn eine bestimmte Tabelle bestimmte Anforderungen erfüllt)
Step 2: die Tabelle wird in eine DataTable geladen (dort wird geprüft, ob bestimmte Spalten-Werte null sind)
Step 3: der Inhalt der korrekten DataTable wird nach bestimmten vorgaben (wie zum Beispiel das Format bei Dates) in eine Textdatei geschrieben

Also das mit dem Datumsformat soll sich eigentlich nicht ändern, da diese Textdatei wieder von einem anderen (mir unbekannten) Programm weiter-verwertet wird.
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 23.03.16 14:06 
Zitat:
Also das mit dem Datumsformat soll sich eigentlich nicht ändern, da diese Textdatei wieder von einem anderen (mir unbekannten) Programm weiter-verwertet wird.


Dann ist die Textdatei das was ich definierte Schnittstelle genannt habe. Und ich hoffe das, gerade wenn die Zielanwendung nicht bekannt ist, es eine Schnittstellendefinition gibt wo eindeutig drin steht "so ist ein Datum formatiert" damit ein Nutzer die richtig einlesen kann.
erfahrener Neuling Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 233
Erhaltene Danke: 19

Win 7, Win 10
C#, ASP-MVC (VS 2017 Community), MS SQL, Firebird SQL
BeitragVerfasst: Mi 23.03.16 14:18 
Ja nach genau so einer Schnittstellendefinition muss ich hier das Programm entwickeln