Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

W jaki sposób strefa czasowa jest obsługiwana w cyklu życia kolumny DateTime ADO.NET + SQL Server?

Wykonałem kilka testów jednostkowych, aby odpowiedzieć na moje własne pytanie we wszystkich czterech częściach.

###1:Czy SQL Server odpowiednio przechowuje DateTime.UtcNow, czy też przesunie go ponownie w oparciu o strefę czasową, w której jest zainstalowany serwer, a następnie zwraca go z odwróconym przesunięciem podczas zapytania? Wykonano to:

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());

Wynik tego o 13:30 czasu lokalnego (-7h lub 20:30 UTC):

Jun  3 2010 8:30PM

Potem spróbowałem tego:

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");

Wykonany o 21:25 UTC, wrócił

Jun  3 2010 9:25PM

Porównaj to z 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");

Wykonano o 15:55 (lokalnie; -7h), zwrócono:

Jun  3 2010  3:55PM

###2:Więc pytam o to i przesyłam go z obiektu do DateTime po pobraniu go z, powiedzmy, kolumny IDataReader. Czy ten rzutowany obiekt System.DateTime już wie, że jest instancją DateTime UTC, czy też zakłada, że ​​został przesunięty?

Ani.

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());

Wynikiem tego (wykonanego o 13:58 czasu lokalnego) było:

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

To znaczy .ToUniversalTime() zakończyło się przesunięciem z czasu lokalnego na czas UTC nie raz, ale dwa razy (??) i .ToLocalTime() skończyło się na tym, że w ogóle się nie kompensuje.

###3:Czy ADO.NET przekazuje przesunięcie do SQL Server i czy SQL Server przechowuje DateTime.Now z metadanymi przesunięcia?

Bez wykonywania jakichkolwiek testów jednostkowych odpowiedź jest już znana jako typ SQL „tylko z DateTimeOffset”. datetime SQL nie wykonuje offsetów.

###4:Czy ten rzutowany obiekt System.DateTime już wie, że jest to czas przesunięcia, czy też zakłada, że ​​jest to UTC?

Żaden. Typ DateTimeOffset SQL jest zwracany jako struktura .NET DateTimeOffset.

Poniższe wykonane o 15:31 czasu lokalnego, gdzie kolumna offval jest typem SQL typu datatimeoffset,

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());

Spowodowało to:

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

Zaskakująca rozbieżność.

Wracając i wykonując test dla pytania nr 1 powyżej przy użyciu DateTime.Now zamiast DateTime.UtcNow, sprawdziłem, że ADO.NET NIE konwertuje na czas uniwersalny przed zapisaniem w bazie danych.

Oznacza to, że zostało to wykonane o 15:27 czasu lokalnego (-7h):

 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");

.. wrócił ..

Jun  3 2010  3:27PM

Wykonanie o 15:17 czasu lokalnego:

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());

Wynik:

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

Porównaj to z 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());

Wykonano o 15:58 (lokalnie, -7h):

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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Server ROWLOCK nad SELECT, jeśli nie istnieje INSERT transakcja

  2. Jak wykonać wygenerowany skrypt (plik .sql) ze schematem i danymi w SQL Server 2008

  3. Pobierz>901 wierszy z połączonego serwera SQL Server 2008 do Active Directory

  4. Jak usunąć lub usunąć wszystkie wyzwalacze z bazy danych w SQL Server

  5. 8078 bajtów na stronie danych 8060 B (SQL Server)?