none
SQL-Server 2012 uund 2014 reagierten nicht auf "Regional Settings" RRS feed

  • Frage

  • Hallo,

    ich musste eine Web-Anwendung auf einen WinServer 2012 umziehen.
    Leider musste ich dabei auch von einer deutschen auf eine us-Version umsteigen.

    Nun klappte die Eingabe eines Datums-Typen nicht mehr.

    Auf meinem deutschen System konnte ich, wie immer das Datum mit "23.05.2017" formatieren.
    Auf dem us-System ging das nicht mehr. Daher habe ich das Format "20170523", also "yyyMMdd" verwendet, das auch auf meinem deutschen System angenommen wird.

    Ich habe übrigens die "Regional Settings" für Betriebssystem, SQL-Server und ODBC Datenquelle auf deutsch eingestellt!

    Aber diese beiden SQL-Server setzen der Sache noch eins drauf.
    Wenn ich diesen Datums-Datentyp wieder auslese (Web-Anwendung mit .NET 2.0 und C#), mit dem
    Statement "dt.Rows[0]["Implemented"].ToString()", bekomme ich den Wert nicht mit den eingestellten "Regional Settings zurück, sondern so wie sie eingegeben wurden.

    D.h. die alten Einträge, von vor der Migration, bekomme ich im Format "23.05.2017" zurück,
    die neuen Einträge bekomme ich allerdings als "20170523" zurück.

    Und damit nicht einmal genug!
    .NET ist nicht in der Lage, das Format "20170523" als ein gültiges Datum zu erkennen.
    Aber es erkennt wenigstens das deutsche Format, so dass die alten Daten wie zuvor angezeigt werden.

    Also selbst wenn ich beim Auslesen einen Format-Spezifizierer verwende,
    z.B. "ParseExact(..)" oder Ähnliches, habe ich das Problem mit unterschiedlichen Formaten beim Auslesen.

    Es tut mir leid. Aber was macht man da bei Microsoft?

    Kann mir jemand bitte erklären wie ich mit dem Verhalten am Besten umgehe.
    Gibt es einen Workaround?

    Habe ich vielleicht doch eine Einstellungsmöglichkeit übersehen?

    Oder muss ich mal wieder selbst den Datums-String zerlegen und wieder zusammensetzen?

    Vielen Dank für Eure Antwort und Grüsse

    Helmut


    • Bearbeitet Helmut19 Dienstag, 7. November 2017 21:59
    Dienstag, 7. November 2017 21:10

Antworten

  • Hi Helmut,
    im anderen Thread von Dir zum gleichen Thema hatte ich Dir bereits die Frage zum Spaltentyp gestellt. Deine Schilderungen lassen vermuten, dass Du eine Textspalte für das Abspeichern einer Datumsinformation nutzt. In diesem Fall wäre der SQL Server nicht für eine Konvertierung von und zu einer lokalen Einstellung verantwortlich. Das ist Aufgabe der Anwendung. Über diese solltest nachdenken und hier mal etwas posten, damit man Dir helfen kann.

    Wenn die Spalte jedoch vom Typ date oder datetime ist, wird ein Datumswert binär und invariant abgelegt. Da kann es zu keinen Problemen mit der genutzten Kultur kommen. Voraussetzung dafür ist aber der Zugriff mit Parametern in der SQL Anweisung. Für die Konvertierung ist dann nur die Anwendung und nicht der SQL Server verantwortlich.

    Aus Deinen Codeschnipseln aus dem anderen Thread ist ersichtlich, dass Du im Programm mit Zeichenketten für Datumswerte arbeitest, ohne explizit Kultureinstellungen anzugeben. So etwas kann auf Anwendungsseite zu impliziten Typkonvertierungen führen (ToString), die dann das von Dir gezeigte Ergebnis bringen können.

    Wenn Du wirklich langfristig die Stabilität der Anwendung sichern willst, wirst um eine geringfügige Analyse und Überarbeitung des DataLayers nicht umhin kommen.


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks



    Mittwoch, 8. November 2017 07:18
  • Dem kann ich auch nur explizit zustimmen.
    Eine Datenbank speichert ihre Information i.d.R. unabhängig von jedweder Ländereinstellung!
    Bei einer Dezimalzahl wählt man ja auch Numeric/Decimal/Double und weiß so, dass der Wert korrekt gespeichert wird unabhängig vom verwendeten Client, der nun einen Dezimalpunkt oder Dezimalkomma verwendet.
    Ganz genauso verhält es sich auch mit den Typen Date/Time/Timestamp, die je nach Dialekt auch  mal einwenig anders heißen.

    Sobald man aber von der Typisierung seiner Daten weggeht kann man sich da nur Probleme einhandeln.
    Bei der Datumdarstellung in der Form "TT.MM.JJJJ" scheitert man bereits an Sortierungen, Vergleichen wie >, <, between oder sogar Berechnungen.
    Hierfür muss man dann wieder Klimmzüge mit Konvertierungen (Cast's) vornehmen, die dann auch noch kontraproduktiv bzgl. der Verwendung von Indizes sind.

    Kommen wir nun zum Client:
    Auch dort werden die Möglichkeiten von sprachneutralen Verwendungen häufig vernachlässigt!

    Seit Einführung von SQL (Ende der 60er) gibt es bereits das Konzept der "Parametermarker".
    D.h., dass grundsätzlich in allen SQL's mit variablen Daten Parametermarker zu verwenden sind!

    Das unsägliche zusammenbauen von SQL's im Code macht die ganze Sache nur unnötig kompliziert und, vor allem, auch langsamer! Und es müssen ebenso die Eigenheiten der Datenbank berücksichtigt werden.

    Hinzu kommt, dass eben Parametermarker ebenso sprachneutral sind. Jede Programmiersprache kennt ihre Datentypen, so dass diese auch in SQL verwendbar sind. Für eine korrekte Übersetzung zwischen Programmvariable und SQL ist letztlich dann der Treiber zuständig.
    Wer kennt nicht das Problem, dass Zeichenketten, die ein Hochkomma enthalten, diese verdoppelt werden müssen? Mit Parametermarker vollkommen unnötig.

    Wenn ich also eine Spalte vom Typ Date definiert habe, kann ich auch in meinem Programm die Variable vom Type Date/Datetime verwenden und diese dann dem jeweiligen Parameter direkt zuweisen.
    Beim Auslesen der Daten erhalte ich auch direkt eine Variable vom Typ Date.
    Dasselbe gilt im Übrigen ebenso der Verwendung von Unicode oder Nicht-Unicode.

    Beispiel:
    Insert into MyTable (F1, F2, F3) values(?, ?, ?)
    Select * from MyTable where F1=? and F2 between ? and ? and F3 > ?

    Je nach Treiber kann dieser ggf. schon die Parameter-Objekte automatisch erstellen.
    Ansonsten gibt es dann Methoden, je "?" einen Parameter in der Reihenfolge zu definieren.
    .NET unterstützt (mit DataAdapter und CommandBuilder) auch benannte Parameter:
    Select * from MyTable where F1=@F1 and F2 between @F2A and @F2B and F3 > @F3

    Zuguter letzt braucht sich der Client dann nur noch in der Präsentation und Eingabe um sprachrelevante Dinge zu kümmern, wobei hier die Regional-Settings dann auch ziehen (außer bei den sog. Invariant-Funktionen).
    Und selbst dabei wird man automatisch durch die Frameworks bereits unterstützt.

    Wie du siehst, eigentlich alles ganz Easy.


    Mittwoch, 8. November 2017 08:38
  • Hallo Helmut,

    mit welchem Datentyp legst Du das Datum in der Tabelle ab?

    Welche Default-Sprache hat das Login welches verwendet wird? Vielleicht vorher Deutsch und jetzt Englisch?


    Einen schönen Tag noch, Christoph -- Data Platform MVP - http://www.insidesql.org/blogs/cmu

    Mittwoch, 8. November 2017 06:58
  • Hallo alle,

    und nochmals vielen Dank für Eure HInweise.
    Sie waren sehr hilfreich. Vor allem das mit dem varchar-Feld.
    Ich habe es erst gar nicht glauben wollen, weil ich doch alle Datumsfelder auch als "dateiteime" angelegt habe.
    Ausserdem kam ja der erste Fehler diesbezüglich beim Eintragen eines neuen Datensatzes, und zwar ebenfalls mit Hinweis auf falsches datetime-Format.

    Und zuvor hat diese Webanwendung jahrelang funktioniert.

    Es war nun so:
    Es war tatsächlich ein varchar-Feld statt eines datetime-Feldes rein gekommen, als ich damals die Datenbank aus
    dem Quellcode der Web-Anwendung für den unglücklichen Besitzer rekonstruiert hatte.

    Und dann habe ich zwei unterschiedliche Fehler für einen gehalten.
    Der Fehler beim Eintragen eines Datensatzes erfolgte, weil ein Datumsfeld leer war, obwohl NULL-Werte erlaubt sind.
    Das habe ich jetzt erst raus bekommen.
    Seltsamerweise kam dann dieser Fehler nicht mehr, als ich das Datumsformat auf "yyyyMMdd" geändert hatte.
    Ab da konnte ich die neu eingetragenen Datensätze nicht mehr anzeigen, weil dieses Datumsformat von den 
    obigen Funktionen nicht konvertiert werden konnte.

    Also danke nochmal.
    Grüsse 
    Helmut

    • Als Antwort markiert Helmut19 Mittwoch, 8. November 2017 22:22
    Mittwoch, 8. November 2017 22:19

Alle Antworten

  • Hallo Helmut,

    mit welchem Datentyp legst Du das Datum in der Tabelle ab?

    Welche Default-Sprache hat das Login welches verwendet wird? Vielleicht vorher Deutsch und jetzt Englisch?


    Einen schönen Tag noch, Christoph -- Data Platform MVP - http://www.insidesql.org/blogs/cmu

    Mittwoch, 8. November 2017 06:58
  • Hi Helmut,
    im anderen Thread von Dir zum gleichen Thema hatte ich Dir bereits die Frage zum Spaltentyp gestellt. Deine Schilderungen lassen vermuten, dass Du eine Textspalte für das Abspeichern einer Datumsinformation nutzt. In diesem Fall wäre der SQL Server nicht für eine Konvertierung von und zu einer lokalen Einstellung verantwortlich. Das ist Aufgabe der Anwendung. Über diese solltest nachdenken und hier mal etwas posten, damit man Dir helfen kann.

    Wenn die Spalte jedoch vom Typ date oder datetime ist, wird ein Datumswert binär und invariant abgelegt. Da kann es zu keinen Problemen mit der genutzten Kultur kommen. Voraussetzung dafür ist aber der Zugriff mit Parametern in der SQL Anweisung. Für die Konvertierung ist dann nur die Anwendung und nicht der SQL Server verantwortlich.

    Aus Deinen Codeschnipseln aus dem anderen Thread ist ersichtlich, dass Du im Programm mit Zeichenketten für Datumswerte arbeitest, ohne explizit Kultureinstellungen anzugeben. So etwas kann auf Anwendungsseite zu impliziten Typkonvertierungen führen (ToString), die dann das von Dir gezeigte Ergebnis bringen können.

    Wenn Du wirklich langfristig die Stabilität der Anwendung sichern willst, wirst um eine geringfügige Analyse und Überarbeitung des DataLayers nicht umhin kommen.


    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks



    Mittwoch, 8. November 2017 07:18
  • Dem kann ich auch nur explizit zustimmen.
    Eine Datenbank speichert ihre Information i.d.R. unabhängig von jedweder Ländereinstellung!
    Bei einer Dezimalzahl wählt man ja auch Numeric/Decimal/Double und weiß so, dass der Wert korrekt gespeichert wird unabhängig vom verwendeten Client, der nun einen Dezimalpunkt oder Dezimalkomma verwendet.
    Ganz genauso verhält es sich auch mit den Typen Date/Time/Timestamp, die je nach Dialekt auch  mal einwenig anders heißen.

    Sobald man aber von der Typisierung seiner Daten weggeht kann man sich da nur Probleme einhandeln.
    Bei der Datumdarstellung in der Form "TT.MM.JJJJ" scheitert man bereits an Sortierungen, Vergleichen wie >, <, between oder sogar Berechnungen.
    Hierfür muss man dann wieder Klimmzüge mit Konvertierungen (Cast's) vornehmen, die dann auch noch kontraproduktiv bzgl. der Verwendung von Indizes sind.

    Kommen wir nun zum Client:
    Auch dort werden die Möglichkeiten von sprachneutralen Verwendungen häufig vernachlässigt!

    Seit Einführung von SQL (Ende der 60er) gibt es bereits das Konzept der "Parametermarker".
    D.h., dass grundsätzlich in allen SQL's mit variablen Daten Parametermarker zu verwenden sind!

    Das unsägliche zusammenbauen von SQL's im Code macht die ganze Sache nur unnötig kompliziert und, vor allem, auch langsamer! Und es müssen ebenso die Eigenheiten der Datenbank berücksichtigt werden.

    Hinzu kommt, dass eben Parametermarker ebenso sprachneutral sind. Jede Programmiersprache kennt ihre Datentypen, so dass diese auch in SQL verwendbar sind. Für eine korrekte Übersetzung zwischen Programmvariable und SQL ist letztlich dann der Treiber zuständig.
    Wer kennt nicht das Problem, dass Zeichenketten, die ein Hochkomma enthalten, diese verdoppelt werden müssen? Mit Parametermarker vollkommen unnötig.

    Wenn ich also eine Spalte vom Typ Date definiert habe, kann ich auch in meinem Programm die Variable vom Type Date/Datetime verwenden und diese dann dem jeweiligen Parameter direkt zuweisen.
    Beim Auslesen der Daten erhalte ich auch direkt eine Variable vom Typ Date.
    Dasselbe gilt im Übrigen ebenso der Verwendung von Unicode oder Nicht-Unicode.

    Beispiel:
    Insert into MyTable (F1, F2, F3) values(?, ?, ?)
    Select * from MyTable where F1=? and F2 between ? and ? and F3 > ?

    Je nach Treiber kann dieser ggf. schon die Parameter-Objekte automatisch erstellen.
    Ansonsten gibt es dann Methoden, je "?" einen Parameter in der Reihenfolge zu definieren.
    .NET unterstützt (mit DataAdapter und CommandBuilder) auch benannte Parameter:
    Select * from MyTable where F1=@F1 and F2 between @F2A and @F2B and F3 > @F3

    Zuguter letzt braucht sich der Client dann nur noch in der Präsentation und Eingabe um sprachrelevante Dinge zu kümmern, wobei hier die Regional-Settings dann auch ziehen (außer bei den sog. Invariant-Funktionen).
    Und selbst dabei wird man automatisch durch die Frameworks bereits unterstützt.

    Wie du siehst, eigentlich alles ganz Easy.


    Mittwoch, 8. November 2017 08:38
  • Hallo alle,

    vielen Dank für Eure ausführlichen Antworten.

    Bin gerade erst von meinem eigentlichen Job gekommen.
    Ich muss mir die DB nochmal genauer ansehen.

    Eigentlich dachte ich ja auch immer so wie Du Peter.
    Und eigentlich habe ich auch alle Felder, die auf ein Datum hindeuten als DataTime angelegt.
    Daher ist das Verhalten ja auch so Irritierend.

    Also sehe ich mir das Ganze nochmals genauer an.

    Mittwoch, 8. November 2017 17:05
  • Hi Helmut,
    es kann schon sein, dass die Datumsfelder auch vom Typ date bzw. datetime sind, aber der DataLayer unpassend programmiert wurde. Im anderen Thread hast Du gezeigt, dass die Methoden des DataLayers mit Zeichenketten für Datumswerte aufgerufen werden. Wenn da wegen fehlenden Culture-Angaben implizit mit den Einstellungen des Anwenders konvertiert wird und diese Zeichenketten dann in SQL Anweisungen eingebaut werden (verkettet, nicht über Parameter), dann kann dieses Chaos auch entstehen. Dafür ist aber nicht der SQL Server verantwortlich und seine Spracheinstellungen haben da keine Auswirkungen.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks

    Mittwoch, 8. November 2017 17:17
  • Hallo alle,

    und nochmals vielen Dank für Eure HInweise.
    Sie waren sehr hilfreich. Vor allem das mit dem varchar-Feld.
    Ich habe es erst gar nicht glauben wollen, weil ich doch alle Datumsfelder auch als "dateiteime" angelegt habe.
    Ausserdem kam ja der erste Fehler diesbezüglich beim Eintragen eines neuen Datensatzes, und zwar ebenfalls mit Hinweis auf falsches datetime-Format.

    Und zuvor hat diese Webanwendung jahrelang funktioniert.

    Es war nun so:
    Es war tatsächlich ein varchar-Feld statt eines datetime-Feldes rein gekommen, als ich damals die Datenbank aus
    dem Quellcode der Web-Anwendung für den unglücklichen Besitzer rekonstruiert hatte.

    Und dann habe ich zwei unterschiedliche Fehler für einen gehalten.
    Der Fehler beim Eintragen eines Datensatzes erfolgte, weil ein Datumsfeld leer war, obwohl NULL-Werte erlaubt sind.
    Das habe ich jetzt erst raus bekommen.
    Seltsamerweise kam dann dieser Fehler nicht mehr, als ich das Datumsformat auf "yyyyMMdd" geändert hatte.
    Ab da konnte ich die neu eingetragenen Datensätze nicht mehr anzeigen, weil dieses Datumsformat von den 
    obigen Funktionen nicht konvertiert werden konnte.

    Also danke nochmal.
    Grüsse 
    Helmut

    • Als Antwort markiert Helmut19 Mittwoch, 8. November 2017 22:22
    Mittwoch, 8. November 2017 22:19
  • Hi Helmut,
    Deine Schilderung lässt vermuten, dass noch nicht durch alle Details durchgestiegen bist. Zulässige Nullwerte und Fehler beim Eintragen haben nichts miteinander zu tun. Das Formatieren eines Datumswertes als Zeichenkette "yyyyMMdd" hat absolut keinen Einfluss auf das Entstehen von Fehlern. Möglich sind lediglich Folgefehler z.B. wegen Länge der Zeichenkette, die mit "yyyyMMdd" kürzer ist als "dd.MM.yyyy".

    Wenn Du wegen dem Überarbeitungsaufwand bei Ablage als Zeichenketten bleiben willst und C#.NEI 7.0 nutzt (VS 2017), dann kannst Du auch die neue Darstellungsform des Datums als Zeichenkette nutzen (yyyy-MM-dd). Die Probleme einer durchgehenden Lokalisierung verbleiben dann beim Anwendungsprogramm. 

            DateTime d1 = new DateTime(2017, 5, 23);
            string s1 = d1.ToString("yyyy-MM-dd");
            Console.WriteLine(s1);
            DateTime d2 = DateTime.Parse(s1);
            Console.WriteLine(d2.ToString());

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks

    Donnerstag, 9. November 2017 08:54
  • Vielen Dank Peter,

    ich werde das nochmal durchsehen.

    Aber momentan läuft dieser Teil, und ich muss mich nun erstmal um den anderen Teil der Problem der Migration kümmern.
    Ich habe da ja noch einen anderen Thread offen, der nun langsam sehr unter den Nägeln brennt.
    Leider scheint sich damit niemand auszukennen, da das Problem irgendwie in Richtung CrystalReports tendiert.

    Also vielen Dank nochmal.
    Die Antworten hier haben schon mal sehr geholfen.

    Grüsse

    Helmut

    Donnerstag, 9. November 2017 23:58
  • Hi Helmut,
    beim anderen offenen Thread fragst Du, warum ein Eintrag im Session-Wörterbuch fehlt und deshalb eine NullReferenceException kommt.. Du zeigst aber nicht den Ablauf, wie dieser Eintrag zustande kommt.  Da kann Dir nur jemand mit einer Glaskugel und hellseherischen Fähigkeiten helfen.

    --
    Viele Grüsse
    Peter Fleischer (ehem. MVP)
    Meine Homepage mit Tipps und Tricks

    Freitag, 10. November 2017 07:49
  • Hi Peter,

    ja, ne Glaskugel wäre nicht schlecht.

    Aber das ist es ja. Der Fehler, der dort angezeigt wird, ist es nicht!
    Momentan halte ich dort eher Crystal Reports für verantwortlich.
    Aber es gehört ja in den anderen Thread.

    Grüsse
    Helmut

    Samstag, 11. November 2017 07:50