2009-03-05 23 views
8

La clase .ZEL TimeZoneInfo es excelente y pensé que respondería a todos mis problemas con la grabación de datos de múltiples zonas horarias en mi base de datos SQL 2005.Acceda a TimeZoneInfo desde SQL 2005 Server

Para convertir una hora UTC en la base de datos a cualquier otra zona horaria, solo obtendría la zona horaria en una clase TimeZoneInfo utilizando TimeZoneInfo.FindSystemTimeZoneById() y luego llamaría TimeZoneInfo.ConvertTimeFromUtc(). ¡Brillante! ¡Llamaré esto desde SQL .NET CLR!

PERO ... TimeZoneInfo tiene un atributo de protección de host de MayLeakOnAbort.

Cuando uso VS 2008 para crear una función de SQL o un procedimiento almacenado, no puedo ni siquiera ver la clase system.TimeZoneInfo no importa lo utilizan. También estoy asumiendo que incluso si pudiera hacer referencia de alguna manera a la clase TimeZoneInfo, probablemente obtendría algún tipo de excepción de seguridad si intenté registrar el ensamblado en SQL Sever 2005.

¡Ayuda! ¿Hay alguna forma de acceder a la clase TimeZoneInfo y todas sus riquezas desde SQL Server 2005?

NB: Me acaba de añadir esta advertencia después de la primera respuesta:

Tenemos sitios en diferentes lugares alrededor del mundo. Necesitamos almacenar la hora local y la hora UTC en la base de datos contra eventos que pueden requerir tendencias en el nivel del sitio. Una tendencia puede consistir en más de 52,000 puntos de datos durante un año, por lo tanto, para mayor eficiencia, no puedo simplemente almacenar los tiempos en UTC en la base de datos y convertir cada punto de datos en el cliente. Por lo tanto, necesito la capacidad, dentro del DB para convertir una hora local en cualquier zona horaria desde y hacia la hora UTC.

+0

¿Qué almacena realmente en la base de datos? ¿Está almacenando el hecho de que esta información se registró a las "3 p.m. en Francia", o está almacenando el hecho de que se registró a las 2 p. UTC? Si es el primero, puede almacenar el desfase horario local en otra columna –

+0

. Necesito registrar tanto el UTC como la hora local. Los informes del sitio generalmente se solicitarán en tiempo local, los informes de toda la empresa se solicitarán en tiempo UTC. A pesar de todo, todavía necesito la capacidad, a nivel de base de datos, para determinar cuál es el desplazamiento local o el tiempo. El usuario que ingresa puede estar en cualquier zona horaria. – user74207

Respuesta

1

No sé si puede acceder a la clase TimeZoneInfo desde SQL, pero generalmente se considera una buena práctica adherirse a UTC en la base de datos, con el cliente haciendo la traducción a la hora local.

Así que cada vez que se escribe en la base de datos, que se traducen a partir de la hora local en UTC, cada vez que se lee de la base de datos, usted traduce a UTC en la hora local.

EDIT: Por lo que entiendo del problema, la solución que aun así, recomendaría es:

1) guardar las fechas en UTC en la base de datos. 2) Calcula la hora local en el cliente.

2 se puede hacer de varias maneras. La forma recomendada es establecer DateTimeMode en Local (o Utc) en la clase DataColumn (*). Si necesita un informe en la hora local, use Local, si lo necesita en UTC, use UTC.

(*) Tenga en cuenta que hay problemas con el diseñador en Visual Studio, consulte entrada de blog: http://bethmassi.blogspot.com/2006/01/serializing-data-across-time-zones-in.html, informe de error: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=96118

+0

Gracias M, No obstante, bueno. Necesito almacenar la hora UTC y local en la base de datos. Tenemos sitios en todo el mundo. Los informes del sitio, por defecto, deben estar en hora local. Una tendencia para un año podría ser 52,000 puntos de datos. No puedo procesar 52,000 fechas en el cliente! Necesito convertir de UTC a local en DB. – user74207

+0

Hora local ¿Dónde? ¿Hora local donde se está ejecutando el informe, o la hora local donde se recopilaron los datos? –

+0

Por hora local me refiero a la hora en el sitio donde se grabaron los datos. Los datos pueden venir de usuarios o servicios en diferentes zonas horarias, por lo que no es estrictamente "donde se recopilaron los datos". P.ej. si un usuario en los EE. UU. registra datos sobre un sitio en el Reino Unido, necesito los datos registrados en horario local UTC y Reino Unido. – user74207

0

Nosotros hemos estado buscando esto por un tiempo, pero no hemos sido capaz de encontrar una buena manera de hacerlo. Creo que eso estaba en la lista de cosas que se agregarán en SQL 2008 si recuerdo haberlo visto hace un tiempo.

+0

Hola Ryan: SQL 2008 tiene el nuevo y agradable tipo de datos DATETIMEOFFSET que podría negar mi necesidad de almacenar horas locales y UTC, pero todavía no hay funciones de conversión de zona horaria, además de convertir entre UTC y la hora del servidor local, lo cual no sirve de nada si estamos trabajando en varias zonas horarias. – user74207

+0

Según tengo entendido, datetimeoffset es solo una fecha con la información de la zona horaria almacenada con ella. –

+0

Hola Matthieu: sí, lo bueno es que coincide exactamente con el tipo de datos datetimeoffset en .NET 3.5. Es una forma eficiente de almacenar hora local y hora UTC en un campo. Lamentablemente, esto no ayuda con mi problema en particular. – user74207

1

me encontré con este mismo problema porque quería convertir entre local y UTC en una consulta que estaba siendo utilizado por los servicios de la información. Pasé por lo que parecen ser las mismas luchas exactas que estás pasando con esto. Mi solución ...

empecé a escribir una aplicación independiente que pasó por el objeto TimeZoneInfo y escribió entradas a una tabla TimeZoneInfo en mi base de datos.Almacenaba todas las compensaciones (incluidas las compensaciones de ahorro de luz diurna) para cada año entre un año de inicio y un año final (estos eran argumentos para la aplicación independiente).

De esta tabla, pude crear algunas funciones sql que tomarían una fecha en utc o local y la zona horaria, use la tabla de búsqueda TimeZoneInfo para obtener el desplazamiento correcto para el momento del año y la zona horaria correctos, y devuelve la fecha y hora convertida a UTC o local.

Desafortunadamente, todavía no había terminado. Tuve que crear una función CLR que devolviera la zona horaria actual del sistema utilizando una biblioteca que WAS era segura para SQL Server (a diferencia del objeto TimeZoneInfo). No tengo acceso a mi código en este momento, pero creo que utilicé el objeto TimeZone.

http://msdn.microsoft.com/en-us/library/system.timezone_members.aspx

En resumen, tenía una función CLR que devolvió la zona horaria del sistema, una aplicación que produjo una zona horaria tabla de consulta con DLS información específica para una serie de años. Completé todo con un procedimiento almacenado que incluía una zona horaria y una fecha para convertir y ha estado funcionando muy bien desde entonces.

Entiendo que esto es un trabajo enorme en torno a hacer algo que parecía bastante simple, pero hizo el trabajo de una manera segura.

0

¿Has echado un vistazo a este artículo en Channel9? Parece hacer lo que estás buscando en una función CLR ... aunque no creo que vayas a obtener TODAS las cosas buenas a las que quieres acceder ... pero es un comienzo.

http://channel9.msdn.com/playground/Sandbox/139123/

Problema que uno de los carteles sobre ese hilo menciones aunque es que es un montaje inseguro debido a la p/invocar.

1

he aquí una solución:

  1. Crear un proc almacenado CLR o UDF, que envuelve la funcionalidad de la clase TimeZoneInfo. Siga esta guía: http://www.codeproject.com/KB/cs/CLR_Stored_Procedure.aspx
  2. TimeZoneInfo requiere .NET 3.5. Sin embargo, System.Core v3.5 no pasará la verificación en Sql Server 2005. Por lo tanto, debe realizar un CREATE ASSEMBLY para System.Core. Ver detalles: http://weblogs.asp.net/paulomorgado/archive/2009/06/13/playing-with-sql-server-clr-integration-part-iv-deploying-to-sql-server-2005.aspx

Tenga en cuenta que debe registrar System.Core como UNSAFE ... para que el DBA pueda tener problemas con él.

Además, incluso si se implementa a SQL Server 2008 (que incluye .NET 3.5), el ensamblado personalizado tendría que ser inseguro ya que utiliza métodos inseguros de TimeZoneInfo: http://social.msdn.microsoft.com/Forums/en/sqlnetfx/thread/d0515862-eb87-4a13-bab4-0e343983823a

He intentado esto y consiguió un mensaje sobre MayLeakOnAbort.

Si bien inseguro es que en el medio ambiente, debe ser capaz de hacerlo.

+0

Esta solución también requiere que la base de datos se configure en modo TRUSTWORTHY, en lugar de firmar los ensamblajes. – Suncat2000

3

Acabo de terminar de hacer esto en una base de datos SQL 2008.

primero tenía que establecer la base de datos para verificar digno de confianza y el dueño era correcta.

use [myDB] 
go 
alter database [myDB] set trustworthy on 
go 

exec sp_changedbowner 'sa' 
go 

A continuación, he creado a.NET solución

Imports System 
Imports System.Data 
Imports System.Data.SqlClient 
Imports System.Data.SqlTypes 
Imports Microsoft.SqlServer.Server 
Imports System.Collections.ObjectModel 
Imports System.Runtime.InteropServices 

Partial Public Class StoredProcedures 
    <Microsoft.SqlServer.Server.SqlProcedure()> _ 
    Public Shared Sub sp_ConvertTime(ByVal UTCTime As DateTime, ByVal ZoneID As String, <Out()> ByRef Output As DateTime) 
    Dim sp As SqlPipe = SqlContext.Pipe 

    Dim ConvertedTime As DateTime 
    Dim tzUTC = TimeZoneInfo.FindSystemTimeZoneById("UTC") 
    Dim tzNew = TimeZoneInfo.FindSystemTimeZoneById(ZoneID) 

    ConvertedTime = TimeZoneInfo.ConvertTime(UTCTime, tzUTC, tzNew) 

    Output = ConvertedTime 
    sp.Send(ConvertedTime) 

    ConvertedTime = Nothing 
    tzUTC = Nothing 
    tzNew = Nothing 
    sp = Nothing 

End Sub 
End Class 

Antes del despliegue fijo el nivel de permiso a inseguro.

A continuación lo implementé Comprobé la ventana de Salida para errores de compilación y los corrigí.

Aquí está la prueba de SQL

DECLARE @UTCTime datetime 
DECLARE @ZoneID varchar(21) 
DECLARE @NewTime datetime 

SET @UTCTime = GETUTCDATE() 
SET @ZoneID = 'Central Standard Time' 

exec sp_ConvertTime @UTCTime, @ZoneID, @NewTime OUTPUT 
select @NewTime AS NewTime 
0

Después de luchar con el mismo problema durante años, finalmente me decidí a construir una solución para SQL Server Time Zone Support. El proyecto usa las zonas horarias estándar de IANA, as listed here.

Por ejemplo:

SELECT Tzdb.UtcToLocal('2015-07-01 00:00:00', 'America/Los_Angeles') 

Sé que esto no es exactamente lo que se pedía, pero creo que va a resolver el problema igual de bien.