Jeg sidder for tiden og arbejder med en applikation, der håndterer kalender events. Applikationen er gammel, og har masser af data. Den gamle data ligger i SQl server, så vi får ingen problemer når vi skal til at håndterer tids-zoner…øhh vel?
Hvordan er det lige at vi gemmer DateTime med SqlClient i .NET frameworket?
Jeg har prøvet at undersøge sagen lidt nærmere, og jeg må sig jeg blev lidt overrasket. Når man instantierer en DateTime struct, får den automatisk sat egenskaben; Kind til Local. Det vil sige at følgende kode:
var dato = new DateTime(2009, 9, 22, 12, 0, 0);
Console.Write(dato.ToString("o"));
Giver følgende output: 2009-09-22T12:00:00+2 (når det bliver kørt i dag 21/9 2009)
Når jeg så gemmer værdien i Sql-server med SqlClient, og læser den ud igen, så er Kind egenskaben gået tabt. Den er nu angivet til Unspecified, og tidspunktet er stadig 12:00.
Man putter altså tids-zone info ind, men den forsvinder i databasen. Det skyldes at Sql servers felttype, kun indeholder en dato-tid værdi – ikke tids-zone værdi. Den kan altså ikke bare lade udlæsninger fra klienten blive angivet til Local – det har den simpelthen ikke viden om.
Hvad gør man så når man vil kode en applikation, der kan håndterer forskellige tids-zoner?
- Man skal vedtage en konvention, om at DateTime kolonnerne i databasen, skal tolkes som UTC.
- Man skal koverterer inputdatoer til UTC når man sætter SqlParameter værdier.
- Man skal specificerer Kind til Utc, når man udlæser fra databasen
ins.Parameters.AddWithValue("@dato", dato.ToUniversalTime());
var dato = DateTime.SpecifyKind(sqlReader.GetDateTime(1), DateTimeKind.Local)
Følger man de retningslinier, får ma ingen problemer.
Har man et legacy system, hvor man har gemt datoer i dansk zone, skal man enten
- Konverterer alle datofelter til UTC
eller
- Isolerer koden der læser/skriver til kolonnerne, og tvinge dem til at angive Kind til Local, ved alle læsninger.
Hvad vælger du?