sql >> Database >  >> RDS >> Sqlserver

Hoe wordt omgegaan met de tijdzone in de levenscyclus van een ADO.NET + SQL Server DateTime-kolom?

Ik heb enkele eenheidstests uitgevoerd om mijn eigen vraag in alle vier de delen te beantwoorden.

###1:Slaat SQL Server DateTime.UtcNow dienovereenkomstig op, of compenseert het het opnieuw op basis van de tijdzone van waar de server is geïnstalleerd, en retourneert het vervolgens omgekeerd wanneer het wordt opgevraagd? Dit uitgevoerd):

cmd.CommandText = "INSERT INTO testtbl (val) VALUES (@newval)";
cmd.Parameters.Add(new SqlParameter("@newval", DateTime.UtcNow));
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT CAST(val as varchar) value FROM testtbl";
Console.WriteLine(cmd.ExecuteScalar());

Het resultaat hiervan om 13.30 uur lokale tijd (-7 uur of 20.30 uur UTC) was:

Jun  3 2010 8:30PM

Toen probeerde ik dit:

cmd.CommandText = "INSERT INTO testtbl (val) VALUES (@newval)";
cmd.Parameters.Add(new SqlParameter("@newval", DateTime.UtcNow));
cmd.ExecuteNonQuery();
Console.WriteLine("change time zone to utc");
Console.ReadLine();
cmd.CommandText = "SELECT CAST(val as varchar) value FROM testtbl";
Console.WriteLine(cmd.ExecuteScalar());
Console.WriteLine("change time zone back to local");

Uitgevoerd om 21:25 UTC, keerde terug

Jun  3 2010 9:25PM

Vergelijk dit met DateTime.Now:

cmd.CommandText = "INSERT INTO testtbl (val) VALUES (@newval)";
cmd.Parameters.Add(new SqlParameter("@newval", DateTime.Now));
cmd.ExecuteNonQuery();
Console.WriteLine("change time zone to utc");
Console.ReadLine();
cmd.CommandText = "SELECT CAST(val as varchar) value FROM testtbl";
Console.WriteLine(cmd.ExecuteScalar());
Console.WriteLine("change time zone back to local");

Uitgevoerd om 15:55 uur (lokaal; -7 uur), geretourneerd:

Jun  3 2010  3:55PM

###2:Dus dan vraag ik ernaar en cast het van object naar een DateTime nadat ik het uit bijvoorbeeld een IDataReader-kolom heb gehaald. Weet dit gecaste System.DateTime-object al dat het een UTC DateTime-instantie is, of gaat het ervan uit dat het is verschoven?

Geen van beide.

cmd.CommandText = "INSERT INTO testtbl (val) VALUES (@newval)";
cmd.Parameters.Add(new SqlParameter("@newval", DateTime.UtcNow));
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT val value FROM testtbl";
var retval = (DateTime)cmd.ExecuteScalar();
Console.WriteLine("Kind: " + retval.Kind);
Console.WriteLine("UTC: " + retval.ToUniversalTime().ToString());
Console.WriteLine("Local: " + retval.ToLocalTime().ToString());

Het resultaat hiervan (uitgevoerd om 13:58 lokale tijd) was:

Kind: Unspecified
UTC: 6/4/2010 3:58:42 AM
Local: 6/3/2010 1:58:42 PM

Dat wil zeggen, .ToUniversalTime() eindigde met een verschuiving van lokale tijd naar UTC-tijd, niet één maar twee keer (??), en .ToLocalTime() uiteindelijk helemaal niet compenserend.

###3:Geeft ADO.NET de offset door aan SQL Server en slaat SQL Server DateTime.Now op met de offset-metadata?

Zonder eenheidstests uit te voeren, is het antwoord al bekend als "alleen met DateTimeOffset" SQL-type. SQL's datetime doet geen offsets.

###4:Weet dit gegoten System.DateTime-object al dat het een offset-tijd is, of gaat het ervan uit dat het UTC is?

Geen van beide. Het DateTimeOffset-type van SQL wordt geretourneerd als een .NET DateTimeOffset-struct.

Het volgende is uitgevoerd om 15:31 lokale tijd waarbij kolom offval is een datetimeoffset SQL-type,

cmd.CommandText = "INSERT INTO testtbl (offval) VALUES (@newval)";
cmd.Parameters.Add(new SqlParameter("@newval", DateTime.Now));
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT offval value FROM testtbl";
object retvalobj = cmd.ExecuteScalar();
Console.WriteLine("Type: " + retvalobj.GetType().Name);
var retval = (DateTimeOffset)retvalobj;
Console.WriteLine("ToString(): " + retval.ToString());
Console.WriteLine("UTC: " + retval.ToUniversalTime().ToString());
Console.WriteLine("Local: " + retval.ToLocalTime().ToString());

Dit resulteerde in:

Type: DateTimeOffset
ToString(): 6/3/2010 3:31:47 PM +00:00
UTC: 6/3/2010 3:31:47 PM +00:00
Local: 6/3/2010 8:31:47 AM -07:00

Een verrassende ongelijkheid.

Door terug te gaan en de test voor vraag #1 hierboven uit te voeren met behulp van DateTime.Now in plaats van DateTime.UtcNow, heb ik gevalideerd dat ADO.NET NIET wordt geconverteerd naar universele tijd voordat het in de database wordt opgeslagen.

Dat wil zeggen, dit is uitgevoerd om 15:27 lokale tijd (-7u):

 cmd.CommandText = "INSERT INTO testtbl (val) VALUES (@newval)";
 cmd.Parameters.Add(new SqlParameter("@newval", DateTime.Now));
 cmd.ExecuteNonQuery();
 Console.WriteLine("change time zone to utc");
 Console.ReadLine();
 cmd.CommandText = "SELECT CAST(val as varchar) value FROM testtbl";
 Console.WriteLine(cmd.ExecuteScalar());
 Console.WriteLine("change time zone back to local");

.. terug ..

Jun  3 2010  3:27PM

Dit wordt uitgevoerd om 15:17 uur lokale tijd:

cmd.CommandText = "INSERT INTO testtbl (val) VALUES (@newval)";
cmd.Parameters.Add(new SqlParameter("@newval", DateTime.UtcNow));
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT val FROM testtbl";
var result = (DateTime)cmd.ExecuteScalar();
Console.WriteLine("Kind: " + result.Kind);
Console.WriteLine("ToString(): " + result.ToString());
Console.WriteLine("Add 1 minute, is greater than UtcNow? "
 + (result.AddMinutes(1) > DateTime.UtcNow).ToString());
Console.WriteLine("Add 1 minute, is greater than Now? "
 + (result.AddMinutes(1) > DateTime.Now).ToString());
Console.WriteLine("Add 1 minute, is less than UtcNow? "
 + (result.AddMinutes(1) < DateTime.UtcNow).ToString());
Console.WriteLine("Add 1 minute, is less than Now? "
 + (result.AddMinutes(1) < DateTime.Now).ToString());
Console.WriteLine("Subtract 1 minute, is greater than UtcNow? "
 + (result.AddMinutes(-1) > DateTime.UtcNow).ToString());
Console.WriteLine("Subtract 1 minute, is greater than Now? "
 + (result.AddMinutes(-1) > DateTime.Now).ToString());
Console.WriteLine("Subtract 1 minute, is less than UtcNow? "
 + (result.AddMinutes(-1) < DateTime.UtcNow).ToString());
Console.WriteLine("Subtract 1 minute, is less than Now? "
 + (result.AddMinutes(-1) < DateTime.Now).ToString());

Resulteerde in:

Kind: Unspecified
ToString(): 6/3/2010 10:17:05 PM
Add 1 minute, is greater than UtcNow? True
Add 1 minute, is greater than Now? True
Add 1 minute, is less than UtcNow? False
Add 1 minute, is less than Now? False
Subtract 1 minute, is greater than UtcNow? False
Subtract 1 minute, is greater than Now? True
Subtract 1 minute, is less than UtcNow? True
Subtract 1 minute, is less than Now? False

Vergelijk dit met DateTime.Now:

cmd.CommandText = "INSERT INTO testtbl (val) VALUES (@newval)";
cmd.Parameters.Add(new SqlParameter("@newval", DateTime.Now));
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT val FROM testtbl";
var result = (DateTime)cmd.ExecuteScalar();
Console.WriteLine("Kind: " + result.Kind);
Console.WriteLine("ToString(): " + result.ToString());
Console.WriteLine("Add 1 minute, is greater than UtcNow? "
 + (result.AddMinutes(1) > DateTime.UtcNow).ToString());
Console.WriteLine("Add 1 minute, is greater than Now? "
 + (result.AddMinutes(1) > DateTime.Now).ToString());
Console.WriteLine("Add 1 minute, is less than UtcNow? "
 + (result.AddMinutes(1) < DateTime.UtcNow).ToString());
Console.WriteLine("Add 1 minute, is less than Now? "
 + (result.AddMinutes(1) < DateTime.Now).ToString());
Console.WriteLine("Subtract 1 minute, is greater than UtcNow? "
 + (result.AddMinutes(-1) > DateTime.UtcNow).ToString());
Console.WriteLine("Subtract 1 minute, is greater than Now? "
 + (result.AddMinutes(-1) > DateTime.Now).ToString());
Console.WriteLine("Subtract 1 minute, is less than UtcNow? "
 + (result.AddMinutes(-1) < DateTime.UtcNow).ToString());
Console.WriteLine("Subtract 1 minute, is less than Now? "
 + (result.AddMinutes(-1) < DateTime.Now).ToString());

Uitgevoerd om 15:58 (lokaal, -7u):

Kind: Unspecified
ToString(): 6/3/2010 3:59:26 PM
Add 1 minute, is greater than UtcNow? False
Add 1 minute, is greater than Now? True
Add 1 minute, is less than UtcNow? True
Add 1 minute, is less than Now? False
Subtract 1 minute, is greater than UtcNow? False
Subtract 1 minute, is greater than Now? False
Subtract 1 minute, is less than UtcNow? True
Subtract 1 minute, is less than Now? True


  1. Hoe TYPE TABLE OF VARCHAR2(5) in Java toe te wijzen?

  2. Hoe MySQL te installeren met phpMyAdmin op Debian 7

  3. Verval/respijtperiode voor orakelgebruikerswachtwoord instellen

  4. MySQL 'POINT' en PHP gebruiken om breedte- en lengtegraadpunten in te voegen via een formulier